Merge "cts: Add default animation for UiAutomation test"
diff --git a/apps/CameraITS/tests/scene1_1/test_black_white.py b/apps/CameraITS/tests/scene1_1/test_black_white.py
index 2421cc9..6cf9de0 100644
--- a/apps/CameraITS/tests/scene1_1/test_black_white.py
+++ b/apps/CameraITS/tests/scene1_1/test_black_white.py
@@ -29,6 +29,7 @@
 import image_processing_utils
 import its_session_utils
 
+_ANDROID10_API_LEVEL = 29
 CH_FULL_SCALE = 255
 CH_THRESH_BLACK = 6
 CH_THRESH_WHITE = CH_FULL_SCALE - 6
@@ -148,10 +149,12 @@
         assert mean > CH_THRESH_WHITE, e_msg
 
       # Assert channels saturate evenly (was test_channel_saturation)
-      e_msg = 'ch saturation not equal! RGB: %s, ATOL: %.f' % (
-          str(white_means), CH_TOL_WHITE)
-      assert np.isclose(
-          np.amin(white_means), np.amax(white_means), atol=CH_TOL_WHITE), e_msg
+      first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
+      if first_api_level > _ANDROID10_API_LEVEL:
+        e_msg = 'ch saturation not equal! RGB: %s, ATOL: %.f' % (
+            str(white_means), CH_TOL_WHITE)
+        assert np.isclose(
+            np.amin(white_means), np.amax(white_means), atol=CH_TOL_WHITE), e_msg
 
 if __name__ == '__main__':
   test_runner.main()
diff --git a/apps/CameraITS/tests/scene3/test_flip_mirror.py b/apps/CameraITS/tests/scene3/test_flip_mirror.py
index 2dff574..679b740 100644
--- a/apps/CameraITS/tests/scene3/test_flip_mirror.py
+++ b/apps/CameraITS/tests/scene3/test_flip_mirror.py
@@ -53,10 +53,6 @@
   Returns:
     boolean: True if flipped, False if not
   """
-
-  # determine if monochrome camera
-  mono_camera = camera_properties_utils.mono_camera(props)
-
   # get a local copy of the chart template
   template = cv2.imread(opencv_processing_utils.CHART_FILE, cv2.IMREAD_ANYDEPTH)
 
@@ -139,6 +135,10 @@
       debug = self.debug_mode
       chart_loc_arg = self.chart_loc_arg
 
+      # check SKIP conditions
+      camera_properties_utils.skip_unless(
+          not camera_properties_utils.mono_camera(props))
+
       # load chart for scene
       its_session_utils.load_scene(
           cam, props, self.scene, self.tablet, self.chart_distance)
diff --git a/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py b/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py
index 73d1276..af55ebc 100644
--- a/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py
+++ b/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py
@@ -29,7 +29,7 @@
 import opencv_processing_utils
 
 ALIGN_TOL_MM = 4.0  # mm
-ALIGN_TOL = 0.01  # multiplied by sensor diagonal to convert to pixels
+ALIGN_TOL = 0.0075  # multiplied by sensor diagonal to convert to pixels
 CIRCLE_COLOR = 0  # [0: black, 255: white]
 CIRCLE_MIN_AREA = 0.01  # multiplied by image size
 CIRCLE_RTOL = 0.1  # 10%
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index d5d3b06..410b277 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -604,8 +604,9 @@
   logging.info('Test execution completed.')
 
   # Power down tablet
-  cmd = f'adb -s {tablet_id} shell input keyevent KEYCODE_POWER'
-  subprocess.Popen(cmd.split())
+  if tablet_id:
+    cmd = f'adb -s {tablet_id} shell input keyevent KEYCODE_POWER'
+    subprocess.Popen(cmd.split())
 
 if __name__ == '__main__':
   main()
diff --git a/apps/CtsVerifier/res/layout/audio_aec_activity.xml b/apps/CtsVerifier/res/layout/audio_aec_activity.xml
index 83aa9cd..d6d4bb0 100644
--- a/apps/CtsVerifier/res/layout/audio_aec_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_aec_activity.xml
@@ -48,12 +48,12 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:id="@+id/audio_aec_mandatory_no"
-                        android:text="@string/af_no" />
+                        android:text="@string/audio_general_no" />
                 <Button
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:id="@+id/audio_aec_mandatory_yes"
-                        android:text="@string/af_yes" />
+                        android:text="@string/audio_general_yes" />
             </LinearLayout>
 
             <LinearLayout
@@ -79,7 +79,7 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:soundEffectsEnabled="false"
-                        android:text="@string/af_button_test"
+                        android:text="@string/audio_general_test"
                         android:id="@+id/audio_aec_button_test" />
                 <ProgressBar
                         android:layout_width="wrap_content"
@@ -90,7 +90,7 @@
                 <TextView
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
-                        android:text="@string/af_test_results"
+                        android:text="@string/audio_general_results"
                         android:id="@+id/audio_aec_test_result" />
             </LinearLayout>
 
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml
index 3ae6d43..fd5f619 100644
--- a/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml
@@ -70,7 +70,7 @@
                         <Button
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            android:text="@string/audio_frequency_line_test_btn"
+                            android:text="@string/audio_general_test"
                             android:id="@+id/audio_frequency_line_test_btn"
                             android:nextFocusForward="@+id/pass_button"
                             android:nextFocusUp="@+id/audio_frequency_line_plug_ready_btn"
@@ -87,7 +87,7 @@
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        android:text="@string/audio_frequency_line_results_text"
+                        android:text="@string/audio_general_results"
                         android:id="@+id/audio_frequency_line_results_text" />
 
                 </LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml
index a991a15..fb2dd32 100644
--- a/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml
@@ -67,7 +67,7 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/frequency_mic_test_noise_btn"
+                            android:text="@string/audio_general_test"
                             android:id="@+id/frequency_mic_test_noise_btn" />
                         <ProgressBar
                             android:layout_width="wrap_content"
@@ -91,14 +91,14 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/frequency_mic_play"
+                            android:text="@string/audio_general_play"
                             android:id="@+id/frequency_mic_play_noise_btn" />
                     </LinearLayout>
                 </LinearLayout>
                 <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/frequency_mic_test_noise_result"
+                    android:text="@string/audio_general_results"
                     android:id="@+id/frequency_mic_test_noise_result" />
             </LinearLayout>
 
@@ -137,7 +137,7 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/frequency_mic_test_usb_background_btn"
+                            android:text="@string/audio_general_test"
                             android:id="@+id/frequency_mic_test_usb_background_btn" />
                         <ProgressBar
                             android:layout_width="wrap_content"
@@ -149,7 +149,7 @@
                 <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/frequency_mic_test_usb_background_result"
+                    android:text="@string/audio_general_results"
                     android:id="@+id/frequency_mic_test_usb_background_result" />
             </LinearLayout>
 
@@ -188,7 +188,7 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/frequency_mic_test_usb_noise_btn"
+                            android:text="@string/audio_general_test"
                             android:id="@+id/frequency_mic_test_usb_noise_btn" />
                         <ProgressBar
                             android:layout_width="wrap_content"
@@ -212,14 +212,14 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/frequency_mic_play"
+                            android:text="@string/audio_general_play"
                             android:id="@+id/frequency_mic_play_usb_noise_btn" />
                     </LinearLayout>
                 </LinearLayout>
                 <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/frequency_mic_test_usb_noise_result"
+                    android:text="@string/audio_general_results"
                     android:id="@+id/frequency_mic_test_usb_noise_result" />
             </LinearLayout>
              <View
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_speaker_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_speaker_activity.xml
index a9aeafa..7c051cc 100644
--- a/apps/CtsVerifier/res/layout/audio_frequency_speaker_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_frequency_speaker_activity.xml
@@ -72,7 +72,7 @@
                         <Button
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            android:text="@string/audio_frequency_speaker_test_btn"
+                            android:text="@string/audio_general_test"
                             android:id="@+id/audio_frequency_speaker_test_btn"
                             android:nextFocusForward="@+id/pass_button"
                             android:nextFocusUp="@+id/audio_frequency_speaker_mic_ready_btn"
@@ -89,7 +89,7 @@
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        android:text="@string/audio_frequency_speaker_results_text"
+                        android:text="@string/audio_general_results"
                         android:id="@+id/audio_frequency_speaker_results_text"/>
 
                 </LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml
index 8032f93..bbd576d 100644
--- a/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml
@@ -67,7 +67,7 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/unprocessed_test_tone_btn"
+                            android:text="@string/audio_general_test"
                             android:id="@+id/unprocessed_test_tone_btn" />
                         <ProgressBar
                             android:layout_width="wrap_content"
@@ -91,14 +91,14 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/unprocessed_play"
+                            android:text="@string/audio_general_play"
                             android:id="@+id/unprocessed_play_tone_btn" />
                     </LinearLayout>
                 </LinearLayout>
                 <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/unprocessed_test_tone_result"
+                    android:text="@string/audio_general_results"
                     android:id="@+id/unprocessed_test_tone_result" />
             </LinearLayout>
 
@@ -136,7 +136,7 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/unprocessed_test_noise_btn"
+                            android:text="@string/audio_general_test"
                             android:id="@+id/unprocessed_test_noise_btn" />
                         <ProgressBar
                             android:layout_width="wrap_content"
@@ -159,14 +159,14 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/unprocessed_play"
+                            android:text="@string/audio_general_play"
                             android:id="@+id/unprocessed_play_noise_btn" />
                     </LinearLayout>
                 </LinearLayout>
                 <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/unprocessed_test_noise_result"
+                    android:text="@string/audio_general_results"
                     android:id="@+id/unprocessed_test_noise_result" />
             </LinearLayout>
 
@@ -204,7 +204,7 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/unprocessed_test_usb_background_btn"
+                            android:text="@string/audio_general_test"
                             android:id="@+id/unprocessed_test_usb_background_btn" />
                         <ProgressBar
                             android:layout_width="wrap_content"
@@ -216,7 +216,7 @@
                 <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/unprocessed_test_usb_background_result"
+                    android:text="@string/audio_general_results"
                     android:id="@+id/unprocessed_test_usb_background_result" />
             </LinearLayout>
 
@@ -254,7 +254,7 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/unprocessed_test_usb_noise_btn"
+                            android:text="@string/audio_general_test"
                             android:id="@+id/unprocessed_test_usb_noise_btn" />
                         <ProgressBar
                             android:layout_width="wrap_content"
@@ -277,14 +277,14 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/unprocessed_play"
+                            android:text="@string/audio_general_play"
                             android:id="@+id/unprocessed_play_usb_noise_btn" />
                     </LinearLayout>
                 </LinearLayout>
                 <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/unprocessed_test_usb_noise_result"
+                    android:text="@string/audio_general_results"
                     android:id="@+id/unprocessed_test_usb_noise_result" />
             </LinearLayout>
              <View
@@ -295,7 +295,7 @@
             <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/unprocessed_test_global_result"
+                    android:text="@string/audio_general_results"
                     android:id="@+id/unprocessed_test_global_result" />
 
             <include layout="@layout/pass_fail_buttons" />
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_voice_recognition_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_voice_recognition_activity.xml
index 1ccd947..f283388 100644
--- a/apps/CtsVerifier/res/layout/audio_frequency_voice_recognition_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_frequency_voice_recognition_activity.xml
@@ -67,7 +67,7 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/af_button_test"
+                            android:text="@string/audio_general_test"
                             android:id="@+id/vr_button_test_tone" />
                         <ProgressBar
                             android:layout_width="wrap_content"
@@ -91,14 +91,14 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/af_button_play"
+                            android:text="@string/audio_general_play"
                             android:id="@+id/vr_button_play_tone" />
                     </LinearLayout>
                 </LinearLayout>
                 <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/af_test_results"
+                    android:text="@string/audio_general_results"
                     android:id="@+id/vr_test_tone_result" />
             </LinearLayout>
 
@@ -136,7 +136,7 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/af_button_test"
+                            android:text="@string/audio_general_test"
                             android:id="@+id/vr_button_test_noise" />
                         <ProgressBar
                             android:layout_width="wrap_content"
@@ -159,14 +159,14 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/af_button_play"
+                            android:text="@string/audio_general_play"
                             android:id="@+id/vr_button_play_noise" />
                     </LinearLayout>
                 </LinearLayout>
                 <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/af_test_results"
+                    android:text="@string/audio_general_results"
                     android:id="@+id/vr_test_noise_result" />
             </LinearLayout>
 
@@ -204,7 +204,7 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/af_button_test"
+                            android:text="@string/audio_general_test"
                             android:id="@+id/vr_button_test_usb_background" />
                         <ProgressBar
                             android:layout_width="wrap_content"
@@ -216,7 +216,7 @@
                 <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/af_test_results"
+                    android:text="@string/audio_general_results"
                     android:id="@+id/vr_test_usb_background_result" />
             </LinearLayout>
 
@@ -254,7 +254,7 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/af_button_test"
+                            android:text="@string/audio_general_test"
                             android:id="@+id/vr_button_test_usb_noise" />
                         <ProgressBar
                             android:layout_width="wrap_content"
@@ -277,14 +277,14 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:soundEffectsEnabled="false"
-                            android:text="@string/af_button_play"
+                            android:text="@string/audio_general_play"
                             android:id="@+id/vr_button_play_usb_noise" />
                     </LinearLayout>
                 </LinearLayout>
                 <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/af_test_results"
+                    android:text="@string/audio_general_results"
                     android:id="@+id/vr_test_usb_noise_result" />
             </LinearLayout>
             <View
diff --git a/apps/CtsVerifier/res/layout/audio_headset_audio_activity.xml b/apps/CtsVerifier/res/layout/audio_headset_audio_activity.xml
index 24767d2..964985c 100644
--- a/apps/CtsVerifier/res/layout/audio_headset_audio_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_headset_audio_activity.xml
@@ -70,12 +70,12 @@
             android:orientation="horizontal"
             android:layout_marginLeft="10dp">
             <Button
-                android:text="@string/analog_headset_play"
+                android:text="@string/audio_general_play"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:id="@+id/headset_analog_play"/>
             <Button
-                android:text="@string/analog_headset_stop"
+                android:text="@string/audio_general_stop"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:id="@+id/headset_analog_stop"/>
diff --git a/apps/CtsVerifier/res/layout/audio_loopback_footer_layout.xml b/apps/CtsVerifier/res/layout/audio_loopback_footer_layout.xml
index f59afeb..624602c 100644
--- a/apps/CtsVerifier/res/layout/audio_loopback_footer_layout.xml
+++ b/apps/CtsVerifier/res/layout/audio_loopback_footer_layout.xml
@@ -13,6 +13,6 @@
     <TextView
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:text="@string/audio_loopback_results_text"
+        android:text="@string/audio_general_results"
         android:id="@+id/audio_loopback_results_text" />
 </LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/audio_loopback_latency_activity.xml b/apps/CtsVerifier/res/layout/audio_loopback_latency_activity.xml
index 9d9631a..894e1d3 100644
--- a/apps/CtsVerifier/res/layout/audio_loopback_latency_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_loopback_latency_activity.xml
@@ -65,12 +65,11 @@
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="match_parent"
-                        android:text="Pro Audio:"/>
+                        android:text="@string/audio_loopback_lbl_proaudio"/>
 
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="match_parent"
-                        android:text=""
                         android:id="@+id/audio_loopback_pro_audio"/>
                 </LinearLayout>
 
@@ -82,12 +81,11 @@
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="match_parent"
-                        android:text="MMAP Supported:"/>
+                        android:text="@string/audio_loopback_lbl_mmap"/>
 
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="match_parent"
-                        android:text=""
                         android:id="@+id/audio_loopback_mmap"/>
                 </LinearLayout>
 
@@ -99,12 +97,11 @@
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="match_parent"
-                        android:text="MMAP Exclusive Supported:"/>
+                        android:text="@string/audio_loopback_lbl_mmexclusive"/>
 
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="match_parent"
-                        android:text=""
                         android:id="@+id/audio_loopback_mmap_exclusive"/>
                 </LinearLayout>
 
@@ -116,12 +113,11 @@
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="match_parent"
-                        android:text="Low Latency Support:"/>
+                        android:text="@string/audio_loopback_lbl_lowlatency"/>
 
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="match_parent"
-                        android:text=""
                         android:id="@+id/audio_loopback_low_latency"/>
                 </LinearLayout>
 
@@ -138,7 +134,6 @@
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="match_parent"
-                        android:text=""
                         android:id="@+id/audio_loopback_must_latency"/>
                 </LinearLayout>
 
@@ -150,12 +145,11 @@
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="match_parent"
-                        android:text="Recommended Max Latency (ms):"/>
+                        android:text="@string/audio_loopback_lbl_recommededlatency"/>
 
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="match_parent"
-                        android:text=""
                         android:id="@+id/audio_loopback_recommended_latency"/>
                 </LinearLayout>
 
@@ -168,7 +162,7 @@
                     <Button
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        android:text="@string/audio_loopback_test_btn"
+                        android:text="@string/audio_general_test"
                         android:id="@+id/audio_loopback_test_btn"
                         android:nextFocusForward="@+id/pass_button"
                         android:nextFocusUp="@+id/audio_loopback_level_seekbar"
diff --git a/apps/CtsVerifier/res/layout/audio_refmic_layout.xml b/apps/CtsVerifier/res/layout/audio_refmic_layout.xml
index bd806a1..74ee203 100644
--- a/apps/CtsVerifier/res/layout/audio_refmic_layout.xml
+++ b/apps/CtsVerifier/res/layout/audio_refmic_layout.xml
@@ -18,21 +18,21 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:soundEffectsEnabled="false"
-            android:text="@string/refmic_test_yes"
+            android:text="@string/audio_general_yes"
             android:id="@+id/refmic_tests_yes_btn" />
 
         <Button
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:soundEffectsEnabled="false"
-            android:text="@string/refmic_test_no"
+            android:text="@string/audio_general_no"
             android:id="@+id/refmic_tests_no_btn" />
 
         <Button
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:soundEffectsEnabled="false"
-            android:text="@string/refmic_test_info"
+            android:text="@string/audio_general_info"
             android:id="@+id/refmic_test_info_btn" />
     </LinearLayout>
 </LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/audio_wired_query_layout.xml b/apps/CtsVerifier/res/layout/audio_wired_query_layout.xml
index bc8038b..bd67643 100644
--- a/apps/CtsVerifier/res/layout/audio_wired_query_layout.xml
+++ b/apps/CtsVerifier/res/layout/audio_wired_query_layout.xml
@@ -21,12 +21,12 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:id="@+id/audio_wired_no"
-            android:text="@string/audio_wired_no" />
+            android:text="@string/audio_general_no" />
 
         <Button
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:id="@+id/audio_wired_yes"
-            android:text="@string/audio_wired_yes" />
+            android:text="@string/audio_general_yes" />
     </LinearLayout>
 </LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/uap_attribs_panel.xml b/apps/CtsVerifier/res/layout/uap_attribs_panel.xml
index b9c5d3e..45cfcd0 100644
--- a/apps/CtsVerifier/res/layout/uap_attribs_panel.xml
+++ b/apps/CtsVerifier/res/layout/uap_attribs_panel.xml
@@ -24,7 +24,7 @@
             android:layout_height="wrap_content"/>
 
         <TextView
-            android:text="status"
+            android:text="@string/audio_general_status"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:id="@+id/uap_attribsStatusTx"
diff --git a/apps/CtsVerifier/res/layout/uap_play_panel.xml b/apps/CtsVerifier/res/layout/uap_play_panel.xml
index 30ef884..a263d45 100644
--- a/apps/CtsVerifier/res/layout/uap_play_panel.xml
+++ b/apps/CtsVerifier/res/layout/uap_play_panel.xml
@@ -32,7 +32,7 @@
             android:layout_height="5dp"/>
 
         <Button
-            android:text="@string/audio_uap_play_playBtn"
+            android:text="@string/audio_general_play"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:id="@+id/uap_playPlayBtn"
diff --git a/apps/CtsVerifier/res/layout/uap_record_panel.xml b/apps/CtsVerifier/res/layout/uap_record_panel.xml
index a5bfcfc..ff993a3 100644
--- a/apps/CtsVerifier/res/layout/uap_record_panel.xml
+++ b/apps/CtsVerifier/res/layout/uap_record_panel.xml
@@ -32,7 +32,7 @@
             android:layout_height="5dp"/>
 
         <Button
-            android:text="@string/audio_uap_record_recordBtn"
+            android:text="@string/audio_general_record"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:id="@+id/uap_recordRecordBtn"
@@ -40,7 +40,7 @@
             android:nextFocusDown="@+id/uap_recordRecordLoopBtn"/>
 
         <Button
-            android:text="@string/audio_uap_record_recordLoopbackBtn"
+            android:text="@string/audio_general_recordLoopback"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:id="@+id/uap_recordRecordLoopBtn"
diff --git a/apps/CtsVerifier/res/layout/uap_usb_confirm.xml b/apps/CtsVerifier/res/layout/uap_usb_confirm.xml
index ea73b88..e89ce84e 100644
--- a/apps/CtsVerifier/res/layout/uap_usb_confirm.xml
+++ b/apps/CtsVerifier/res/layout/uap_usb_confirm.xml
@@ -18,21 +18,21 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:soundEffectsEnabled="false"
-            android:text="@string/uap_test_yes"
+            android:text="@string/audio_general_yes"
             android:id="@+id/uap_tests_yes_btn" />
 
         <Button
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:soundEffectsEnabled="false"
-            android:text="@string/uap_test_no"
+            android:text="@string/audio_general_no"
             android:id="@+id/uap_tests_no_btn" />
 
         <Button
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:soundEffectsEnabled="false"
-            android:text="@string/uap_test_info"
+            android:text="@string/audio_general_info"
             android:id="@+id/uap_test_info_btn" />
     </LinearLayout>
 </LinearLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 3df2bc4..aaac43c 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -4960,15 +4960,10 @@
     <string name="audio_uap_play_test">USB Audio Peripheral Play Test</string>
     <string name="uapPlayTestInstructions">Connect the USB Audio Interface Peripheral and press the
         PLAY button below. Verify that a tone is correctly played.</string>
-    <string name="audio_uap_play_playBtn">Play</string>
-    <string name="audio_uap_play_stopBtn">Stop</string>
 
     <string name="audio_uap_record_test">USB Audio Peripheral Record Test</string>
     <string name="uapRecordTestInstructions">Connect the USB Audio Peripheral and press the RECORD or
         RECORD LOOPBACK button below. Verify that a tone is correctly played.</string>
-    <string name="audio_uap_record_recordBtn">Record</string>
-    <string name="audio_uap_record_recordLoopbackBtn">Record Loopback</string>
-    <string name="audio_uap_record_stopBtn">Stop</string>
 
     <string name="audio_uap_buttons_test">USB Audio Peripheral Buttons Test</string>
     <string name="uapButtonTestInstructions">Connect the USB Audio headset with buttons
@@ -5049,7 +5044,6 @@
         flag and therefore does not need to run this test.</string>
 
     <!-- Various test status strings -->
-    <string name="audio_proaudio_pass">Pass</string>
     <string name="audio_proaudio_latencytoohigh">Latency is too high</string>
     <string name="audio_proaudio_confidencetoolow">"Insufficient Confidence value"</string>
     <string name="audio_proaudio_midinotreported">"No MIDI support reported"</string>
@@ -5100,8 +5094,6 @@
 
     <!-- Audio general text -->
     <string name="audio_wired_exists">Does this device support wired USB or Analog audio peripherals?</string>
-    <string name="audio_wired_no">No</string>
-    <string name="audio_wired_yes">Yes</string>
     <string name="audio_general_deficiency_found">WARNING: Some results show potential deficiencies on the system.
     Please consider addressing them for a future release.</string>
     <string name="audio_general_test_passed">Test Result: Successful</string>
@@ -5118,6 +5110,13 @@
     <string name="audio_general_ok">Ok</string>
     <string name="audio_general_start">Start</string>
     <string name="audio_general_stop">Stop</string>
+    <string name="audio_general_play">Play</string>
+    <string name="audio_general_test">Test</string>
+    <string name="audio_general_status">Status</string>
+    <string name="audio_general_record">Record</string>
+    <string name="audio_general_recordLoopback">Record Loopback</string>
+    <string name="audio_general_results">Results...</string>
+    <string name="audio_general_pass">Pass</string>
 
     <string name="audio_general_JavaApi">Java API</string>
     <string name="audio_general_NativeApi">Native API</string>
@@ -5148,9 +5147,15 @@
           It might require multiple tries until a confidence >= 0.6 is achieved.
     </string>
     <string name="audio_loopback_level_text">Audio Level</string>
-    <string name="audio_loopback_test_btn">Test</string>
-    <string name="audio_loopback_results_text">Results...</string>
 
+    <!-- UI Labels -->
+    <string name="audio_loopback_lbl_proaudio">Pro Audio:</string>
+    <string name="audio_loopback_lbl_mmap">MMAP Supported:</string>
+    <string name="audio_loopback_lbl_mmexclusive">MMAP Exclusive Supported:</string>
+    <string name="audio_loopback_lbl_lowlatency">Low Latency Support:</string>
+    <string name="audio_loopback_lbl_testpath">Test Path:</string>
+    <string name="audio_loopback_lbl_mustlatency">Required Max Latency (ms):</string>
+    <string name="audio_loopback_lbl_recommededlatency">Recommended Max Latency (ms):</string>
     <string name="audio_loopback_failure">FAILURE - Could not allocate analyzer thread.</string>
 
     <!-- Audio Cold-Start Latency Test -->
@@ -5206,9 +5211,6 @@
     </string>
     <string name="audio_frequency_line_plug_ready_btn">Loopback Plug Ready</string>
 
-    <string name="audio_frequency_line_test_btn">Test</string>
-    <string name="audio_frequency_line_results_text">Results...</string>
-
     <!-- Audio Frequency Speaker Test -->
     <string name="audio_frequency_speaker_test">Audio Frequency Speaker Test</string>
     <string name="audio_frequency_speaker_info">
@@ -5223,8 +5225,6 @@
     <string name="audio_frequency_speaker_mic_ready_text">USB Audio device detected\n\nPlease set up Device Under test
     in quiet room, and Microphone 20 cms perpendicular to center of screen, then press TEST</string>
     <string name="audio_frequency_speaker_mic_not_ready_text">"No USB Audio device detected. Please reconnect."</string>
-    <string name="audio_frequency_speaker_test_btn">Test</string>
-    <string name="audio_frequency_speaker_results_text">Results...</string>
 
     <!-- Audio Frequency Microphone Test -->
     <string name="audio_frequency_mic_test">Audio Frequency Microphone Test</string>
@@ -5234,23 +5234,15 @@
 Follow the instructions on the screen to measure the frequency response for the built in microphone.
        </string>
 
-    <string name="frequency_mic_play">Play</string>
-    <string name="frequency_mic_stop">Stop</string>
     <string name="frequency_mic_noise_instructions">TEST NOISE: Position speakers 40 cms from device under test.
     Press [PLAY] to play broadband white noise. Press [TEST]
     </string>
-    <string name="frequency_mic_test_noise_btn">Test</string>
-    <string name="frequency_mic_test_noise_result">Results...</string>
 
     <string name="frequency_mic_test_usb_background_instructions">TEST USB BACKGROUND: Connect USB microphone and position it right next to microphone under test.
     No source of noise should be active during this test. Press [TEST]</string>
-    <string name="frequency_mic_test_usb_background_btn">Test</string>
-    <string name="frequency_mic_test_usb_background_result">Results...</string>
 
     <string name="frequency_mic_test_usb_noise_instructions">TEST USB NOISE: Connect USB microphone and position it right next to microphone under test.
     Position speakers 40 cms from device under test. Press [PLAY] to play broadband white noise. Press [TEST]</string>
-    <string name="frequency_mic_test_usb_noise_btn">Test</string>
-    <string name="frequency_mic_test_usb_noise_result">Results...</string>
 
     <string name="frequency_mic_test_global_result">Global Results...</string>
 
@@ -5267,30 +5259,17 @@
     <string name="audio_frequency_unprocessed_defined">Audio Frequency Unprocessed feature is defined. Success in all tests is mandatory to pass</string>
     <string name="audio_frequency_unprocessed_not_defined">Audio Frequency Unprocessed feature is NOT defined. Success in all test is NOT mandatory to pass</string>
 
-    <string name="unprocessed_play">Play</string>
-    <string name="unprocessed_stop">Stop</string>
-
     <string name="unprocessed_test_tone_instructions">TEST TONE: Press [PLAY] to play tone at 1 Khz. Measure sound SPL to be 94 dB
     right next to microphone under test. Press [TEST]</string>
-    <string name="unprocessed_test_tone_btn">Test</string>
-    <string name="unprocessed_test_tone_result">Results...</string>
 
     <string name="unprocessed_test_noise_instructions">TEST NOISE: Position speakers 40 cms from device under test.
     Press [PLAY] to play broadband white noise. Press [TEST]</string>
-    <string name="unprocessed_test_noise_btn">Test</string>
-    <string name="unprocessed_test_noise_result">Results...</string>
 
     <string name="unprocessed_test_usb_background_instructions">TEST USB BACKGROUND: Connect USB microphone and position it right next to microphone under test.
     No source of noise should be active during this test. Press [TEST]</string>
-    <string name="unprocessed_test_usb_background_btn">Test</string>
-    <string name="unprocessed_test_usb_background_result">Results...</string>
 
     <string name="unprocessed_test_usb_noise_instructions">TEST USB NOISE: Connect USB microphone and position it right next to microphone under test.
     Position speakers 40 cms from device under test. Press [PLAY] to play broadband white noise. Press [TEST]</string>
-    <string name="unprocessed_test_usb_noise_btn">Test</string>
-    <string name="unprocessed_test_usb_noise_result">Results...</string>
-
-    <string name="unprocessed_test_global_result">Global Results...</string>
 
     <!-- Audio Frequency Voice_Recognition Test -->
     <string name="audio_frequency_voice_recognition_test">Audio Frequency Voice Recognition Test</string>
@@ -5311,8 +5290,6 @@
     <!-- Analog Headset Test -->
     <string name="audio_headset_audio_test">Analog Headset Audio Test</string>
     <string name="analog_headset_query">Does this Android device have an analog headset jack?</string>
-    <string name="analog_headset_play">Play</string>
-    <string name="analog_headset_stop">Stop</string>
     <string name="analog_headset_playback_prompt">Play a test tone and verify correct playback</string>
     <string name="analog_headset_playback_query">Was the audio correctly played through the headset?</string>
     <string name="analog_headset_keycodes_label">Headset key codes</string>
@@ -5342,27 +5319,26 @@
         \n(see <a href="https://source.android.com/devices/accessories/headset/plug-headset-spec">3.5 mm Headset: Accessory Specification</a> and
         <a href="https://source.android.com/compatibility/android-cdd#7_8_2_1_analog_audio_ports">Android CDD § 7.8.2.1. Analog Audio Ports</a>)
     </string>
+
     <!-- Audio AEC Test -->
     <string name="audio_aec_test">Audio Acoustic Echo Cancellation (AEC) Test</string>
-    <string name="audio_aec_info">
-        The recording source VOICE_COMMUNICATION will be tested with/without the Acoustic Echo Canceller effect engaged.
-        The Acoustic Coupling Factor (ACF) will be computed for each case. A successful test expects ACF less than 0.4 for AEC ON,
-        and ACF greater than 0.6 for AEC OFF.
-        This test requires a quiet environment, and no headphones or similar connected.
-        This test must pass in devices where AEC functionality is mandatory or any device which implements AEC.
+    <string name="audio_aec_info">Tests Acoustic Echo Canceler (AEC) functionality.
+        \n\nTest Setup:
+        \n\"Microphone\" permission is required.
+        \nPerform the test in a quiet room, placing the DUT on a flat surface. Do not connect any headphones or other audio peripherals.
+        \n\nTest Process:
+        \n1. Verify that AEC is mandatory for the DUT. If the answer is NO, the test passes at this point.
+        \n2. Press the \"Test\" button. The test will playback/record a short audio clip with both AEC enabled and disabled
+        to verify that the DUT meets the requirements for Acoustic Coupling Factor (ACF) in both modes.
+        \n\nTest Criteria:
+        \nRequires an ACF of less that 0.4 with AEC engaged and greater that 0.6 with AEC disengaged.
+        \n\nCDD Section: <a href="https://source.android.com/compatibility/android-cdd#544_acoustic_echo_canceler">5.4.4. Acoustic Echo Canceler</a>
     </string>
     <string name="audio_aec_instructions">Press [TEST] to play a voice recording twice with different parameters.</string>
     <string name="audio_aec_mandatory_test">Is AEC mandatory in this device?</string>
 
     <!--Audio Frequency Global strings -->
-    <string name="af_button_play">Play</string>
-    <string name="af_button_stop">Stop</string>
-
-    <string name="af_button_test">Test</string>
-    <string name="af_test_results">Results...</string>
     <string name="af_global_test_results">Global Results...</string>
-    <string name="af_no">No</string>
-    <string name="af_yes">Yes</string>
 
     <!-- AudioTap2Tone test -->
     <string name="audio_tap2tone">Audio Tap To Tone Test</string>
@@ -6076,9 +6052,6 @@
     7. Click Pass button if checks in step 5 and 6 passed, otherwise click Fail button.
     </string>
 
-    <string name="uap_test_no">No</string>
-    <string name="uap_test_yes">Yes</string>
-    <string name="uap_test_info">Info</string>
     <string name="uap_test_question">Does this device allow for the connection of a USB audio peripheral?\nNote: phones and tablets generally do, watches and automobiles generally do not.</string>
     <string name="uap_refmic_question">Does this device allow for the connection of a USB reference microphone?</string>
     <string name="uap_mic_dlg_caption">USB Host Mode Audio Required</string>
@@ -6090,9 +6063,6 @@
     Note: Devices declaring feature android.hardware.audio.pro MUST implement USB host mode (CDD 5.10 C-1-3) and if they omit a 4 conductor 3.5mm audio jack MUST support USB audio class (CDD 5.10 C-3-1)
     </string>
 
-    <string name="refmic_test_no">No</string>
-    <string name="refmic_test_yes">Yes</string>
-    <string name="refmic_test_info">Info</string>
     <string name="refmic_test_question">Does this device allow for the connection of a USB reference microphone?</string>
     <string name="ref_mic_dlg_caption">Reference Mic Required</string>
     <string name="ref_mic_dlg_text">This test requires a USB Reference Mic to be connected to the device.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
index 72f5ae1..0f2ce9a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
@@ -266,8 +266,8 @@
     }
 
     private void setButtonPlayStatus(int playResId) {
-        String play = getResources().getText(R.string.frequency_mic_play).toString();
-        String stop = getResources().getText(R.string.frequency_mic_stop).toString();
+        String play = getResources().getText(R.string.audio_general_play).toString();
+        String stop = getResources().getText(R.string.audio_general_stop).toString();
 
         mButtonPlayNoise.setText(playResId == R.id.frequency_mic_play_noise_btn ? stop : play);
         mButtonPlayUsbNoise.setText(playResId ==
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
index 5509501..f8a0aca 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
@@ -333,8 +333,8 @@
     }
 
     private void setButtonPlayStatus(int playResId) {
-        String play = getResources().getText(R.string.unprocessed_play).toString();
-        String stop = getResources().getText(R.string.unprocessed_stop).toString();
+        String play = getResources().getText(R.string.audio_general_play).toString();
+        String stop = getResources().getText(R.string.audio_general_stop).toString();
 
         mButtonPlayTone.setText(playResId == R.id.unprocessed_play_tone_btn ? stop : play);
         mButtonPlayNoise.setText(playResId == R.id.unprocessed_play_noise_btn ? stop : play);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java
index 5ed51e3..b93ac62 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java
@@ -376,8 +376,8 @@
     }
 
     private void setButtonPlayStatus(int playResId) {
-        String play = getResources().getText(R.string.af_button_play).toString();
-        String stop = getResources().getText(R.string.af_button_stop).toString();
+        String play = getResources().getText(R.string.audio_general_play).toString();
+        String stop = getResources().getText(R.string.audio_general_stop).toString();
 
         mButtonPlayTone.setText(playResId == R.id.vr_button_play_tone ? stop : play);
         mButtonPlayNoise.setText(playResId == R.id.vr_button_play_noise ? stop : play);
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 9804cd3..9da33de 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
@@ -166,7 +166,7 @@
 
         Resources strings = getResources();
         if (hasPassed) {
-            mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_pass));
+            mTestStatusLbl.setText(strings.getString(R.string.audio_general_pass));
         } else if (!mClaimsMIDI) {
             mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_midinotreported));
         } else if (!mClaimsUSBHostMode) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralPlayActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralPlayActivity.java
index 4ae5ec3..5ce3da3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralPlayActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralPlayActivity.java
@@ -74,10 +74,10 @@
                 Log.i(TAG, "Play Button Pressed");
                 if (!isPlaying()) {
                     startPlay();
-                    mPlayBtn.setText(getString(R.string.audio_uap_play_stopBtn));
+                    mPlayBtn.setText(getString(R.string.audio_general_stop));
                 } else {
                     stopPlay();
-                    mPlayBtn.setText(getString(R.string.audio_uap_play_playBtn));
+                    mPlayBtn.setText(getString(R.string.audio_general_play));
                 }
                 break;
             }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralRecordActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralRecordActivity.java
index 880013f..5cd9884 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralRecordActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralRecordActivity.java
@@ -167,12 +167,12 @@
             case R.id.uap_recordRecordBtn:
                 if (!isRecording()) {
                     if (startRecording(false)) {
-                        mRecordBtn.setText(getString(R.string.audio_uap_record_stopBtn));
+                        mRecordBtn.setText(getString(R.string.audio_general_stop));
                         mRecordLoopbackBtn.setEnabled(false);
                     }
                 } else {
                     stopRecording();
-                    mRecordBtn.setText(getString(R.string.audio_uap_record_recordBtn));
+                    mRecordBtn.setText(getString(R.string.audio_general_record));
                     mRecordLoopbackBtn.setEnabled(true);
                 }
                 break;
@@ -180,13 +180,13 @@
             case R.id.uap_recordRecordLoopBtn:
                 if (!isRecording()) {
                     if (startRecording(true)) {
-                        mRecordLoopbackBtn.setText(getString(R.string.audio_uap_record_stopBtn));
+                        mRecordLoopbackBtn.setText(getString(R.string.audio_general_stop));
                         mRecordBtn.setEnabled(false);
                     }
                 } else {
                     stopRecording();
                     mRecordLoopbackBtn.setText(
-                        getString(R.string.audio_uap_record_recordLoopbackBtn));
+                        getString(R.string.audio_general_recordLoopback));
                     mRecordBtn.setEnabled(true);
                 }
                 break;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BackgroundRfcommTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BackgroundRfcommTestActivity.java
index feb8ce5..bf1a12c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BackgroundRfcommTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BackgroundRfcommTestActivity.java
@@ -79,7 +79,7 @@
         PendingIntent pendingIntent =
                 PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
 
-        mBluetoothAdapter.closeRfcommServer(mUuid);
+        mBluetoothAdapter.stopRfcommServer(mUuid);
 
         if (mBluetoothAdapter.startRfcommServer("TestBackgroundRfcomm", mUuid, pendingIntent)
                 != BluetoothStatusCodes.SUCCESS) {
@@ -90,7 +90,7 @@
 
     @Override
     protected void onDestroy() {
-        mBluetoothAdapter.closeRfcommServer(mUuid);
+        mBluetoothAdapter.stopRfcommServer(mUuid);
         if (mReceiver != null) {
             unregisterReceiver(mReceiver);
             mReceiver = null;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/OWNERS
new file mode 100644
index 0000000..2718191
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 1151772
+mrcasey@google.com
+mkephart@google.com
+moellerj@google.com
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/logcat/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/logcat/OWNERS
new file mode 100644
index 0000000..37638f4
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/logcat/OWNERS
@@ -0,0 +1,7 @@
+# Bug Component: 36824
+
+cbrubaker@google.com
+eunjeongshin@google.com
+jsharkey@google.com
+vishwath@google.com
+wenhaowang@google.com
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/BaseEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/BaseEmulatorActivity.java
index 4b682c1..263d43f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/BaseEmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/BaseEmulatorActivity.java
@@ -110,9 +110,8 @@
                     changeDefault.putExtra(CardEmulation.EXTRA_CATEGORY,
                             CardEmulation.CATEGORY_PAYMENT);
                     changeDefault.putExtra(CardEmulation.EXTRA_SERVICE_COMPONENT, defaultComponent);
-                    changeDefault.putExtra(CardEmulation.EXTRA_USERID,
-                            UserHandle.getUserHandleForUid(getApplicationInfo().uid)
-                            .getIdentifier());
+                    changeDefault.putExtra(Intent.EXTRA_USER,
+                            UserHandle.getUserHandleForUid(getApplicationInfo().uid));
                     startActivityForResult(changeDefault, 0);
                 }
             });
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceEmulatorTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceEmulatorTestActivity.java
index ab66339..bd4a262 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceEmulatorTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceEmulatorTestActivity.java
@@ -27,6 +27,7 @@
 import android.nfc.cardemulation.CardEmulation;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.SystemProperties;
 
 /** Activity that lists all the NFC HCE emulator tests. */
 public class HceEmulatorTestActivity extends PassFailButtons.TestListActivity {
@@ -131,13 +132,17 @@
                 }
             }
 
-            adapter.add(TestListItem.newTest(this, R.string.nfc_screen_on_only_offhost_emulator,
-                    ScreenOnOnlyOffHostEmulatorActivity.class.getName(),
-                    new Intent(this, ScreenOnOnlyOffHostEmulatorActivity.class), null));
+            int firstSdk =
+                    SystemProperties.getInt("ro.product.first_api_level", Build.VERSION_CODES.S);
+            if (firstSdk >= Build.VERSION_CODES.S) {
+                adapter.add(TestListItem.newTest(this, R.string.nfc_screen_on_only_offhost_emulator,
+                        ScreenOnOnlyOffHostEmulatorActivity.class.getName(),
+                        new Intent(this, ScreenOnOnlyOffHostEmulatorActivity.class), null));
 
-            adapter.add(TestListItem.newTest(this, R.string.nfc_screen_off_hce_payment_emulator,
-                    ScreenOffPaymentEmulatorActivity.class.getName(),
-                    new Intent(this, ScreenOffPaymentEmulatorActivity.class), null));
+                adapter.add(TestListItem.newTest(this, R.string.nfc_screen_off_hce_payment_emulator,
+                        ScreenOffPaymentEmulatorActivity.class.getName(),
+                        new Intent(this, ScreenOffPaymentEmulatorActivity.class), null));
+            }
         }
 
         setTestListAdapter(adapter);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceReaderTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceReaderTestActivity.java
index 4998d5c..fa5da2b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceReaderTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceReaderTestActivity.java
@@ -25,7 +25,9 @@
 
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.os.Build;
 import android.os.Bundle;
+import android.os.SystemProperties;
 
 /** Activity that lists all the NFC HCE reader tests. */
 public class HceReaderTestActivity extends PassFailButtons.TestListActivity {
@@ -121,14 +123,17 @@
                         ConflictingNonPaymentPrefixEmulatorActivity.buildReaderIntent(this), null));
             }
 
-            adapter.add(TestListItem.newTest(this, R.string.nfc_screen_on_only_offhost_reader,
-                    getString(R.string.nfc_screen_on_only_offhost_reader),
-                    ScreenOnOnlyOffHostEmulatorActivity.buildReaderIntent(this), null));
+            int firstSdk =
+                    SystemProperties.getInt("ro.product.first_api_level", Build.VERSION_CODES.S);
+            if (firstSdk >= Build.VERSION_CODES.S) {
+                adapter.add(TestListItem.newTest(this, R.string.nfc_screen_on_only_offhost_reader,
+                        getString(R.string.nfc_screen_on_only_offhost_reader),
+                        ScreenOnOnlyOffHostEmulatorActivity.buildReaderIntent(this), null));
 
-            adapter.add(TestListItem.newTest(this, R.string.nfc_screen_off_hce_payment_reader,
-                    getString(R.string.nfc_screen_off_hce_payment_reader),
-                    ScreenOffPaymentEmulatorActivity.buildReaderIntent(this), null));
-
+                adapter.add(TestListItem.newTest(this, R.string.nfc_screen_off_hce_payment_reader,
+                        getString(R.string.nfc_screen_off_hce_payment_reader),
+                        ScreenOffPaymentEmulatorActivity.buildReaderIntent(this), null));
+            }
         }
 
         setTestListAdapter(adapter);
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/ApiLevelUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/ApiLevelUtil.java
index 943ebc7..bb4c46e 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/ApiLevelUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/ApiLevelUtil.java
@@ -17,6 +17,7 @@
 package com.android.compatibility.common.util;
 
 import android.os.Build;
+import android.os.SystemProperties;
 
 import java.lang.reflect.Field;
 
@@ -61,6 +62,10 @@
         return Build.VERSION.SDK_INT;
     }
 
+    public static boolean isFirstApiAtLeast(int version) {
+        return SystemProperties.getInt("ro.product.first_api_level", 0) >= version;
+    }
+
     public static boolean codenameEquals(String name) {
         return Build.VERSION.CODENAME.equalsIgnoreCase(name.trim());
     }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/util/CarrierPrivilegeUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/CarrierPrivilegeUtils.java
similarity index 63%
rename from tests/tests/telephony/current/src/android/telephony/cts/util/CarrierPrivilegeUtils.java
rename to common/device-side/util-axt/src/com/android/compatibility/common/util/CarrierPrivilegeUtils.java
index ea46c9b..2b174a7 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/util/CarrierPrivilegeUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/CarrierPrivilegeUtils.java
@@ -14,16 +14,14 @@
  * limitations under the License.
  */
 
-package android.telephony.cts.util;
+package com.android.compatibility.common.util;
+
+import static android.telephony.TelephonyManager.CarrierPrivilegesListener;
 
 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
-import static com.android.internal.util.FunctionalUtils.ThrowingRunnable;
-import static com.android.internal.util.FunctionalUtils.ThrowingSupplier;
 
-import android.content.BroadcastReceiver;
+import android.Manifest;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.os.PersistableBundle;
@@ -32,9 +30,8 @@
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
-import com.android.internal.telephony.uicc.IccUtils;
-
 import java.security.MessageDigest;
+import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -45,73 +42,79 @@
  * task is completed.
  *
  * <p>Example:
- *
  * <pre>
  *   CarrierPrivilegeUtils.withCarrierPrivileges(c, subId, () -> telephonyManager.setFoo(bar));
  * </pre>
+ *
+ * @see {@link TelephonyManager#hasCarrierPrivileges()}
  */
-public class CarrierPrivilegeUtils {
+public final class CarrierPrivilegeUtils {
     private static final String TAG = CarrierPrivilegeUtils.class.getSimpleName();
 
-    private static class CarrierPrivilegeReceiver extends BroadcastReceiver
-            implements AutoCloseable {
-
+    private static class CarrierPrivilegeChangeMonitor implements AutoCloseable {
         private final CountDownLatch mLatch = new CountDownLatch(1);
         private final Context mContext;
         private final int mSubId;
         private final boolean mGain;
+        private final boolean mIsShell;
+        private final TelephonyManager mTelephonyManager;
+        private final CarrierPrivilegesListener mCarrierPrivilegesListener;
 
         /**
-         * Construct a listener that will wait for adding or removing carrier privileges.
-         *
-         * @param subId the subId to wait for.
-         * @param hash the package hash that indicate carrier privileges.
-         * @param gain if true, wait for the package to be added; if false, wait for the package to
-         *     be removed.
+         * Construct a {@link CarrierPrivilegesListener} to monitor carrier privileges change.
+         * @param c context
+         * @param subId subscriptionId to listen to
+         * @param gain true if wait to grant carrier privileges, false if wait to revoke
+         * @param isShell true if the caller is Shell
          */
-        CarrierPrivilegeReceiver(Context c, int subId, String hash, boolean gain) {
+        CarrierPrivilegeChangeMonitor(Context c, int subId, boolean gain, boolean isShell) {
             mContext = c;
             mSubId = subId;
             mGain = gain;
+            mIsShell = isShell;
+            mTelephonyManager = mContext.getSystemService(
+                    TelephonyManager.class).createForSubscriptionId(subId);
+            Objects.requireNonNull(mTelephonyManager);
 
-            mContext.registerReceiver(
-                    this, new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
+            mCarrierPrivilegesListener =
+                    (privilegedPackageNames, privilegedUids) -> {
+                        if (mTelephonyManager.hasCarrierPrivileges() == mGain) {
+                            mLatch.countDown();
+                        }
+                    };
+
+            // Run with shell identify only when caller is not Shell to avoid overriding current
+            // SHELL permissions
+            if (mIsShell) {
+                mTelephonyManager.addCarrierPrivilegesListener(
+                        SubscriptionManager.getSlotIndex(subId),
+                        mContext.getMainExecutor(),
+                        mCarrierPrivilegesListener);
+            } else {
+                runWithShellPermissionIdentity(() -> {
+                    mTelephonyManager.addCarrierPrivilegesListener(
+                            SubscriptionManager.getSlotIndex(subId),
+                            mContext.getMainExecutor(),
+                            mCarrierPrivilegesListener);
+                }, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+            }
         }
 
         @Override
         public void close() {
-            mContext.unregisterReceiver(this);
-        }
+            if (mTelephonyManager == null) return;
 
-        @Override
-        public void onReceive(Context c, Intent intent) {
-            if (!CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
-                return;
-            }
-
-            final int subId = intent.getIntExtra(
-                    CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
-                    SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-            if (mSubId != subId) {
-                return;
-            }
-
-            final PersistableBundle carrierConfigs =
-                    c.getSystemService(CarrierConfigManager.class).getConfigForSubId(mSubId);
-            if (!CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfigs)) {
-                return;
-            }
-
-            try {
-                if (hasCarrierPrivileges(c, mSubId) == mGain) {
-                    mLatch.countDown();
-                }
-            } catch (Exception e) {
+            if (mIsShell) {
+                mTelephonyManager.removeCarrierPrivilegesListener(mCarrierPrivilegesListener);
+            } else {
+                runWithShellPermissionIdentity(() -> {
+                    mTelephonyManager.removeCarrierPrivilegesListener(mCarrierPrivilegesListener);
+                }, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
             }
         }
 
         public void waitForCarrierPrivilegeChanged() throws Exception {
-            if (!mLatch.await(5000 /* millis */, TimeUnit.MILLISECONDS)) {
+            if (!mLatch.await(5, TimeUnit.SECONDS)) {
                 throw new IllegalStateException("Failed to update carrier privileges");
             }
         }
@@ -130,7 +133,7 @@
                 .getPackageInfo(c.getOpPackageName(), PackageManager.GET_SIGNATURES);
         final MessageDigest md = MessageDigest.getInstance("SHA-256");
         final byte[] certHash = md.digest(pkgInfo.signatures[0].toByteArray());
-        return IccUtils.bytesToHexString(certHash);
+        return UiccUtil.bytesToHexString(certHash);
     }
 
     private static void changeCarrierPrivileges(Context c, int subId, boolean gain, boolean isShell)
@@ -154,8 +157,8 @@
 
         final CarrierConfigManager configManager = c.getSystemService(CarrierConfigManager.class);
 
-        try (CarrierPrivilegeReceiver receiver =
-                new CarrierPrivilegeReceiver(c, subId, certHash, gain)) {
+        try (CarrierPrivilegeChangeMonitor monitor =
+                     new CarrierPrivilegeChangeMonitor(c, subId, gain, isShell)) {
             // If the caller is the shell, it's dangerous to adopt shell permission identity for
             // the CarrierConfig override (as it will override the existing shell permissions).
             if (isShell) {
@@ -166,7 +169,7 @@
                 }, android.Manifest.permission.MODIFY_PHONE_STATE);
             }
 
-            receiver.waitForCarrierPrivilegeChanged();
+            monitor.waitForCarrierPrivilegeChanged();
         }
     }
 
@@ -174,7 +177,7 @@
             throws Exception {
         try {
             changeCarrierPrivileges(c, subId, true /* gain */, false /* isShell */);
-            action.runOrThrow();
+            action.run();
         } finally {
             changeCarrierPrivileges(c, subId, false /* lose */, false /* isShell */);
         }
@@ -185,7 +188,7 @@
             throws Exception {
         try {
             changeCarrierPrivileges(c, subId, true /* gain */, true /* isShell */);
-            action.runOrThrow();
+            action.run();
         } finally {
             changeCarrierPrivileges(c, subId, false /* lose */, true /* isShell */);
         }
@@ -195,7 +198,7 @@
             throws Exception {
         try {
             changeCarrierPrivileges(c, subId, true /* gain */, false /* isShell */);
-            return action.getOrThrow();
+            return action.get();
         } finally {
             changeCarrierPrivileges(c, subId, false /* lose */, false /* isShell */);
         }
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 8318201..6f0c6ed 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
@@ -16,6 +16,9 @@
 package com.android.compatibility.common.util;
 
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.res.AssetFileDescriptor;
 import android.drm.DrmConvertedStatus;
 import android.drm.DrmManagerClient;
@@ -32,10 +35,16 @@
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.net.Uri;
+import android.os.BatteryManager;
 import android.os.Build;
+import android.os.SystemProperties;
 import android.os.ParcelFileDescriptor;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Range;
+import android.view.WindowManager;
+
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.ResultType;
@@ -61,6 +70,11 @@
 
 public class MediaUtils {
     private static final String TAG = "MediaUtils";
+    private static final Context mContext =
+            InstrumentationRegistry.getInstrumentation().getTargetContext();
+    private static final PackageManager pm = mContext.getPackageManager();
+    private static final boolean FIRST_SDK_IS_AT_LEAST_R =
+            ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.R);
 
     /*
      *  ----------------------- HELPER METHODS FOR SKIPPING TESTS -----------------------
@@ -1409,6 +1423,70 @@
         return result.toString();
     }
 
+
+    /*
+     *  ------------------- HELPER METHODS FOR DETECTING DEVICE TYPES -------------------
+     */
+
+    public static boolean hasDeviceGotBattery() {
+        final Intent batteryInfo = mContext.registerReceiver(null,
+                new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+        return batteryInfo.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
+    }
+
+    public static double getScreenSizeInInches() {
+        DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
+        double widthInInchesSquared = Math.pow(dm.widthPixels/dm.xdpi,2);
+        double heightInInchesSquared = Math.pow(dm.heightPixels/dm.ydpi,2);
+        double diagonalInInches = Math.sqrt(widthInInchesSquared + heightInInchesSquared);
+        return diagonalInInches;
+    }
+
+    public static boolean isTv() {
+        return pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK) ||
+                pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION);
+    }
+
+    public static boolean hasMicrophone() {
+        return pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE);
+    }
+
+    public static boolean hasCamera() {
+        return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
+    }
+
+    public static boolean isWatch() {
+        return pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+    }
+
+    public static boolean isAutomotive() {
+        return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
+
+    public static boolean isPc() {
+        return pm.hasSystemFeature(PackageManager.FEATURE_PC);
+    }
+
+    public static boolean hasAudioOutput() {
+        return pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
+    }
+
+    public static boolean isHandheld() {
+        double screenSize = getScreenSizeInInches();
+        if (screenSize < (FIRST_SDK_IS_AT_LEAST_R ? 3.3 : 2.5)) return false;
+        if (screenSize > 8.0) return false;
+        if (!hasDeviceGotBattery()) return false;
+        return true;
+    }
+
+    public static boolean isTablet() {
+        double screenSize = getScreenSizeInInches();
+        if (screenSize < 7.0) return false;
+        if (screenSize > 18.0) return false;
+        if (!hasDeviceGotBattery()) return false;
+        return true;
+    }
+
     /*
      *  ------------------- HELPER METHODS FOR DETECTING NON-PRODUCTION DEVICES -------------------
      */
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
index b8562ab..4125ede 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
@@ -44,7 +44,6 @@
     private static final String CAMERAX_EXTENSIONS_ENABLED = "ro.camerax.extensions.enabled";
     private static final String MANUFACTURER_PROPERTY = "ro.product.manufacturer";
     private static final String TAG_DEV_KEYS = "dev-keys";
-    private static final String VENDOR_BUILD_VERSION_SDK = "ro.vendor.build.version.sdk";
     private static final String VNDK_VERSION = "ro.vndk.version";
 
     public static final String GOOGLE_SETTINGS_QUERY =
@@ -91,12 +90,12 @@
 
     /**
      * Return the API level that the VSR requirement must be fulfilled. It reads
-     * ro.product.first_api_level, ro.board.first_api_level, and ro.board.api_level
-     * to find the minimum required VSR api_level for the DUT.
+     * ro.product.first_api_level and ro.board.first_api_level to find the minimum required VSR
+     * api_level for the DUT.
      */
     public static int getVsrApiLevel() {
         // Api level properties of the board. The order of the properties must be kept.
-        String[] boardApiLevelProps = { BOARD_API_LEVEL, BOARD_FIRST_API_LEVEL, VENDOR_BUILD_VERSION_SDK };
+        String[] boardApiLevelProps = {BOARD_API_LEVEL, BOARD_FIRST_API_LEVEL};
         for (String apiLevelProp : boardApiLevelProps) {
             int apiLevel = getPropertyInt(apiLevelProp);
             if (apiLevel != INT_VALUE_IF_UNSET) {
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 69b59e8..610ce88 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
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.telephony.TelephonyManager;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.StringDef;
 import androidx.test.InstrumentationRegistry;
 
@@ -26,6 +27,11 @@
 
 /** 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'
+    };
+
     /** The hashes of all supported CTS UICC test keys and their corresponding specification. */
     @StringDef({UiccCertificate.CTS_UICC_LEGACY, UiccCertificate.CTS_UICC_2021})
     public @interface UiccCertificate {
@@ -72,4 +78,28 @@
                         Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
         return uiccCerts == null ? false : uiccCerts.contains(requiredCert);
     }
+
+    /**
+     * 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);
+
+        for (int i = 0 ; i < bytes.length ; i++) {
+            int b;
+            b = 0x0f & (bytes[i] >> 4);
+            ret.append(HEX_CHARS[b]);
+            b = 0x0f & bytes[i];
+            ret.append(HEX_CHARS[b]);
+        }
+
+        return ret.toString();
+    }
 }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java
index db6124a..be7ab00 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java
@@ -86,6 +86,7 @@
 
         removeTestPackages();
         deviceDisableDeviceConfigSync();
+        deviceSetupServerBasedParameter();
     }
 
     @After
@@ -95,46 +96,8 @@
     }
 
     @Test
-    public void resumeOnReboot_SingleUser_Success() throws Exception {
-        if (!isSupportedDevice()) {
-            CLog.v(TAG, "Device not supported; skipping test");
-            return;
-        }
-
-        int[] users = Utils.prepareSingleUser(getDevice());
-        int initialUser = users[0];
-
-        // Clean up the server based parameters for HAL based test.
-        deviceCleanupServerBasedParameter();
-
-        try {
-            installTestPackages();
-
-            deviceSetup(initialUser);
-            deviceRequestLskf();
-            deviceLock(initialUser);
-            deviceEnterLskf(initialUser);
-            deviceRebootAndApply();
-
-            runDeviceTestsAsUser("testVerifyUnlockedAndDismiss", initialUser);
-        } finally {
-            try {
-                // Remove secure lock screens and tear down test app
-                runDeviceTestsAsUser("testTearDown", initialUser);
-
-                deviceClearLskf();
-            } finally {
-                removeTestPackages();
-            }
-        }
-    }
-
-    @Test
     public void resumeOnReboot_ManagedProfile_Success() throws Exception {
-        if (!isSupportedDevice()) {
-            CLog.v(TAG, "Device not supported; skipping test");
-            return;
-        }
+        assumeTrue("Device isn't at least S or has no lock screen", isSupportedSDevice());
 
         if (!getDevice().hasFeature("android.software.managed_users")) {
             CLog.v(TAG, "Device doesn't support managed users; skipping test");
@@ -146,8 +109,6 @@
 
         int managedUserId = createManagedProfile(initialUser);
 
-        deviceCleanupServerBasedParameter();
-
         try {
             // Set up test app and secure lock screens
             installTestPackages();
@@ -177,10 +138,7 @@
 
     @Test
     public void resumeOnReboot_TwoUsers_SingleUserUnlock_Success() throws Exception {
-        if (!isSupportedDevice()) {
-            CLog.v(TAG, "Device not supported; skipping test");
-            return;
-        }
+        assumeTrue("Device isn't at least S or has no lock screen", isSupportedSDevice());
 
         if (!mSupportsMultiUser) {
             CLog.v(TAG, "Device doesn't support multi-user; skipping test");
@@ -191,8 +149,6 @@
         int initialUser = users[0];
         int secondaryUser = users[1];
 
-        deviceCleanupServerBasedParameter();
-
         try {
             // Set up test app and secure lock screens
             installTestPackages();
@@ -234,10 +190,7 @@
 
     @Test
     public void resumeOnReboot_TwoUsers_BothUserUnlock_Success() throws Exception {
-        if (!isSupportedDevice()) {
-            CLog.v(TAG, "Device not supported; skipping test");
-            return;
-        }
+        assumeTrue("Device isn't at least S or has no lock screen", isSupportedSDevice());
 
         if (!mSupportsMultiUser) {
             CLog.v(TAG, "Device doesn't support multi-user; skipping test");
@@ -248,8 +201,6 @@
         int initialUser = users[0];
         int secondaryUser = users[1];
 
-        deviceCleanupServerBasedParameter();
-
         try {
             installTestPackages();
 
@@ -291,23 +242,13 @@
         }
     }
 
-    private boolean isSupportedSDevice() throws Exception {
-        // The following tests targets API level >= S.
-        boolean isAtleastS = ApiLevelUtil.isAfter(getDevice(), 30 /* BUILD.VERSION_CODES.R */)
-                || ApiLevelUtil.codenameEquals(getDevice(), "S");
-
-        return isAtleastS && getDevice().hasFeature(FEATURE_SECURE_LOCK_SCREEN);
-    }
-
     @Test
     public void resumeOnReboot_SingleUser_ServerBased_Success() throws Exception {
-        assumeTrue("Device isn't at least S or have no lock screen", isSupportedSDevice());
+        assumeTrue("Device isn't at least S or has no lock screen", isSupportedSDevice());
 
         int[] users = Utils.prepareSingleUser(getDevice());
         int initialUser = users[0];
 
-        deviceSetupServerBasedParameter();
-
         try {
             installTestPackages();
 
@@ -327,7 +268,6 @@
                 deviceClearLskf();
             } finally {
                 removeTestPackages();
-                deviceCleanupServerBasedParameter();
 
                 getDevice().rebootUntilOnline();
                 getDevice().waitForDeviceAvailable();
@@ -337,13 +277,11 @@
 
     @Test
     public void resumeOnReboot_SingleUser_MultiClient_ClientASuccess() throws Exception {
-        assumeTrue("Device isn't at least S or have no lock screen", isSupportedSDevice());
+        assumeTrue("Device isn't at least S or has no lock screen", isSupportedSDevice());
 
         int[] users = Utils.prepareSingleUser(getDevice());
         int initialUser = users[0];
 
-        deviceSetupServerBasedParameter();
-
         final String clientA = "ClientA";
         final String clientB = "ClientB";
         try {
@@ -370,7 +308,6 @@
                 deviceClearLskf();
             } finally {
                 removeTestPackages();
-                deviceCleanupServerBasedParameter();
 
                 getDevice().rebootUntilOnline();
                 getDevice().waitForDeviceAvailable();
@@ -380,13 +317,11 @@
 
     @Test
     public void resumeOnReboot_SingleUser_MultiClient_ClientBSuccess() throws Exception {
-        assumeTrue("Device isn't at least S or have no lock screen", isSupportedSDevice());
+        assumeTrue("Device isn't at least S or has no lock screen", isSupportedSDevice());
 
         int[] users = Utils.prepareSingleUser(getDevice());
         int initialUser = users[0];
 
-        deviceSetupServerBasedParameter();
-
         final String clientA = "ClientA";
         final String clientB = "ClientB";
         try {
@@ -412,7 +347,6 @@
                 deviceClearLskf();
             } finally {
                 removeTestPackages();
-                deviceCleanupServerBasedParameter();
 
                 getDevice().rebootUntilOnline();
                 getDevice().waitForDeviceAvailable();
@@ -631,9 +565,12 @@
         Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, CLASS, testMethodName);
     }
 
-    private boolean isSupportedDevice() throws Exception {
-        return getDevice().hasFeature(FEATURE_DEVICE_ADMIN)
-                && getDevice().hasFeature(FEATURE_REBOOT_ESCROW);
+    private boolean isSupportedSDevice() throws Exception {
+        // The following tests targets API level >= S.
+        boolean isAtleastS = ApiLevelUtil.isAfter(getDevice(), 30 /* BUILD.VERSION_CODES.R */)
+                || ApiLevelUtil.codenameEquals(getDevice(), "S");
+
+        return isAtleastS && getDevice().hasFeature(FEATURE_SECURE_LOCK_SCREEN);
     }
 
     private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
diff --git a/hostsidetests/blobstore/src/com/android/cts/host/blob/DataPersistenceTest.java b/hostsidetests/blobstore/src/com/android/cts/host/blob/DataPersistenceTest.java
index 973ca8b..076819b 100644
--- a/hostsidetests/blobstore/src/com/android/cts/host/blob/DataPersistenceTest.java
+++ b/hostsidetests/blobstore/src/com/android/cts/host/blob/DataPersistenceTest.java
@@ -31,7 +31,7 @@
         rebootAndWaitUntilReady();
         runDeviceTest(TARGET_PKG, TEST_CLASS, "testOpenSessionAndWrite");
         rebootAndWaitUntilReady();
-        runDeviceTest(TARGET_PKG, TEST_CLASS, "testCommitSession");
+        runDeviceTest(TARGET_PKG, TEST_CLASS, "testCommitSessionAndAcquireLease");
         rebootAndWaitUntilReady();
         runDeviceTest(TARGET_PKG, TEST_CLASS, "testOpenBlob");
     }
diff --git a/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/DataPersistenceTest.java b/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/DataPersistenceTest.java
index 2efc523..90a406c 100644
--- a/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/DataPersistenceTest.java
+++ b/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/DataPersistenceTest.java
@@ -75,7 +75,7 @@
     }
 
     @Test
-    public void testCommitSession() throws Exception {
+    public void testCommitSessionAndAcquireLease() throws Exception {
         final long sessionId = readSessionIdFromDisk();
         try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
             final CompletableFuture<Integer> callback = new CompletableFuture<>();
@@ -83,6 +83,8 @@
             assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_MS, TimeUnit.MILLISECONDS))
                     .isEqualTo(0);
         }
+        final BlobHandle blobHandle = readBlobHandleFromDisk();
+        mBlobStoreManager.acquireLease(blobHandle, "test desc");
     }
 
     @Test
diff --git a/hostsidetests/content/OWNERS b/hostsidetests/content/OWNERS
index 84911ce..6f4eaa8 100644
--- a/hostsidetests/content/OWNERS
+++ b/hostsidetests/content/OWNERS
@@ -1,2 +1,3 @@
 # Bug component: 197138
-svetoslavganov@google.com
+omakoto@google.com
+varunshah@google.com
diff --git a/hostsidetests/hdmicec/app/Android.bp b/hostsidetests/hdmicec/app/Android.bp
index 09f4fbf..965746b 100644
--- a/hostsidetests/hdmicec/app/Android.bp
+++ b/hostsidetests/hdmicec/app/Android.bp
@@ -20,7 +20,6 @@
     name: "HdmiCecHelperApp",
     defaults: ["cts_defaults"],
     platform_apis: true,
-    certificate: "platform",
     srcs: ["src/**/*.java"],
     static_libs: [
         "androidx.test.runner",
diff --git a/hostsidetests/hdmicec/app/AndroidManifest.xml b/hostsidetests/hdmicec/app/AndroidManifest.xml
index dde8441..4eb046e3 100644
--- a/hostsidetests/hdmicec/app/AndroidManifest.xml
+++ b/hostsidetests/hdmicec/app/AndroidManifest.xml
@@ -19,7 +19,6 @@
      package="android.hdmicec.app">
     <uses-feature android:name="android.software.leanback"
          android:required="false"/>
-    <uses-permission android:name="android.permission.HDMI_CEC" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <application>
         <activity android:name=".HdmiCecKeyEventCapture"
@@ -49,21 +48,6 @@
                 <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
             </intent-filter>
         </activity>
-        <activity android:name=".HdmiControlManagerHelper" >
-            <intent-filter>
-                <action android:name="android.hdmicec.app.OTP" />
-                <action android:name="android.hdmicec.app.DEVICE_SELECT" />
-            </intent-filter>
-        </activity>
-        <activity android:name=".HdmiCecVendorCommandListener"
-             android:exported="true">
-            <intent-filter>
-                <action android:name="android.hdmicec.app.VENDOR_LISTENER_WITH_ID"/>
-                <action android:name="android.hdmicec.app.VENDOR_LISTENER_WITHOUT_ID"/>
-                <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
-            </intent-filter>
-        </activity>
-
         <uses-library android:name="android.test.runner" />
     </application>
 
diff --git a/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiControlManagerHelper.java b/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiControlManagerHelper.java
index 5ff7aaa..7a05c13 100755
--- a/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiControlManagerHelper.java
+++ b/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiControlManagerHelper.java
@@ -16,67 +16,60 @@
 
 package android.hdmicec.app;
 
+import static android.Manifest.permission.HDMI_CEC;
+
 import android.app.Activity;
+import android.content.Context;
+import android.hardware.hdmi.HdmiClient;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiPlaybackClient;
 import android.hardware.hdmi.HdmiTvClient;
-import android.os.Bundle;
 import android.util.Log;
+import android.view.KeyEvent;
+
+
+import java.util.concurrent.TimeUnit;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
- * A simple activity that can be used to trigger actions using the HdmiControlManager. The actions
- * supported are:
- *
- * <p>
- *
- * <p>1. android.hdmicec.app.OTP: Triggers the OTP
- *
- * <p>Usage: <code>START_COMMAND -a android.hdmicec.app.OTP</code>
- *
- * <p>
- *
- * <p>2. android.hdmicec.app.SELECT_DEVICE: Selects a device to be the active source. The logical
- * address of the device that has to be made the active source has to passed as a parameter.
- *
- * <p>Usage: <code>START_COMMAND -a android.hdmicec.app.DEVICE_SELECT --ei "la" [LOGICAL_ADDRESS]
- * </code>
- *
- * <p>
- *
- * <p>where START_COMMAND is
- *
- * <p><code>
- * adb shell am start -n "android.hdmicec.app/android.hdmicec.app.HdmiControlManagerHelper"
- * </code>
+ * A simple class that can be used to trigger actions using the HdmiControlManager.
  */
-public class HdmiControlManagerHelper extends Activity {
-
+@RunWith(AndroidJUnit4.class)
+public final class HdmiControlManagerHelper {
+    private static final String LOGICAL_ADDR = "ARG_LOGICAL_ADDR";
     private static final String TAG = HdmiControlManagerHelper.class.getSimpleName();
     HdmiControlManager mHdmiControlManager;
 
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
+    @Before
+    public void setUp() throws Exception {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+                HDMI_CEC);
 
-        mHdmiControlManager = getSystemService(HdmiControlManager.class);
+        mHdmiControlManager = context.getSystemService(HdmiControlManager.class);
         if (mHdmiControlManager == null) {
             Log.i(TAG, "Failed to get HdmiControlManager");
             return;
         }
-
-        switch (getIntent().getAction()) {
-            case "android.hdmicec.app.OTP":
-                initiateOtp();
-                break;
-            case "android.hdmicec.app.DEVICE_SELECT":
-                int logicalAddress = getIntent().getIntExtra("la", 50);
-                deviceSelect(logicalAddress);
-            default:
-                Log.w(TAG, "Unknown intent!");
-        }
     }
 
-    private void deviceSelect(int logicalAddress) {
+    @After
+    public void tearDown() {
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+
+    @Test
+    public void deviceSelect() throws InterruptedException {
+        final String param = InstrumentationRegistry.getArguments().getString(LOGICAL_ADDR);
+        int logicalAddress = Integer.parseInt(param);
         HdmiTvClient client = mHdmiControlManager.getTvClient();
         if (client == null) {
             Log.e(TAG, "Failed to get the TV client");
@@ -93,25 +86,32 @@
                                 TAG,
                                 "Could not select device with logical address " + logicalAddress);
                     }
-                    finishAndRemoveTask();
                 });
     }
 
-    private void initiateOtp() {
-        HdmiPlaybackClient client = mHdmiControlManager.getPlaybackClient();
+    @Test
+    public void interruptedLongPress() throws InterruptedException {
+        HdmiClient client = mHdmiControlManager.getPlaybackClient();
         if (client == null) {
-            Log.i(TAG, "Failed to get HdmiPlaybackClient");
+            client = mHdmiControlManager.getTvClient();
+        }
+
+        if (client == null) {
+            Log.i(TAG, "Could not get a TV/Playback client, cannot send key event");
             return;
         }
 
-        client.oneTouchPlay(
-                (result) -> {
-                    if (result == HdmiControlManager.RESULT_SUCCESS) {
-                        Log.i(TAG, "OTP successful");
-                    } else {
-                        Log.i(TAG, "OTP failed");
-                    }
-                    finishAndRemoveTask();
-                });
+        try {
+            for (int i = 0; i < 5; i++) {
+                client.sendKeyEvent(KeyEvent.KEYCODE_DPAD_UP, true);
+                TimeUnit.MILLISECONDS.sleep(450);
+            }
+            client.sendKeyEvent(KeyEvent.KEYCODE_DPAD_UP, false);
+            // Sleep for 500ms more
+            TimeUnit.MILLISECONDS.sleep(500);
+            client.sendKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, true);
+        } catch (InterruptedException ie) {
+            Log.w(TAG, "Interrupted between keyevents, could not send all keyevents!");
+        }
     }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java
index 58e767e..f5a6454 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java
@@ -16,7 +16,7 @@
 
 package android.hdmicec.cts;
 
-import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assume.assumeTrue;
 
@@ -47,6 +47,8 @@
 
     public static final String PROPERTY_LOCALE = "persist.sys.locale";
     private static final String POWER_CONTROL_MODE = "power_control_mode";
+    private static final String POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST =
+            "power_state_change_on_active_source_lost";
 
     /** Enum contains the list of possible address types. */
     private enum AddressType {
@@ -190,6 +192,36 @@
                 "Could not parse logicalAddress from dumpsys.");
     }
 
+    /**
+     * Gets the system audio mode status of the device by parsing the dumpsys hdmi_control. Returns
+     * true when system audio mode is on and false when system audio mode is off
+     */
+    public boolean isSystemAudioModeOn(ITestDevice device) throws DumpsysParseException {
+        List<LogicalAddress> logicalAddressList = new ArrayList<>();
+        String line;
+        String pattern =
+                "(.*?)"
+                        + "(mSystemAudioActivated: )"
+                        + "(?<"
+                        + "systemAudioModeStatus"
+                        + ">[true|false])"
+                        + "(.*?)";
+        Pattern p = Pattern.compile(pattern);
+        try {
+            String dumpsys = device.executeShellCommand("dumpsys hdmi_control");
+            BufferedReader reader = new BufferedReader(new StringReader(dumpsys));
+            while ((line = reader.readLine()) != null) {
+                Matcher m = p.matcher(line);
+                if (m.matches()) {
+                    return m.group("systemAudioModeStatus").equals("true");
+                }
+            }
+        } catch (IOException | DeviceNotAvailableException e) {
+            throw new DumpsysParseException("Could not parse system audio mode from dumpsys.", e);
+        }
+        throw new DumpsysParseException("Could not parse system audio mode from dumpsys.");
+    }
+
     /** Gets the DUT's logical address to which messages should be sent */
     public LogicalAddress getTargetLogicalAddress() throws DumpsysParseException {
         return getTargetLogicalAddress(getDevice(), mTestDeviceType);
@@ -366,16 +398,9 @@
                 "dumpsys hdmi_control | sed -n '/mDeviceInfos/,/mCecController/{//!p;}'");
     }
 
-    public void checkDeviceAsleep() throws Exception {
-        ITestDevice device = getDevice();
-        TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
-        String wakeState = device.executeShellCommand("dumpsys power | grep mWakefulness=");
-        assertThat(wakeState.trim()).isEqualTo("mWakefulness=Asleep");
-    }
-
     public void sendDeviceToSleepAndValidate() throws Exception {
         sendDeviceToSleep();
-        checkDeviceAsleep();
+        assertDeviceWakefulness(HdmiCecConstants.WAKEFULNESS_ASLEEP);
     }
 
     public void waitForTransitionTo(int finalState) throws Exception {
@@ -417,6 +442,7 @@
 
     public void sendDeviceToSleep() throws Exception {
         sendDeviceToSleepWithoutWait();
+        assertDeviceWakefulness(HdmiCecConstants.WAKEFULNESS_ASLEEP);
         waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
     }
 
@@ -436,15 +462,45 @@
     public void wakeUpDevice() throws Exception {
         ITestDevice device = getDevice();
         device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        assertDeviceWakefulness(HdmiCecConstants.WAKEFULNESS_AWAKE);
         waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_ON);
         WakeLockHelper.releasePartialWakeLock(device);
     }
 
+    public void wakeUpDeviceWithoutWait() throws Exception {
+        ITestDevice device = getDevice();
+        device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        assertDeviceWakefulness(HdmiCecConstants.WAKEFULNESS_AWAKE);
+        WakeLockHelper.releasePartialWakeLock(device);
+    }
+
     public void checkStandbyAndWakeUp() throws Exception {
-        checkDeviceAsleep();
+        assertDeviceWakefulness(HdmiCecConstants.WAKEFULNESS_ASLEEP);
         wakeUpDevice();
     }
 
+    public void assertDeviceWakefulness(String wakefulness) throws Exception {
+        ITestDevice device = getDevice();
+        String actualWakefulness;
+        int waitTimeSeconds = 0;
+
+        do {
+            TimeUnit.SECONDS.sleep(HdmiCecConstants.SLEEP_TIMESTEP_SECONDS);
+            waitTimeSeconds += HdmiCecConstants.SLEEP_TIMESTEP_SECONDS;
+            actualWakefulness =
+                    device.executeShellCommand("dumpsys power | grep mWakefulness=")
+                            .trim().replace("mWakefulness=", "");
+        } while (!actualWakefulness.equals(wakefulness)
+                && waitTimeSeconds <= HdmiCecConstants.MAX_SLEEP_TIME_SECONDS);
+        assertWithMessage(
+                "Device wakefulness is "
+                        + actualWakefulness
+                        + " but expected to be "
+                        + wakefulness)
+                .that(actualWakefulness)
+                .isEqualTo(wakefulness);
+    }
+
     public void sendOtp() throws Exception {
         ITestDevice device = getDevice();
         device.executeShellCommand("cmd hdmi_control onetouchplay");
@@ -456,6 +512,13 @@
         return val;
     }
 
+    public String setPowerStateChangeOnActiveSourceLost(String valToSet) throws Exception {
+        String previousPowerStateChange =
+                getSettingsValue(POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST);
+        setSettingsValue(POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, valToSet);
+        return previousPowerStateChange;
+    }
+
     public boolean isDeviceActiveSource(ITestDevice device) throws DumpsysParseException {
         final String activeSource = "activeSource";
         final String pattern =
@@ -481,4 +544,39 @@
         }
         throw new DumpsysParseException("Could not parse isActiveSource() from dumpsys.");
     }
+
+    /**
+     * For source devices, simulate that a sink is connected by responding to the
+     * {@code Give Power Status} message that is sent when re-enabling CEC.
+     * Validate that HdmiControlService#mIsCecAvailable is set to true as a result.
+     */
+    public void simulateCecSinkConnected(ITestDevice device, LogicalAddress source)
+            throws Exception {
+        hdmiCecClient.clearClientOutput();
+        device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 0");
+        device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 1");
+        // When a CEC device has just become available, the CEC adapter isn't able to send it
+        // messages right away. Therefore we let the first <Give Power Status> message time-out, and
+        // only respond to the retry.
+        hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.GIVE_POWER_STATUS);
+        hdmiCecClient.clearClientOutput();
+        hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.GIVE_POWER_STATUS);
+        hdmiCecClient.sendCecMessage(LogicalAddress.TV, source, CecOperand.REPORT_POWER_STATUS,
+                CecMessage.formatParams(HdmiCecConstants.CEC_POWER_STATUS_STANDBY));
+        checkIsCecAvailable(device);
+    }
+
+    private void checkIsCecAvailable(ITestDevice device) throws Exception {
+        boolean isCecAvailable;
+        int waitTimeSeconds = 0;
+        do {
+            TimeUnit.SECONDS.sleep(HdmiCecConstants.SLEEP_TIMESTEP_SECONDS);
+            waitTimeSeconds += HdmiCecConstants.SLEEP_TIMESTEP_SECONDS;
+            isCecAvailable =
+                    device.executeShellCommand("dumpsys hdmi_control | grep mIsCecAvailable:")
+                            .replace("mIsCecAvailable:", "").trim().equals("true");
+        } while (!isCecAvailable && waitTimeSeconds <= HdmiCecConstants.MAX_SLEEP_TIME_SECONDS);
+        assertWithMessage("Simulating that a sink is connected, failed.")
+                .that(isCecAvailable).isTrue();
+    }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
index c313680..083cf2e 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
@@ -130,6 +130,10 @@
     public static final int CEC_POWER_STATUS_IN_TRANSITION_TO_ON = 0x2;
     public static final int CEC_POWER_STATUS_IN_TRANSITION_TO_STANDBY = 0x3;
 
+    /** PowerManager wakefulness states */
+    public static final String WAKEFULNESS_AWAKE = "Awake";
+    public static final String WAKEFULNESS_ASLEEP = "Asleep";
+
     /** Poll Message Success */
     public static final String POLL_SUCCESS = "POLL message sent";
 
@@ -153,6 +157,10 @@
     public static final String POWER_CONTROL_MODE_NONE = "none";
     public static final String POWER_CONTROL_MODE_TV = "to_tv";
 
+    // Power State Change on Active Source Lost Settings values
+    public static final String POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE = "none";
+    public static final String POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW = "standby_now";
+
     // CEC 2.0 Report Feature Bits
     public static final int FEATURES_SINK_SUPPORTS_ARC_TX_BIT = 0x4;
     public static final int FEATURES_SINK_SUPPORTS_ARC_RX_BIT = 0x2;
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiControlManagerUtility.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiControlManagerUtility.java
index cb92093..8e81ab3 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiControlManagerUtility.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiControlManagerUtility.java
@@ -18,37 +18,51 @@
 
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
-/** Helper class to call intents in the HdmiCecControlManagerHelper app */
+import java.util.HashMap;
+import java.util.Map;
+
+/** Helper class to call tests in the HdmiCecControlManagerHelper app */
 public class HdmiControlManagerUtility {
     /** The package name of the APK. */
-    private static final String PACKAGE = "android.hdmicec.app";
+    private static final String TEST_PKG = "android.hdmicec.app";
 
     /** The class name of the main activity in the APK. */
-    private static final String CLASS = "HdmiControlManagerHelper";
+    private static final String TEST_CLS = "android.hdmicec.app.HdmiControlManagerHelper";
 
-    /** The command to launch the main activity. */
-    private static final String START_COMMAND =
-            String.format("am start -n %s/%s.%s -a ", PACKAGE, PACKAGE, CLASS);
+    /** The method name of the set active source case. */
+    private static final String SELECT_DEVICE = "deviceSelect";
 
-    /** The command to clear the main activity. */
-    private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE);
+    /** The method name of the set active source case. */
+    private static final String SEND_INTERRUPTED_LONG_PRESS = "interruptedLongPress";
+
+    /** The key of the set active source case arguments. */
+    private static final String LOGICAL_ADDR = "ARG_LOGICAL_ADDR";
+
+    /** The timeout of the test. */
+    private static final long TEST_TIMEOUT_MS = 10 * 60 * 1000L;
 
     /**
      * Method to make a device the active source. Will only work if the DUT is TV.
      *
+     * @param host Reference to the JUnit4 host test class
      * @param device Reference to the DUT
      * @param logicalAddress The logical address of the device that should be made the active source
      */
-    public static void setActiveSource(ITestDevice device, int logicalAddress)
-            throws DeviceNotAvailableException {
-        // Clear activity
-        device.executeShellCommand(CLEAR_COMMAND);
-        // Start the APK and wait for it to complete.
-        device.executeShellCommand(
-                START_COMMAND
-                        + "android.hdmicec.app.DEVICE_SELECT --ei "
-                        + "\"la\" "
-                        + logicalAddress);
+    public static void selectDevice(BaseHostJUnit4Test host, ITestDevice device,
+            String logicalAddress) throws DeviceNotAvailableException {
+        Map<String, String> args = new HashMap<>();
+        args.put(LOGICAL_ADDR, logicalAddress);
+        host.runDeviceTests(device, null, TEST_PKG, TEST_CLS, SELECT_DEVICE, null,
+                TEST_TIMEOUT_MS, TEST_TIMEOUT_MS, 0L, true, false, args);
+    }
+
+    /**
+     * Sends a long press keyevent (KEYCODE_UP) followed by a short press of another keyevent
+     * (KEYCODE_DOWN).
+     */
+    public static void sendLongPressKeyevent(BaseHostJUnit4Test host) throws DeviceNotAvailableException {
+        host.runDeviceTests(TEST_PKG, TEST_CLS, SEND_INTERRUPTED_LONG_PRESS);
     }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java
index f95a98c..55606e4 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java
@@ -17,7 +17,6 @@
 package android.hdmicec.cts.common;
 
 import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.hdmicec.cts.BaseHdmiCecCtsTest;
 import android.hdmicec.cts.CecMessage;
@@ -315,17 +314,9 @@
         for (Integer operand : powerControlOperands) {
             try {
                 sendDeviceToSleep();
-                String wakeStateBefore = device.executeShellCommand(
-                        "dumpsys power | grep mWakefulness=");
-                assertThat(wakeStateBefore.trim()).isEqualTo("mWakefulness=Asleep");
-
                 hdmiCecClient.sendUserControlPressAndRelease(source, operand, false);
-
                 TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
-                String wakeStateAfter = device.executeShellCommand(
-                        "dumpsys power | grep mWakefulness=");
-                assertWithMessage("Device should wake up on <User Control Pressed> %s", operand)
-                        .that(wakeStateAfter.trim()).isEqualTo("mWakefulness=Awake");
+                assertDeviceWakefulness(HdmiCecConstants.WAKEFULNESS_AWAKE);
             } finally {
                 wakeUpDevice();
             }
@@ -352,19 +343,10 @@
         for (Integer operand : powerControlOperands) {
             try {
                 wakeUpDevice();
-                String wakeStateBefore = device.executeShellCommand(
-                        "dumpsys power | grep mWakefulness=");
-                assertThat(wakeStateBefore.trim()).isEqualTo("mWakefulness=Awake");
-
                 WakeLockHelper.acquirePartialWakeLock(device);
                 hdmiCecClient.sendUserControlPressAndRelease(source, operand, false);
-
                 TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
-                String wakeStateAfter = device.executeShellCommand(
-                        "dumpsys power | grep mWakefulness=");
-                assertWithMessage("Device should go to standby on <User Control Pressed> %s",
-                        operand)
-                        .that(wakeStateAfter.trim()).isEqualTo("mWakefulness=Asleep");
+                assertDeviceWakefulness(HdmiCecConstants.WAKEFULNESS_ASLEEP);
             } finally {
                 wakeUpDevice();
             }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemAudioControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemAudioControlTest.java
index 0eebc18..132c19f 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemAudioControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemAudioControlTest.java
@@ -153,10 +153,8 @@
     @Test
     public void cect_GiveSystemAudioModeStatus() throws Exception {
         ITestDevice device = getDevice();
-        /* Home Key to prevent device from going to deep suspend state */
-        device.executeShellCommand("input keyevent KEYCODE_HOME");
         sendDeviceToSleep();
-        wakeUpDevice();
+        wakeUpDeviceWithoutWait();
         hdmiCecClient.checkExpectedOutput(
                 hdmiCecClient.getSelfDevice(), CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS);
     }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecDeviceSelectForPlaybackTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecDeviceSelectForPlaybackTest.java
index d46150b..279bc2b 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecDeviceSelectForPlaybackTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecDeviceSelectForPlaybackTest.java
@@ -52,15 +52,6 @@
                                     this, HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE))
                     .around(hdmiCecClient);
 
-    private String setPowerStateChangeOnActiveSourceLost(String valToSet) throws Exception {
-        ITestDevice device = getDevice();
-        String previousPowerStateChange = device.executeShellCommand("cmd hdmi_control cec_setting "
-                + "get power_state_change_on_active_source_lost").split(" = ")[1].trim();
-        device.executeShellCommand("cmd hdmi_control cec_setting "
-                + "set power_state_change_on_active_source_lost " + valToSet);
-        return previousPowerStateChange;
-    }
-
     private int getUnusedPhysicalAddress(int initialValue, int usedValue) {
         if (initialValue == usedValue)
             return 0x2000;
@@ -89,7 +80,8 @@
         // Store previous power state change on active source lost.
         // Set the power state change to none, such that the device won't go to sleep when the
         // active source is changed.
-        String previousPowerStateChange = setPowerStateChangeOnActiveSourceLost("none");
+        String previousPowerStateChange = setPowerStateChangeOnActiveSourceLost(
+                HdmiCecConstants.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE);
         try {
             int dumpsysPhysicalAddress = getDumpsysPhysicalAddress();
             // Add Playback 2 in the network.
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPowerStatusTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPowerStatusTest.java
index 408d719..5b361be 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPowerStatusTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPowerStatusTest.java
@@ -16,9 +16,6 @@
 
 package android.hdmicec.cts.playback;
 
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
 import android.hdmicec.cts.BaseHdmiCecCtsTest;
 import android.hdmicec.cts.CecMessage;
 import android.hdmicec.cts.CecOperand;
@@ -28,16 +25,16 @@
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
 /**
  * HDMI CEC tests verifying power status related messages of the device (CEC 2.0 CTS Section 7.6)
  */
@@ -113,29 +110,15 @@
      */
     @Test
     public void cect_hf4_6_7_setStreamPath_powerOn() throws Exception {
-        ITestDevice device = getDevice();
-
         try {
             sendDeviceToSleep();
-
-            TimeUnit.SECONDS.sleep(HdmiCecConstants.MAX_SLEEP_TIME_SECONDS);
-
-            String wakeStateBefore = device.executeShellCommand(
-                    "dumpsys power | grep mWakefulness=");
-            assertThat(wakeStateBefore.trim()).isEqualTo("mWakefulness=Asleep");
-
             hdmiCecClient.sendCecMessage(
                     LogicalAddress.TV,
                     LogicalAddress.BROADCAST,
                     CecOperand.SET_STREAM_PATH,
                     CecMessage.formatParams(getDumpsysPhysicalAddress(),
                             HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH));
-
-            TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
-            String wakeStateAfter = device.executeShellCommand(
-                    "dumpsys power | grep mWakefulness=");
-            assertWithMessage("Device should wake up on <Set Stream Path>")
-                    .that(wakeStateAfter.trim()).isEqualTo("mWakefulness=Awake");
+            assertDeviceWakefulness(HdmiCecConstants.WAKEFULNESS_AWAKE);
         } finally {
             wakeUpDevice();
         }
@@ -150,7 +133,6 @@
      */
     @Test
     public void cect_hf4_6_16_standby_tvBeforeUcp_20() throws Exception {
-        ITestDevice device = getDevice();
         setCec20();
         String previousPowerControlMode =
                 setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
@@ -176,7 +158,6 @@
      */
     @Test
     public void cect_hf4_6_19_standby_broadcastBeforeUcp_20() throws Exception {
-        ITestDevice device = getDevice();
         setCec20();
         String previousPowerControlMode =
                 setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_BROADCAST);
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java
index cc7d5fd..18fe41f 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java
@@ -16,15 +16,21 @@
 
 package android.hdmicec.cts.playback;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import android.hdmicec.cts.BaseHdmiCecCtsTest;
 import android.hdmicec.cts.CecMessage;
 import android.hdmicec.cts.CecOperand;
 import android.hdmicec.cts.HdmiCecConstants;
+import android.hdmicec.cts.HdmiControlManagerUtility;
 import android.hdmicec.cts.LogicalAddress;
 import android.hdmicec.cts.RemoteControlPassthrough;
 
+import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.RuleChain;
@@ -141,4 +147,102 @@
                 cecKeycode,
                 androidKeycode);
     }
+
+    /**
+     * Test HF4-8-9 (CEC 2.0)
+     *
+     * <p>Tests that the DUT sends multiple {@code <USER_CONTROL_PRESSED>[KEYCODE]} when there is a
+     * long press keyevent.
+     */
+    @Test
+    public void cect_hf4_8_9_SendLongPress() throws Exception {
+        setCec20();
+        String message;
+        int i;
+
+        HdmiControlManagerUtility.sendLongPressKeyevent(this);
+        // The above command should send 5 <UCP>[KEYCODE_UP] messages followed by 1 <UCR> message
+        // and finally, a <UCP>[KEYCODE_DOWN].
+        for (i = 0; i < 5; i++) {
+            message =
+                    hdmiCecClient.checkExpectedOutput(
+                            LogicalAddress.TV, CecOperand.USER_CONTROL_PRESSED);
+            assertThat(CecMessage.getParams(message)).isEqualTo(HdmiCecConstants.CEC_KEYCODE_UP);
+        }
+        message =
+                hdmiCecClient.checkExpectedOutput(
+                        LogicalAddress.TV, CecOperand.USER_CONTROL_RELEASED);
+        message =
+                hdmiCecClient.checkExpectedOutput(
+                        LogicalAddress.TV, CecOperand.USER_CONTROL_PRESSED);
+        assertThat(CecMessage.getParams(message)).isEqualTo(HdmiCecConstants.CEC_KEYCODE_DOWN);
+    }
+
+    /**
+     * Test HF4-8-13 (CEC 2.0)
+     *
+     * <p>Tests that the device responds with a {@code <FEATURE_ABORT>[Not in correct mode]} when it
+     * is not in a mode to action the message.
+     */
+    @Test
+    public void cect_hf4_8_13_AbortIncorrectMode() throws Exception {
+        setCec20();
+        try {
+            sendDeviceToSleep();
+            hdmiCecClient.sendUserControlPressAndRelease(
+                    LogicalAddress.TV, HdmiCecConstants.CEC_KEYCODE_ROOT_MENU, false);
+            String message =
+                    hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.FEATURE_ABORT);
+            int reason = CecMessage.getParams(message) & 0xFF;
+            assertThat(reason).isEqualTo(HdmiCecConstants.ABORT_NOT_IN_CORRECT_MODE);
+        } finally {
+            wakeUpDevice();
+        }
+    }
+
+    /*
+     * Test to check that the DUT sends volume key press events to the TV when system audio mode is
+     * not turned on.
+     */
+    @Test
+    @Ignore("b/218266432")
+    public void cect_sendVolumeKeyPressToTv() throws Exception {
+        ITestDevice device = getDevice();
+        String ucpMessage;
+        String command = "cmd hdmi_control setsam ";
+
+        simulateCecSinkConnected(device, getTargetLogicalAddress());
+
+        boolean wasSystemAudioModeOn = isSystemAudioModeOn(device);
+        if (wasSystemAudioModeOn) {
+            device.executeShellCommand(command + "off");
+            assertWithMessage("System audio mode is not off")
+                    .that(isSystemAudioModeOn(device))
+                    .isFalse();
+        }
+        try {
+            device.executeShellCommand("input keyevent KEYCODE_VOLUME_UP");
+            ucpMessage =
+                    hdmiCecClient.checkExpectedOutput(
+                            LogicalAddress.TV, CecOperand.USER_CONTROL_PRESSED);
+            assertThat(CecMessage.getParams(ucpMessage))
+                    .isEqualTo(HdmiCecConstants.CEC_KEYCODE_VOLUME_UP);
+            device.executeShellCommand("input keyevent KEYCODE_VOLUME_DOWN");
+            ucpMessage =
+                    hdmiCecClient.checkExpectedOutput(
+                            LogicalAddress.TV, CecOperand.USER_CONTROL_PRESSED);
+            assertThat(CecMessage.getParams(ucpMessage))
+                    .isEqualTo(HdmiCecConstants.CEC_KEYCODE_VOLUME_DOWN);
+            device.executeShellCommand("input keyevent KEYCODE_VOLUME_MUTE");
+            ucpMessage =
+                    hdmiCecClient.checkExpectedOutput(
+                            LogicalAddress.TV, CecOperand.USER_CONTROL_PRESSED);
+            assertThat(CecMessage.getParams(ucpMessage))
+                    .isEqualTo(HdmiCecConstants.CEC_KEYCODE_MUTE);
+        } finally {
+            if (wasSystemAudioModeOn) {
+                device.executeShellCommand(command + "on");
+            }
+        }
+    }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java
index e715f91..65da394 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java
@@ -132,7 +132,6 @@
      */
     @Test
     public void cect_11_2_2_4_InactiveSourceOnStandby() throws Exception {
-        ITestDevice device = getDevice();
         String previousPowerControlMode =
                 setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_NONE);
         try {
@@ -143,7 +142,7 @@
                     CecOperand.SET_STREAM_PATH,
                     CecMessage.formatParams(dumpsysPhysicalAddress));
             TimeUnit.SECONDS.sleep(5);
-            sendDeviceToSleep();
+            sendDeviceToSleepWithoutWait();
             String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV,
                     CecOperand.INACTIVE_SOURCE);
             CecMessage.assertPhysicalAddressValid(message, dumpsysPhysicalAddress);
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java
new file mode 100644
index 0000000..718ae56
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.hdmicec.cts.playback;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.hdmicec.cts.BaseHdmiCecCtsTest;
+import android.hdmicec.cts.CecMessage;
+import android.hdmicec.cts.CecOperand;
+import android.hdmicec.cts.HdmiCecConstants;
+import android.hdmicec.cts.LogicalAddress;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Rule;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+
+/** HDMI CEC test verifying system audio control commands (CEC 2.0 CTS Section 7.6) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecSystemAudioControlTest extends BaseHdmiCecCtsTest {
+
+    public HdmiCecSystemAudioControlTest() {
+        super("-t", "a", "-t", "x");
+    }
+
+    @Rule
+    public RuleChain ruleChain =
+            RuleChain.outerRule(CecRules.requiresCec(this))
+                    .around(CecRules.requiresLeanback(this))
+                    .around(
+                            CecRules.requiresDeviceType(
+                                    this, HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE))
+                    .around(hdmiCecClient);
+
+    /**
+     * Test HF4-10-5
+     *
+     * <p>Tests that a device forwards all remote control commands to the device that is providing
+     * the audio rendering.
+     */
+    @Test
+    @Ignore("b/218266432")
+    public void cect_hf4_10_5_RemoteControlCommandsWithSystemAudioControlProperty()
+            throws Exception {
+        setCec20();
+
+        ITestDevice device = getDevice();
+        // Broadcast <Set System Audio Mode> ["off"].
+        broadcastSystemAudioModeMessage(false);
+        // All remote control commands should forward to the TV.
+        sendVolumeUpCommandAndCheckForUcp(LogicalAddress.TV);
+
+        // Broadcast <Set System Audio Mode> ["on"].
+        broadcastSystemAudioModeMessage(true);
+        // All remote control commands should forward to the audio rendering device.
+        sendVolumeUpCommandAndCheckForUcp(LogicalAddress.AUDIO_SYSTEM);
+    }
+
+    private void broadcastSystemAudioModeMessage(boolean val) throws Exception {
+        hdmiCecClient.sendCecMessage(
+                hdmiCecClient.getSelfDevice(),
+                LogicalAddress.BROADCAST,
+                CecOperand.SET_SYSTEM_AUDIO_MODE,
+                CecMessage.formatParams(val ? 1 : 0));
+    }
+
+    private void sendVolumeUpCommandAndCheckForUcp(LogicalAddress toDevice) throws Exception {
+        getDevice().executeShellCommand("input keyevent KEYCODE_VOLUME_UP");
+        String message =
+                hdmiCecClient.checkExpectedOutput(toDevice, CecOperand.USER_CONTROL_PRESSED);
+        assertThat(CecMessage.getParams(message)).isEqualTo(HdmiCecConstants.CEC_KEYCODE_VOLUME_UP);
+        hdmiCecClient.checkExpectedOutput(toDevice, CecOperand.USER_CONTROL_RELEASED);
+    }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecTvPowerToggleTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecTvPowerToggleTest.java
index 7f666e4..125b1e3 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecTvPowerToggleTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecTvPowerToggleTest.java
@@ -16,8 +16,6 @@
 
 package android.hdmicec.cts.playback;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import android.hdmicec.cts.BaseHdmiCecCtsTest;
 import android.hdmicec.cts.CecMessage;
 import android.hdmicec.cts.CecOperand;
@@ -71,13 +69,10 @@
         device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
         String previousPowerControlMode =
                 setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
+        String previousPowerStateChange = setPowerStateChangeOnActiveSourceLost(
+                HdmiCecConstants.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE);
         try {
-            device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 0");
-            device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 1");
-            hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.GIVE_POWER_STATUS);
-            hdmiCecClient.sendCecMessage(LogicalAddress.TV, PLAYBACK_DEVICE,
-                    CecOperand.REPORT_POWER_STATUS, CecMessage.formatParams(OFF));
-            TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
+            simulateCecSinkConnected(device, PLAYBACK_DEVICE);
             hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.BROADCAST,
                     CecOperand.ACTIVE_SOURCE, CecMessage.formatParams("0000"));
             TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
@@ -89,10 +84,10 @@
                     CecOperand.REPORT_POWER_STATUS, CecMessage.formatParams(ON));
             // Verify that device is asleep and <Standby> was sent to TV.
             hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.STANDBY);
-            String wakeState = device.executeShellCommand("dumpsys power | grep mWakefulness=");
-            assertThat(wakeState.trim()).isEqualTo("mWakefulness=Asleep");
+            assertDeviceWakefulness(HdmiCecConstants.WAKEFULNESS_ASLEEP);
         } finally {
             setPowerControlMode(previousPowerControlMode);
+            setPowerStateChangeOnActiveSourceLost(previousPowerStateChange);
             wakeUpDevice();
         }
     }
@@ -109,12 +104,7 @@
         String previousPowerControlMode =
                 setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
         try {
-            device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 0");
-            device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 1");
-            hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.GIVE_POWER_STATUS);
-            hdmiCecClient.sendCecMessage(LogicalAddress.TV, PLAYBACK_DEVICE,
-                    CecOperand.REPORT_POWER_STATUS, CecMessage.formatParams(OFF));
-            TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
+            simulateCecSinkConnected(device, PLAYBACK_DEVICE);
             device.executeShellCommand("input keyevent KEYCODE_HOME");
             TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
             hdmiCecClient.clearClientOutput();
@@ -125,8 +115,7 @@
                     CecOperand.REPORT_POWER_STATUS, CecMessage.formatParams(ON));
             // Verify that device is asleep and <Standby> was sent to TV.
             hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.STANDBY);
-            String wakeState = device.executeShellCommand("dumpsys power | grep mWakefulness=");
-            assertThat(wakeState.trim()).isEqualTo("mWakefulness=Asleep");
+            assertDeviceWakefulness(HdmiCecConstants.WAKEFULNESS_ASLEEP);
         } finally {
             setPowerControlMode(previousPowerControlMode);
             wakeUpDevice();
@@ -145,13 +134,9 @@
         String previousPowerControlMode =
                 setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
         try {
-            device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 0");
-            device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 1");
-            hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.GIVE_POWER_STATUS);
-            hdmiCecClient.sendCecMessage(LogicalAddress.TV, PLAYBACK_DEVICE,
-                    CecOperand.REPORT_POWER_STATUS, CecMessage.formatParams(OFF));
-            TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
+            simulateCecSinkConnected(device, PLAYBACK_DEVICE);
             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);
@@ -159,8 +144,7 @@
                     CecOperand.REPORT_POWER_STATUS, CecMessage.formatParams(ON));
             // Verify that device is asleep and <Standby> was sent to TV.
             hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.STANDBY);
-            String wakeState = device.executeShellCommand("dumpsys power | grep mWakefulness=");
-            assertThat(wakeState.trim()).isEqualTo("mWakefulness=Asleep");
+            assertDeviceWakefulness(HdmiCecConstants.WAKEFULNESS_ASLEEP);
         } finally {
             setPowerControlMode(previousPowerControlMode);
             wakeUpDevice();
@@ -179,13 +163,9 @@
         String previousPowerControlMode =
                 setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
         try {
-            device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 0");
-            device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 1");
-            hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.GIVE_POWER_STATUS);
-            hdmiCecClient.sendCecMessage(LogicalAddress.TV, PLAYBACK_DEVICE,
-                    CecOperand.REPORT_POWER_STATUS, CecMessage.formatParams(OFF));
-            TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
+            simulateCecSinkConnected(device, PLAYBACK_DEVICE);
             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);
@@ -194,8 +174,7 @@
             // Verify that device is awake and <Text View On> and <Active Source> were sent.
             hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.TEXT_VIEW_ON);
             hdmiCecClient.checkExpectedOutput(LogicalAddress.BROADCAST, CecOperand.ACTIVE_SOURCE);
-            String wakeState = device.executeShellCommand("dumpsys power | grep mWakefulness=");
-            assertThat(wakeState.trim()).isEqualTo("mWakefulness=Awake");
+            assertDeviceWakefulness(HdmiCecConstants.WAKEFULNESS_AWAKE);
         } finally {
             setPowerControlMode(previousPowerControlMode);
             wakeUpDevice();
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRemoteControlPassThroughTest.java
index ff2ff00..605ecee 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRemoteControlPassThroughTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRemoteControlPassThroughTest.java
@@ -46,7 +46,7 @@
 @RunWith(DeviceJUnit4ClassRunner.class)
 public final class HdmiCecRemoteControlPassThroughTest extends BaseHdmiCecCtsTest {
 
-    private static final int WAIT_TIME_MS = 300;
+    private static final int WAIT_TIME_MS = 1000;
 
     private HashMap<String, Integer> remoteControlKeys = new HashMap<String, Integer>();
     private HashMap<String, Integer> remoteControlAudioKeys = new HashMap<String, Integer>();
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRoutingControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRoutingControlTest.java
index 1775f5e..75d006a 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRoutingControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRoutingControlTest.java
@@ -41,7 +41,7 @@
 @RunWith(DeviceJUnit4ClassRunner.class)
 public final class HdmiCecRoutingControlTest extends BaseHdmiCecCtsTest {
 
-    private static final int WAIT_TIME_MS = 300;
+    private static final int WAIT_TIME_MS = 1000;
 
     @Rule
     public RuleChain ruleChain =
@@ -98,8 +98,8 @@
         hdmiCecClient.broadcastReportPhysicalAddress(LogicalAddress.PLAYBACK_1, 0x2200);
         TimeUnit.SECONDS.sleep(2);
         // Make the device with LA 4 as the active source.
-        HdmiControlManagerUtility.setActiveSource(
-                getDevice(), LogicalAddress.PLAYBACK_1.getLogicalAddressAsInt());
+        HdmiControlManagerUtility.selectDevice(
+                this, getDevice(), LogicalAddress.PLAYBACK_1.toString());
         String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_STREAM_PATH);
         assertWithMessage("Device has not sent a Set Stream Path message to the selected device")
                 .that(CecMessage.getParams(message))
@@ -115,8 +115,7 @@
     @Test
     public void cect_11_1_2_2_DutDoesNotRespondToRequestActiveSourceMessage() throws Exception {
         // Ensure that DUT is the active source.
-        HdmiControlManagerUtility.setActiveSource(
-                getDevice(), LogicalAddress.TV.getLogicalAddressAsInt());
+        HdmiControlManagerUtility.selectDevice(this, getDevice(), LogicalAddress.TV.toString());
         hdmiCecClient.checkExpectedOutput(CecOperand.ACTIVE_SOURCE);
         // Broadcast an active source from the client device.
         hdmiCecClient.broadcastActiveSource(hdmiCecClient.getSelfDevice());
@@ -137,8 +136,7 @@
     @Test
     public void cect_11_1_2_3_DutDoesRespondToRequestActiveSourceMessage() throws Exception {
         // Make the TV device the active source.
-        HdmiControlManagerUtility.setActiveSource(
-                getDevice(), LogicalAddress.TV.getLogicalAddressAsInt());
+        HdmiControlManagerUtility.selectDevice(this, getDevice(), LogicalAddress.TV.toString());
         hdmiCecClient.sendCecMessage(
                 hdmiCecClient.getSelfDevice(),
                 LogicalAddress.BROADCAST,
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvOneTouchPlayTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvOneTouchPlayTest.java
index 4aba289..7ee413a 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvOneTouchPlayTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvOneTouchPlayTest.java
@@ -40,7 +40,7 @@
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class HdmiCecTvOneTouchPlayTest extends BaseHdmiCecCtsTest {
 
-    private static final int WAIT_TIME_MS = 300;
+    private static final int WAIT_TIME_MS = 1000;
 
     private static final int SLEEP_TIMESTEP_SECONDS = 1;
     private static final int POWER_TRANSITION_WAIT_TIME = 10;
@@ -131,8 +131,7 @@
             TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS);
         }
         // Make the TV device the active source.
-        HdmiControlManagerUtility.setActiveSource(
-                getDevice(), LogicalAddress.TV.getLogicalAddressAsInt());
+        HdmiControlManagerUtility.selectDevice(this, getDevice(), LogicalAddress.TV.toString());
         hdmiCecClient.checkExpectedOutput(LogicalAddress.BROADCAST, CecOperand.ACTIVE_SOURCE);
     }
 
@@ -209,4 +208,3 @@
                 .isEqualTo(powerStatus);
     }
 }
-
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvStandbyTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvStandbyTest.java
index 4efab29..d3b6d1d 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvStandbyTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvStandbyTest.java
@@ -64,10 +64,6 @@
         try {
             sendDeviceToSleep();
             hdmiCecClient.checkExpectedOutput(LogicalAddress.BROADCAST, CecOperand.STANDBY);
-            String wakeState = device.executeShellCommand("dumpsys power | grep mWakefulness=");
-            assertWithMessage("Device is not in standby.")
-                    .that(wakeState.trim())
-                    .isEqualTo("mWakefulness=Asleep");
         } finally {
             wakeUpDevice();
             setHdmiControlDeviceAutoOff(wasOn);
diff --git a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/ShellCommandUtils.java b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/ShellCommandUtils.java
index afaa9c8..6423aff 100644
--- a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/ShellCommandUtils.java
+++ b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/ShellCommandUtils.java
@@ -29,6 +29,8 @@
     // Copied from android.content.pm.PackageManager#FEATURE_INPUT_METHODS.
     public static final String FEATURE_INPUT_METHODS = "android.software.input_methods";
 
+    public static final String FEATURE_TV_OPERATOR_TIER = "com.google.android.tv.operator_tier";
+
     private static final String SETTING_DEFAULT_IME = "secure default_input_method";
 
     /** Command to get ID of current IME. */
diff --git a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java
index 4064ff5..bd6e4e3 100644
--- a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java
+++ b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java
@@ -24,6 +24,7 @@
 import static android.inputmethodservice.cts.common.DeviceEventConstants.RECEIVER_COMPONENT;
 
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
 import android.inputmethodservice.cts.common.ComponentNameUtils;
@@ -460,6 +461,8 @@
 
     private void testImeSwitchingWithoutWindowFocusAfterDisplayOffOn(boolean instant)
             throws Exception {
+        // Skip whole tests when DUT has com.google.android.tv.operator_tier feature.
+        assumeFalse(hasDeviceFeature(ShellCommandUtils.FEATURE_TV_OPERATOR_TIER));
         sendTestStartEvent(
                 DeviceTestConstants.TEST_IME_SWITCHING_WITHOUT_WINDOW_FOCUS_AFTER_DISPLAY_OFF_ON);
         installPossibleInstantPackage(
diff --git a/hostsidetests/jvmti/redefining/app/src/android/jvmti/cts/JvmtiRedefineClassesTest.java b/hostsidetests/jvmti/redefining/app/src/android/jvmti/cts/JvmtiRedefineClassesTest.java
index d68d1ddc..0e101d9 100644
--- a/hostsidetests/jvmti/redefining/app/src/android/jvmti/cts/JvmtiRedefineClassesTest.java
+++ b/hostsidetests/jvmti/redefining/app/src/android/jvmti/cts/JvmtiRedefineClassesTest.java
@@ -742,7 +742,7 @@
 
     @Test
     public void testCannotRetransformOnLoadTest() throws Exception {
-        // Just a sanity check along with below.
+        // Just a confidence check along with below.
         Class<?> target_class = new InMemoryDexClassLoader(
                 ByteBuffer.wrap(ONLOAD_INITIAL_CLASS),
                 getClass().getClassLoader()).loadClass(ONLOAD_TEST_CLASS_NAME);
diff --git a/hostsidetests/multiuser/OWNERS b/hostsidetests/multiuser/OWNERS
index 2b344eb..cbd8eb1 100644
--- a/hostsidetests/multiuser/OWNERS
+++ b/hostsidetests/multiuser/OWNERS
@@ -1,4 +1,3 @@
 # Bug component: 71510
 include /tests/app/OWNERS
-
-bookatz@google.com
+include platform/frameworks/base:/MULTIUSER_OWNERS
diff --git a/hostsidetests/sample/AndroidTest.xml b/hostsidetests/sample/AndroidTest.xml
index 80189da..2878a31 100644
--- a/hostsidetests/sample/AndroidTest.xml
+++ b/hostsidetests/sample/AndroidTest.xml
@@ -15,6 +15,8 @@
 -->
 <configuration description="Config for CTS Sample host test cases">
     <option name="test-suite-tag" value="cts" />
+    <!-- Change the value field of `component` into an appropriate one.
+         See README for the full list. -->
     <option name="config-descriptor:metadata" key="component" value="misc" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
diff --git a/hostsidetests/sample/README b/hostsidetests/sample/README
new file mode 100644
index 0000000..71dbbce
--- /dev/null
+++ b/hostsidetests/sample/README
@@ -0,0 +1,4 @@
+This 'sample' folder is a sample which illustrates the basic structure and contents of a CTS
+hostside module.
+
+Please refer to 'cts/tests/sample/README' for more details on how to use this sample.
\ No newline at end of file
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 0ba69f5..17aab09 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
@@ -32,7 +32,7 @@
 
     private void startOverlayService() {
         if (Settings.canDrawOverlays(this)) {
-            Intent intent = new Intent(PocActivity.this, PocService.class);
+            Intent intent = new Intent(PocActivity.this, PocService.class);
             startService(intent);
         } else {
             try {
@@ -45,7 +45,7 @@
     }
 
     private void stopOverlayService() {
-        Intent intent = new Intent(PocActivity.this, PocService.class);
+        Intent intent = new Intent(PocActivity.this, PocService.class);
         stopService(intent);
     }
 
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/PocActivity.java
index 11fd02c..b654e0c 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0586/src/android/security/cts/CVE_2021_0586/PocActivity.java
@@ -25,7 +25,7 @@
 
     private void startOverlayService() {
         if (Settings.canDrawOverlays(this)) {
-            Intent intent = new Intent(PocActivity.this, PocService.class);
+            Intent intent = new Intent(PocActivity.this, PocService.class);
             startService(intent);
         } else {
             try {
@@ -38,7 +38,7 @@
     }
 
     private void stopOverlayService() {
-        Intent intent = new Intent(PocActivity.this, PocService.class);
+        Intent intent = new Intent(PocActivity.this, PocService.class);
         stopService(intent);
     }
 
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/perfetto/PerfettoTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/perfetto/PerfettoTests.java
index 22b2b49..6b2f95f 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/perfetto/PerfettoTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/perfetto/PerfettoTests.java
@@ -36,6 +36,7 @@
 import com.android.os.AtomsProto.Atom;
 import com.android.os.AtomsProto.PerfettoTrigger;
 import com.android.os.AtomsProto.PerfettoUploaded;
+import com.android.os.AtomsProto.TracingServiceReportEvent;
 import com.android.os.StatsLog.EventMetricData;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -45,17 +46,18 @@
 
 import com.google.protobuf.ByteString;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+
 import perfetto.protos.PerfettoConfig.DataSourceConfig;
 import perfetto.protos.PerfettoConfig.FtraceConfig;
 import perfetto.protos.PerfettoConfig.TraceConfig;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
 public class PerfettoTests extends DeviceTestCase implements IBuildReceiver {
 
-    private static final int WAIT_AFTER_START_PERFETTO_MS = 2000;
+    private static final int WAIT_AFTER_START_PERFETTO_MS = 3000;
 
     // Config constants
     // These were chosen to match the statsd <-> Perfetto CTS integration
@@ -84,11 +86,11 @@
     public void setBuild(IBuildInfo buildInfo) {
     }
 
-    public void testPerfettoUploadedAtoms() throws Exception {
+    public void testPerfettoUploadedIncidentdAtoms() throws Exception {
         if (DeviceUtils.hasFeature(getDevice(), DeviceUtils.FEATURE_WATCH)) return;
         resetPerfettoGuardrails();
 
-        StatsdConfig.Builder config = getStatsdConfig();
+        StatsdConfig.Builder config = getStatsdConfig(getPerfettoIncidentConfig());
         ConfigUtils.addEventMetric(config, AtomsProto.Atom.PERFETTO_UPLOADED_FIELD_NUMBER);
         ConfigUtils.uploadConfig(getDevice(), config);
 
@@ -106,6 +108,49 @@
                         PerfettoUploaded.Event.PERFETTO_TRACED_START_TRACING);
     }
 
+    public void testSkipReportAtoms() throws Exception {
+        if (DeviceUtils.hasFeature(getDevice(), DeviceUtils.FEATURE_WATCH)) return;
+        resetPerfettoGuardrails();
+
+        StatsdConfig.Builder config = getStatsdConfig(getPerfettoReportConfig(true));
+        ConfigUtils.addEventMetric(config, AtomsProto.Atom.PERFETTO_UPLOADED_FIELD_NUMBER);
+        ConfigUtils.uploadConfig(getDevice(), config);
+
+        startPerfettoTrace();
+        Thread.sleep(WAIT_AFTER_START_PERFETTO_MS);
+
+        List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
+        assertThat(extractPerfettoUploadedEvents(data))
+                .containsAtLeast(
+                        PerfettoUploaded.Event.PERFETTO_TRACE_BEGIN,
+                        PerfettoUploaded.Event.PERFETTO_ON_CONNECT,
+                        PerfettoUploaded.Event.PERFETTO_TRACED_ENABLE_TRACING,
+                        PerfettoUploaded.Event.PERFETTO_TRACED_START_TRACING);
+    }
+
+    public void testReportAtoms() throws Exception {
+        if (DeviceUtils.hasFeature(getDevice(), DeviceUtils.FEATURE_WATCH)) return;
+        resetPerfettoGuardrails();
+
+        StatsdConfig.Builder config = getStatsdConfig(getPerfettoReportConfig(false));
+        ConfigUtils.addEventMetric(config, AtomsProto.Atom.PERFETTO_UPLOADED_FIELD_NUMBER);
+        ConfigUtils.addEventMetric(config, Atom.TRACING_SERVICE_REPORT_EVENT_FIELD_NUMBER);
+        ConfigUtils.uploadConfig(getDevice(), config);
+
+        startPerfettoTrace();
+        Thread.sleep(WAIT_AFTER_START_PERFETTO_MS);
+
+        List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
+        assertThat(extractPerfettoUploadedEvents(data))
+                .containsAtLeast(
+                        PerfettoUploaded.Event.PERFETTO_CMD_FW_REPORT_BEGIN,
+                        PerfettoUploaded.Event.PERFETTO_CMD_FW_REPORT_HANDOFF);
+        assertThat(extractReportEvents(data))
+                .containsExactly(
+                        TracingServiceReportEvent.Event.TRACING_SERVICE_REPORT_BEGIN,
+                        TracingServiceReportEvent.Event.TRACING_SERVICE_REPORT_BIND_PERM_INCORRECT);
+    }
+
     public void testPerfettoTriggerAtoms() throws Exception {
         if (DeviceUtils.hasFeature(getDevice(), DeviceUtils.FEATURE_WATCH)) return;
 
@@ -123,11 +168,31 @@
                         PerfettoTrigger.Event.PERFETTO_TRIGGER_PERFETTO_TRIGGER);
     }
 
-    /**
-     * Returns a protobuf-encoded perfetto config that enables the kernel ftrace tracer with
-     * sched_switch for 10 seconds.
-     */
-    private ByteString getPerfettoConfig() {
+    private ByteString getPerfettoIncidentConfig() {
+        TraceConfig.IncidentReportConfig incident =
+                TraceConfig.IncidentReportConfig.newBuilder()
+                        .setSkipIncidentd(true)
+                        .build();
+        return getBasePerfettoConfigBuilder()
+                .setIncidentReportConfig(incident)
+                .build()
+                .toByteString();
+    }
+
+    private ByteString getPerfettoReportConfig(boolean skipReport) {
+        TraceConfig.AndroidReportConfig config = TraceConfig.AndroidReportConfig.newBuilder()
+                .setSkipReport(skipReport)
+                .setReporterServicePackage("android.cts")
+                .setReporterServiceClass("android.cts.class")
+                .setUsePipeInFrameworkForTesting(true)
+                .build();
+        return getBasePerfettoConfigBuilder()
+                .setAndroidReportConfig(config)
+                .build()
+                .toByteString();
+    }
+
+    private TraceConfig.Builder getBasePerfettoConfigBuilder() {
         TraceConfig.Builder builder = TraceConfig.newBuilder();
 
         TraceConfig.BufferConfig buffer =
@@ -146,15 +211,9 @@
                 TraceConfig.DataSource.newBuilder().setConfig(dataSourceConfig).build();
         builder.addDataSources(dataSource);
 
-        builder.setDurationMs(3000);
+        builder.setDurationMs(500);
         builder.setAllowUserBuildTracing(true);
 
-        TraceConfig.IncidentReportConfig incident =
-                TraceConfig.IncidentReportConfig.newBuilder()
-                        .setSkipIncidentd(true)
-                        .build();
-        builder.setIncidentReportConfig(incident);
-
         // To avoid being hit with guardrails firing in multiple test runs back
         // to back, we set a unique session key for each config.
         Random random = new Random();
@@ -162,14 +221,16 @@
         sessionNameBuilder.append(random.nextInt() & Integer.MAX_VALUE);
         builder.setUniqueSessionName(sessionNameBuilder.toString());
 
-        return builder.build().toByteString();
+        return builder;
     }
 
     private List<PerfettoUploaded.Event> extractPerfettoUploadedEvents(
             List<EventMetricData> input) {
         List<PerfettoUploaded.Event> output = new ArrayList<>();
         for (EventMetricData data : input) {
-            output.add(data.getAtom().getPerfettoUploaded().getEvent());
+            if (data.getAtom().hasPerfettoUploaded()) {
+                output.add(data.getAtom().getPerfettoUploaded().getEvent());
+            }
         }
         return output;
     }
@@ -178,7 +239,20 @@
             List<EventMetricData> input) {
         List<PerfettoTrigger.Event> output = new ArrayList<>();
         for (EventMetricData data : input) {
-            output.add(data.getAtom().getPerfettoTrigger().getEvent());
+            if (data.getAtom().hasPerfettoTrigger()) {
+                output.add(data.getAtom().getPerfettoTrigger().getEvent());
+            }
+        }
+        return output;
+    }
+
+    private List<TracingServiceReportEvent.Event> extractReportEvents(
+            List<EventMetricData> input) {
+        List<TracingServiceReportEvent.Event> output = new ArrayList<>();
+        for (EventMetricData data : input) {
+            if (data.getAtom().hasTracingServiceReportEvent()) {
+                output.add(data.getAtom().getTracingServiceReportEvent().getEvent());
+            }
         }
         return output;
     }
@@ -190,11 +264,12 @@
     private void runTriggerPerfetto() throws Exception {
         final String cmd = "trigger_perfetto cts.test.trigger";
         CommandResult cr = getDevice().executeShellV2Command(cmd);
-        if (cr.getStatus() != CommandStatus.SUCCESS)
+        if (cr.getStatus() != CommandStatus.SUCCESS) {
             throw new Exception(
                     String.format(
                             "Error while executing %s: %s %s",
                             cmd, cr.getStdout(), cr.getStderr()));
+        }
     }
 
     /**
@@ -204,11 +279,12 @@
     private void resetPerfettoGuardrails() throws Exception {
         final String cmd = "perfetto --reset-guardrails";
         CommandResult cr = getDevice().executeShellV2Command(cmd);
-        if (cr.getStatus() != CommandStatus.SUCCESS)
+        if (cr.getStatus() != CommandStatus.SUCCESS) {
             throw new Exception(
                     String.format(
                             "Error while executing %s: %s %s",
                             cmd, cr.getStdout(), cr.getStderr()));
+        }
     }
 
     private void startPerfettoTrace() throws Exception {
@@ -219,7 +295,7 @@
                                 1, AppBreadcrumbReported.State.START.ordinal()));
     }
 
-    private final StatsdConfig.Builder getStatsdConfig() throws Exception {
+    private final StatsdConfig.Builder getStatsdConfig(ByteString config) throws Exception {
         return ConfigUtils.createConfigBuilder("AID_NOBODY")
                 .addSubscription(
                         Subscription.newBuilder()
@@ -228,7 +304,7 @@
                                 .setRuleId(ALERT_ID)
                                 .setPerfettoDetails(
                                         PerfettoDetails.newBuilder()
-                                                .setTraceConfig(getPerfettoConfig())))
+                                                .setTraceConfig(config)))
                 .addValueMetric(
                         ValueMetric.newBuilder()
                                 .setId(METRIC_ID)
diff --git a/libs/json/fuzzers/Android.bp b/libs/json/fuzzers/Android.bp
index 6434e9a..d6f7f0d 100644
--- a/libs/json/fuzzers/Android.bp
+++ b/libs/json/fuzzers/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 java_fuzz_host {
     name: "json-reader-fuzzer",
     srcs: [
@@ -21,4 +25,4 @@
         "jazzer",
         "jsonlib",
     ],
-}
\ No newline at end of file
+}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
index 9b7951f..1c17037 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
@@ -19,22 +19,28 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
 import android.accessibility.cts.common.InstrumentedAccessibilityServiceTestRule;
 import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.UiAutomation;
 import android.content.Context;
 import android.os.Message;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
+import android.text.SpannableString;
 import android.text.TextUtils;
+import android.text.style.LocaleSpan;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityRecord;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
@@ -49,45 +55,59 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
-/**
- * Class for testing {@link AccessibilityEvent}.
- */
+/** Class for testing {@link AccessibilityEvent}. */
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class AccessibilityEventTest {
+    private static final long IDLE_TIMEOUT_MS = 500;
+    private static final long DEFAULT_TIMEOUT_MS = 1000;
+
+    // From ViewConfiguration.SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS
+    private static final long SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS = 100;
 
     private EventReportingLinearLayout mParentView;
     private View mChildView;
-    private AccessibilityManager mAccessibilityManager;
+    private TextView mTextView;
+    private String mPackageName;
 
+    private static Instrumentation sInstrumentation;
+    private static UiAutomation sUiAutomation;
     private final ActivityTestRule<DummyActivity> mActivityRule =
             new ActivityTestRule<>(DummyActivity.class, false, false);
     private final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
             new AccessibilityDumpOnFailureRule();
     private InstrumentedAccessibilityServiceTestRule<SpeakingAccessibilityService>
-            mInstrumentedAccessibilityServiceRule = new InstrumentedAccessibilityServiceTestRule<>(
-            SpeakingAccessibilityService.class, false);
+            mInstrumentedAccessibilityServiceRule =
+                    new InstrumentedAccessibilityServiceTestRule<>(
+                            SpeakingAccessibilityService.class, false);
 
     @Rule
-    public final RuleChain mRuleChain = RuleChain
-            .outerRule(mActivityRule)
-            .around(mInstrumentedAccessibilityServiceRule)
-            .around(mDumpOnFailureRule);
+    public final RuleChain mRuleChain =
+            RuleChain.outerRule(mActivityRule)
+                    .around(mInstrumentedAccessibilityServiceRule)
+                    .around(mDumpOnFailureRule);
 
     @Before
     public void setUp() throws Throwable {
         final Activity activity = mActivityRule.launchActivity(null);
-        mAccessibilityManager = activity.getSystemService(AccessibilityManager.class);
+        mPackageName = activity.getApplicationContext().getPackageName();
+        sInstrumentation = InstrumentationRegistry.getInstrumentation();
+        sUiAutomation = sInstrumentation.getUiAutomation();
         mInstrumentedAccessibilityServiceRule.enableService();
-        mActivityRule.runOnUiThread(() -> {
-            final LinearLayout grandparent = new LinearLayout(activity);
-            activity.setContentView(grandparent);
-            mParentView = new EventReportingLinearLayout(activity);
-            mChildView = new View(activity);
-            grandparent.addView(mParentView);
-            mParentView.addView(mChildView);
-        });
+        mActivityRule.runOnUiThread(
+                () -> {
+                    final LinearLayout grandparent = new LinearLayout(activity);
+                    activity.setContentView(grandparent);
+                    mParentView = new EventReportingLinearLayout(activity);
+                    mChildView = new View(activity);
+                    mTextView = new TextView(activity);
+                    grandparent.addView(mParentView);
+                    mParentView.addView(mChildView);
+                    mParentView.addView(mTextView);
+                });
+        sUiAutomation.waitForIdle(IDLE_TIMEOUT_MS, DEFAULT_TIMEOUT_MS);
     }
 
     private static class EventReportingLinearLayout extends LinearLayout {
@@ -106,52 +126,66 @@
 
     @Test
     public void testScrollEvent() throws Exception {
-        mChildView.scrollTo(0, 100);
-        Thread.sleep(1000);
-        scrollEventFilter.assertReceivedEventCount(1);
+        sUiAutomation.executeAndWaitForEvent(
+                () -> mChildView.scrollTo(0, 100), new ScrollEventFilter(1), DEFAULT_TIMEOUT_MS);
     }
 
     @Test
     public void testScrollEventBurstCombined() throws Exception {
-        mChildView.scrollTo(0, 100);
-        mChildView.scrollTo(0, 125);
-        mChildView.scrollTo(0, 150);
-        mChildView.scrollTo(0, 175);
-        Thread.sleep(1000);
-        scrollEventFilter.assertReceivedEventCount(1);
+        sUiAutomation.executeAndWaitForEvent(
+                () -> {
+                    mChildView.scrollTo(0, 100);
+                    mChildView.scrollTo(0, 125);
+                    mChildView.scrollTo(0, 150);
+                    mChildView.scrollTo(0, 175);
+                },
+                new ScrollEventFilter(1),
+                DEFAULT_TIMEOUT_MS);
     }
 
     @Test
     public void testScrollEventsDeliveredInCorrectInterval() throws Exception {
-        mChildView.scrollTo(0, 25);
-        mChildView.scrollTo(0, 50);
-        mChildView.scrollTo(0, 100);
-        Thread.sleep(150);
-        mChildView.scrollTo(0, 150);
-        mChildView.scrollTo(0, 175);
-        Thread.sleep(50);
-        mChildView.scrollTo(0, 200);
-        Thread.sleep(1000);
-        scrollEventFilter.assertReceivedEventCount(2);
+        sUiAutomation.executeAndWaitForEvent(
+                () -> {
+                    try {
+                        mChildView.scrollTo(0, 25);
+                        mChildView.scrollTo(0, 50);
+                        mChildView.scrollTo(0, 100);
+                        Thread.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS * 2);
+                        mChildView.scrollTo(0, 150);
+                        mChildView.scrollTo(0, 175);
+                        Thread.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS / 2);
+                        mChildView.scrollTo(0, 200);
+                    } catch (InterruptedException e) {
+                        fail("Interrupted while dispatching event bursts.");
+                    }
+                },
+                new ScrollEventFilter(2),
+                DEFAULT_TIMEOUT_MS);
     }
 
-    private AccessibilityEventFilter scrollEventFilter = new AccessibilityEventFilter() {
-        public boolean pass(AccessibilityEvent event) {
-            return event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED;
-        }
-    };
-
     @Test
     public void testScrollEventsClearedOnDetach() throws Throwable {
-        mChildView.scrollTo(0, 25);
-        mChildView.scrollTo(5, 50);
-        mChildView.scrollTo(7, 100);
-        mActivityRule.runOnUiThread(() -> {
-            mParentView.removeView(mChildView);
-            mParentView.addView(mChildView);
-        });
-        mChildView.scrollTo(0, 150);
-        Thread.sleep(1000);
+        ScrollEventFilter scrollEventFilter = new ScrollEventFilter(1);
+        sUiAutomation.executeAndWaitForEvent(
+                () -> {
+                    mChildView.scrollTo(0, 25);
+                    mChildView.scrollTo(5, 50);
+                    mChildView.scrollTo(7, 100);
+                },
+                scrollEventFilter,
+                DEFAULT_TIMEOUT_MS);
+        mActivityRule.runOnUiThread(
+                () -> {
+                    mParentView.removeView(mChildView);
+                    mParentView.addView(mChildView);
+                });
+        sUiAutomation.executeAndWaitForEvent(
+                () -> {
+                    mChildView.scrollTo(0, 150);
+                },
+                scrollEventFilter,
+                DEFAULT_TIMEOUT_MS);
         AccessibilityEvent event = scrollEventFilter.getLastEvent();
         assertEquals(-7, event.getScrollDeltaX());
         assertEquals(50, event.getScrollDeltaY());
@@ -159,10 +193,15 @@
 
     @Test
     public void testScrollEventsCaptureTotalDelta() throws Throwable {
-        mChildView.scrollTo(0, 25);
-        mChildView.scrollTo(5, 50);
-        mChildView.scrollTo(7, 100);
-        Thread.sleep(1000);
+        ScrollEventFilter scrollEventFilter = new ScrollEventFilter(1);
+        sUiAutomation.executeAndWaitForEvent(
+                () -> {
+                    mChildView.scrollTo(0, 25);
+                    mChildView.scrollTo(5, 50);
+                    mChildView.scrollTo(7, 100);
+                },
+                scrollEventFilter,
+                DEFAULT_TIMEOUT_MS);
         AccessibilityEvent event = scrollEventFilter.getLastEvent();
         assertEquals(7, event.getScrollDeltaX());
         assertEquals(100, event.getScrollDeltaY());
@@ -170,12 +209,24 @@
 
     @Test
     public void testScrollEventsClearDeltaAfterSending() throws Throwable {
-        mChildView.scrollTo(0, 25);
-        mChildView.scrollTo(5, 50);
-        mChildView.scrollTo(7, 100);
-        Thread.sleep(1000);
-        mChildView.scrollTo(0, 150);
-        Thread.sleep(1000);
+        ScrollEventFilter scrollEventFilter = new ScrollEventFilter(2);
+        sUiAutomation.executeAndWaitForEvent(
+                () -> {
+                    try {
+                        mChildView.scrollTo(0, 25);
+                        mChildView.scrollTo(5, 50);
+                        mChildView.scrollTo(7, 100);
+                        Thread.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS * 2);
+                        mChildView.scrollTo(0, 25);
+                        mChildView.scrollTo(5, 50);
+                        mChildView.scrollTo(7, 100);
+                        mChildView.scrollTo(0, 150);
+                    } catch (InterruptedException e) {
+                        fail("Interrupted while dispatching event bursts.");
+                    }
+                },
+                scrollEventFilter,
+                DEFAULT_TIMEOUT_MS);
         AccessibilityEvent event = scrollEventFilter.getLastEvent();
         assertEquals(-7, event.getScrollDeltaX());
         assertEquals(50, event.getScrollDeltaY());
@@ -183,94 +234,132 @@
 
     @Test
     public void testStateEvent() throws Throwable {
-        sendStateDescriptionChangedEvent(mChildView);
-        Thread.sleep(1000);
-        stateDescriptionEventFilter.assertReceivedEventCount(1);
+        sUiAutomation.executeAndWaitForEvent(
+                () -> {
+                    sendStateDescriptionChangedEvent(mChildView);
+                },
+                new StateDescriptionEventFilter(1),
+                DEFAULT_TIMEOUT_MS);
     }
 
     @Test
     public void testStateEventBurstCombined() throws Throwable {
-        sendStateDescriptionChangedEvent(mChildView);
-        sendStateDescriptionChangedEvent(mChildView);
-        sendStateDescriptionChangedEvent(mChildView);
-        sendStateDescriptionChangedEvent(mChildView);
-        Thread.sleep(1000);
-        stateDescriptionEventFilter.assertReceivedEventCount(1);
+        sUiAutomation.executeAndWaitForEvent(
+                () -> {
+                    sendStateDescriptionChangedEvent(mChildView);
+                    sendStateDescriptionChangedEvent(mChildView);
+                    sendStateDescriptionChangedEvent(mChildView);
+                    sendStateDescriptionChangedEvent(mChildView);
+                },
+                new StateDescriptionEventFilter(1),
+                DEFAULT_TIMEOUT_MS);
     }
 
     @Test
     public void testStateEventsDeliveredInCorrectInterval() throws Throwable {
-        sendStateDescriptionChangedEvent(mChildView);
-        sendStateDescriptionChangedEvent(mChildView);
-        sendStateDescriptionChangedEvent(mChildView);
-        Thread.sleep(150);
-        sendStateDescriptionChangedEvent(mChildView);
-        sendStateDescriptionChangedEvent(mChildView);
-        Thread.sleep(50);
-        sendStateDescriptionChangedEvent(mChildView);
-        Thread.sleep(1000);
-        stateDescriptionEventFilter.assertReceivedEventCount(2);
+        sUiAutomation.executeAndWaitForEvent(
+                () -> {
+                    try {
+                        sendStateDescriptionChangedEvent(mChildView);
+                        sendStateDescriptionChangedEvent(mChildView);
+                        sendStateDescriptionChangedEvent(mChildView);
+                        Thread.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS * 2);
+                        sendStateDescriptionChangedEvent(mChildView);
+                        sendStateDescriptionChangedEvent(mChildView);
+                        Thread.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS / 2);
+                        sendStateDescriptionChangedEvent(mChildView);
+                    } catch (InterruptedException e) {
+                        fail("Interrupted while dispatching event bursts.");
+                    }
+                },
+                new StateDescriptionEventFilter(2),
+                DEFAULT_TIMEOUT_MS);
     }
 
     @Test
     public void testStateEventsHaveLastEventText() throws Throwable {
-        sendStateDescriptionChangedEvent(mChildView, "First state");
+        StateDescriptionEventFilter stateDescriptionEventFilter =
+                new StateDescriptionEventFilter(1);
         String expectedState = "Second state";
-        sendStateDescriptionChangedEvent(mChildView, expectedState);
-        Thread.sleep(1000);
+        sUiAutomation.executeAndWaitForEvent(
+                () -> {
+                    sendStateDescriptionChangedEvent(mChildView, "First state");
+                    sendStateDescriptionChangedEvent(mChildView, expectedState);
+                },
+                stateDescriptionEventFilter,
+                DEFAULT_TIMEOUT_MS);
         AccessibilityEvent event = stateDescriptionEventFilter.getLastEvent();
         assertEquals(expectedState, event.getText().get(0));
     }
 
-    private AccessibilityEventFilter stateDescriptionEventFilter = new AccessibilityEventFilter() {
-        public boolean pass(AccessibilityEvent event) {
-            return event.getContentChangeTypes()
-                    == AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION;
-        }
-    };
-
-    private abstract class AccessibilityEventFilter {
-        abstract boolean pass(AccessibilityEvent event);
-
-        void assertReceivedEventCount(int count) {
-            assertEquals(count, filteredEventsReceived().size());
-        }
-
-        AccessibilityEvent getLastEvent() {
-            List<AccessibilityEvent> events = filteredEventsReceived();
-            if (events.size() > 0) {
-                return events.get(events.size() - 1);
-            }
-            return null;
-        }
-
-        private List<AccessibilityEvent> filteredEventsReceived() {
-            List<AccessibilityEvent> filteredEvents = new ArrayList<AccessibilityEvent>();
-            List<AccessibilityEvent> receivedEvents = mParentView.mReceivedEvents;
-            for (int i = 0; i < receivedEvents.size(); i++) {
-                if (pass(receivedEvents.get(i))) {
-                    filteredEvents.add(receivedEvents.get(i));
-                }
-            }
-            return filteredEvents;
-        }
-    }
-
     private void sendStateDescriptionChangedEvent(View view) {
         sendStateDescriptionChangedEvent(view, null);
     }
 
     private void sendStateDescriptionChangedEvent(View view, CharSequence text) {
-        AccessibilityEvent event = AccessibilityEvent.obtain(
-                AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        AccessibilityEvent event =
+                AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
         event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION);
         event.getText().add(text);
         view.sendAccessibilityEventUnchecked(event);
     }
 
+    @Test
+    public void setText_textChanged_receivesTextEvent() throws Throwable {
+        sUiAutomation.executeAndWaitForEvent(
+                () -> sInstrumentation.runOnMainSync(() -> mTextView.setText("a")),
+                event -> isExpectedChangeType(event, AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT),
+                DEFAULT_TIMEOUT_MS);
+
+        sUiAutomation.executeAndWaitForEvent(
+                () -> {
+                    sInstrumentation.runOnMainSync(
+                            () -> {
+                                mTextView.setText("b");
+                            });
+                },
+                event ->
+                        isExpectedSource(event, mTextView)
+                                && isExpectedChangeType(
+                                        event, AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT),
+                DEFAULT_TIMEOUT_MS);
+    }
+
+    @Test
+    public void setText_parcelableSpanChanged_receivesUndefinedEvent() throws Throwable {
+        String text = "a";
+        sUiAutomation.executeAndWaitForEvent(
+                () -> sInstrumentation.runOnMainSync(() -> mTextView.setText(text)),
+                event -> isExpectedChangeType(event, AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT),
+                DEFAULT_TIMEOUT_MS);
+
+        sUiAutomation.executeAndWaitForEvent(
+                () -> {
+                    sInstrumentation.runOnMainSync(
+                            () -> {
+                                SpannableString spannableString = new SpannableString(text);
+                                spannableString.setSpan(new LocaleSpan(Locale.ENGLISH), 0, 1, 0);
+                                mTextView.setText(spannableString);
+                            });
+                },
+                event ->
+                        isExpectedSource(event, mTextView)
+                                && isExpectedChangeType(
+                                        event, AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED),
+                DEFAULT_TIMEOUT_MS);
+    }
+
+    private static boolean isExpectedSource(AccessibilityEvent event, View view) {
+        return TextUtils.equals(view.getContext().getPackageName(), event.getPackageName())
+                && TextUtils.equals(view.getAccessibilityClassName(), event.getClassName());
+    }
+
+    private static boolean isExpectedChangeType(AccessibilityEvent event, int changeType) {
+        return (event.getContentChangeTypes() & changeType) == changeType;
+    }
+
     /**
-     * Tests whether accessibility events are correctly written and
-     * read from a parcel (version 1).
+     * Tests whether accessibility events are correctly written and read from a parcel (version 1).
      */
     @SmallTest
     @Test
@@ -291,9 +380,7 @@
         parcel.recycle();
     }
 
-    /**
-     * Tests if {@link AccessibilityEvent} are properly reused.
-     */
+    /** Tests if {@link AccessibilityEvent} are properly reused. */
     @SmallTest
     @Test
     public void testReuse() {
@@ -303,9 +390,7 @@
         assertSame("AccessibilityEvent not properly reused", firstEvent, secondEvent);
     }
 
-    /**
-     * Tests if {@link AccessibilityEvent} are properly recycled.
-     */
+    /** Tests if {@link AccessibilityEvent} are properly recycled. */
     @SmallTest
     @Test
     public void testRecycle() {
@@ -321,61 +406,80 @@
         assertAccessibilityEventCleared(recycledEvent);
     }
 
-    /**
-     * Tests whether the event types are correctly converted to strings.
-     */
+    /** Tests whether the event types are correctly converted to strings. */
     @SmallTest
     @Test
     public void testEventTypeToString() {
-        assertEquals("TYPE_NOTIFICATION_STATE_CHANGED", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED));
-        assertEquals("TYPE_TOUCH_EXPLORATION_GESTURE_END", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END));
-        assertEquals("TYPE_TOUCH_EXPLORATION_GESTURE_START", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START));
-        assertEquals("TYPE_VIEW_CLICKED", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_VIEW_CLICKED));
-        assertEquals("TYPE_VIEW_FOCUSED", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_VIEW_FOCUSED));
-        assertEquals("TYPE_VIEW_HOVER_ENTER",
+        assertEquals(
+                "TYPE_NOTIFICATION_STATE_CHANGED",
+                AccessibilityEvent.eventTypeToString(
+                        AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED));
+        assertEquals(
+                "TYPE_TOUCH_EXPLORATION_GESTURE_END",
+                AccessibilityEvent.eventTypeToString(
+                        AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END));
+        assertEquals(
+                "TYPE_TOUCH_EXPLORATION_GESTURE_START",
+                AccessibilityEvent.eventTypeToString(
+                        AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START));
+        assertEquals(
+                "TYPE_VIEW_CLICKED",
+                AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_CLICKED));
+        assertEquals(
+                "TYPE_VIEW_FOCUSED",
+                AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_FOCUSED));
+        assertEquals(
+                "TYPE_VIEW_HOVER_ENTER",
                 AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER));
-        assertEquals("TYPE_VIEW_HOVER_EXIT", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_VIEW_HOVER_EXIT));
-        assertEquals("TYPE_VIEW_LONG_CLICKED", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_VIEW_LONG_CLICKED));
-        assertEquals("TYPE_VIEW_CONTEXT_CLICKED", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED));
-        assertEquals("TYPE_VIEW_SCROLLED", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_VIEW_SCROLLED));
-        assertEquals("TYPE_VIEW_SELECTED", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_VIEW_SELECTED));
-        assertEquals("TYPE_VIEW_TEXT_CHANGED", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED));
-        assertEquals("TYPE_VIEW_TEXT_SELECTION_CHANGED", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED));
-        assertEquals("TYPE_WINDOW_CONTENT_CHANGED", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED));
-        assertEquals("TYPE_WINDOW_STATE_CHANGED", AccessibilityEvent.eventTypeToString(
-                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED));
+        assertEquals(
+                "TYPE_VIEW_HOVER_EXIT",
+                AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT));
+        assertEquals(
+                "TYPE_VIEW_LONG_CLICKED",
+                AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED));
+        assertEquals(
+                "TYPE_VIEW_CONTEXT_CLICKED",
+                AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED));
+        assertEquals(
+                "TYPE_VIEW_SCROLLED",
+                AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_SCROLLED));
+        assertEquals(
+                "TYPE_VIEW_SELECTED",
+                AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_SELECTED));
+        assertEquals(
+                "TYPE_VIEW_TEXT_CHANGED",
+                AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED));
+        assertEquals(
+                "TYPE_VIEW_TEXT_SELECTION_CHANGED",
+                AccessibilityEvent.eventTypeToString(
+                        AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED));
+        assertEquals(
+                "TYPE_WINDOW_CONTENT_CHANGED",
+                AccessibilityEvent.eventTypeToString(
+                        AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED));
+        assertEquals(
+                "TYPE_WINDOW_STATE_CHANGED",
+                AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED));
     }
 
-    /**
-     * Tests whether the event describes its contents consistently.
-     */
+    /** Tests whether the event describes its contents consistently. */
     @SmallTest
     @Test
     public void testDescribeContents() {
         AccessibilityEvent event = AccessibilityEvent.obtain();
-        assertSame("Accessibility events always return 0 for this method.", 0,
+        assertSame(
+                "Accessibility events always return 0 for this method.",
+                0,
                 event.describeContents());
         fullyPopulateAccessibilityEvent(event);
-        assertSame("Accessibility events always return 0 for this method.", 0,
+        assertSame(
+                "Accessibility events always return 0 for this method.",
+                0,
                 event.describeContents());
     }
 
     /**
-     * Tests whether accessibility events are correctly written and
-     * read from a parcel (version 2).
+     * Tests whether accessibility events are correctly written and read from a parcel (version 2).
      */
     @SmallTest
     @Test
@@ -429,8 +533,8 @@
 
         final AccessibilityEvent firstEvent = new AccessibilityEvent();
         firstEvent.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED);
-        final AccessibilityEvent secondEvent = new AccessibilityEvent(
-                AccessibilityEvent.TYPE_VIEW_FOCUSED);
+        final AccessibilityEvent secondEvent =
+                new AccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
 
         assertEqualsAccessibilityEvent(firstEvent, secondEvent);
     }
@@ -475,59 +579,104 @@
     }
 
     /**
-     * Compares all properties of the <code>expectedEvent</code> and the
-     * <code>receivedEvent</code> to verify that the received event is the one
-     * that is expected.
+     * Compares all properties of the <code>expectedEvent</code> and the <code>receivedEvent</code>
+     * to verify that the received event is the one that is expected.
      */
-    private static void assertEqualsAccessibilityEvent(AccessibilityEvent expectedEvent,
-            AccessibilityEvent receivedEvent) {
-        assertEquals("addedCount has incorrect value", expectedEvent.getAddedCount(), receivedEvent
-                .getAddedCount());
-        assertEquals("beforeText has incorrect value", expectedEvent.getBeforeText(), receivedEvent
-                .getBeforeText());
-        assertEquals("checked has incorrect value", expectedEvent.isChecked(), receivedEvent
-                .isChecked());
-        assertEquals("className has incorrect value", expectedEvent.getClassName(), receivedEvent
-                .getClassName());
-        assertEquals("contentDescription has incorrect value", expectedEvent
-                .getContentDescription(), receivedEvent.getContentDescription());
-        assertEquals("currentItemIndex has incorrect value", expectedEvent.getCurrentItemIndex(),
+    private static void assertEqualsAccessibilityEvent(
+            AccessibilityEvent expectedEvent, AccessibilityEvent receivedEvent) {
+        assertEquals(
+                "addedCount has incorrect value",
+                expectedEvent.getAddedCount(),
+                receivedEvent.getAddedCount());
+        assertEquals(
+                "beforeText has incorrect value",
+                expectedEvent.getBeforeText(),
+                receivedEvent.getBeforeText());
+        assertEquals(
+                "checked has incorrect value",
+                expectedEvent.isChecked(),
+                receivedEvent.isChecked());
+        assertEquals(
+                "className has incorrect value",
+                expectedEvent.getClassName(),
+                receivedEvent.getClassName());
+        assertEquals(
+                "contentDescription has incorrect value",
+                expectedEvent.getContentDescription(),
+                receivedEvent.getContentDescription());
+        assertEquals(
+                "currentItemIndex has incorrect value",
+                expectedEvent.getCurrentItemIndex(),
                 receivedEvent.getCurrentItemIndex());
-        assertEquals("enabled has incorrect value", expectedEvent.isEnabled(), receivedEvent
-                .isEnabled());
-        assertEquals("eventType has incorrect value", expectedEvent.getEventType(), receivedEvent
-                .getEventType());
-        assertEquals("fromIndex has incorrect value", expectedEvent.getFromIndex(), receivedEvent
-                .getFromIndex());
-        assertEquals("fullScreen has incorrect value", expectedEvent.isFullScreen(), receivedEvent
-                .isFullScreen());
-        assertEquals("itemCount has incorrect value", expectedEvent.getItemCount(), receivedEvent
-                .getItemCount());
-        assertEquals("password has incorrect value", expectedEvent.isPassword(), receivedEvent
-                .isPassword());
-        assertEquals("removedCount has incorrect value", expectedEvent.getRemovedCount(),
+        assertEquals(
+                "enabled has incorrect value",
+                expectedEvent.isEnabled(),
+                receivedEvent.isEnabled());
+        assertEquals(
+                "eventType has incorrect value",
+                expectedEvent.getEventType(),
+                receivedEvent.getEventType());
+        assertEquals(
+                "fromIndex has incorrect value",
+                expectedEvent.getFromIndex(),
+                receivedEvent.getFromIndex());
+        assertEquals(
+                "fullScreen has incorrect value",
+                expectedEvent.isFullScreen(),
+                receivedEvent.isFullScreen());
+        assertEquals(
+                "itemCount has incorrect value",
+                expectedEvent.getItemCount(),
+                receivedEvent.getItemCount());
+        assertEquals(
+                "password has incorrect value",
+                expectedEvent.isPassword(),
+                receivedEvent.isPassword());
+        assertEquals(
+                "removedCount has incorrect value",
+                expectedEvent.getRemovedCount(),
                 receivedEvent.getRemovedCount());
-        assertSame("maxScrollX has incorrect value", expectedEvent.getMaxScrollX(),
+        assertSame(
+                "maxScrollX has incorrect value",
+                expectedEvent.getMaxScrollX(),
                 receivedEvent.getMaxScrollX());
-        assertSame("maxScrollY has incorrect value", expectedEvent.getMaxScrollY(),
+        assertSame(
+                "maxScrollY has incorrect value",
+                expectedEvent.getMaxScrollY(),
                 receivedEvent.getMaxScrollY());
-        assertSame("scrollX has incorrect value", expectedEvent.getScrollX(),
+        assertSame(
+                "scrollX has incorrect value",
+                expectedEvent.getScrollX(),
                 receivedEvent.getScrollX());
-        assertSame("scrollY has incorrect value", expectedEvent.getScrollY(),
+        assertSame(
+                "scrollY has incorrect value",
+                expectedEvent.getScrollY(),
                 receivedEvent.getScrollY());
-        assertSame("scrollDeltaX has incorrect value", expectedEvent.getScrollDeltaX(),
+        assertSame(
+                "scrollDeltaX has incorrect value",
+                expectedEvent.getScrollDeltaX(),
                 receivedEvent.getScrollDeltaX());
-        assertSame("scrollDeltaY has incorrect value", expectedEvent.getScrollDeltaY(),
+        assertSame(
+                "scrollDeltaY has incorrect value",
+                expectedEvent.getScrollDeltaY(),
                 receivedEvent.getScrollDeltaY());
-        assertSame("toIndex has incorrect value", expectedEvent.getToIndex(),
+        assertSame(
+                "toIndex has incorrect value",
+                expectedEvent.getToIndex(),
                 receivedEvent.getToIndex());
-        assertSame("scrollable has incorrect value", expectedEvent.isScrollable(),
+        assertSame(
+                "scrollable has incorrect value",
+                expectedEvent.isScrollable(),
                 receivedEvent.isScrollable());
-        assertSame("granularity has incorrect value", expectedEvent.getMovementGranularity(),
+        assertSame(
+                "granularity has incorrect value",
+                expectedEvent.getMovementGranularity(),
                 receivedEvent.getMovementGranularity());
-        assertSame("action has incorrect value", expectedEvent.getAction(),
-                receivedEvent.getAction());
-        assertSame("windowChangeTypes has incorrect value", expectedEvent.getWindowChanges(),
+        assertSame(
+                "action has incorrect value", expectedEvent.getAction(), receivedEvent.getAction());
+        assertSame(
+                "windowChangeTypes has incorrect value",
+                expectedEvent.getWindowChanges(),
                 receivedEvent.getWindowChanges());
 
         AccessibilityRecordTest.assertEqualsText(expectedEvent.getText(), receivedEvent.getText());
@@ -536,12 +685,14 @@
         assertEqualAppendedRecord(expectedEvent, receivedEvent);
     }
 
-    private static void assertEqualAppendedRecord(AccessibilityEvent expectedEvent,
-            AccessibilityEvent receivedEvent) {
-        assertEquals("recordCount has incorrect value", expectedEvent.getRecordCount(),
+    private static void assertEqualAppendedRecord(
+            AccessibilityEvent expectedEvent, AccessibilityEvent receivedEvent) {
+        assertEquals(
+                "recordCount has incorrect value",
+                expectedEvent.getRecordCount(),
                 receivedEvent.getRecordCount());
         if (expectedEvent.getRecordCount() != 0 && receivedEvent.getRecordCount() != 0) {
-            AccessibilityRecord expectedRecord =  expectedEvent.getRecord(0);
+            AccessibilityRecord expectedRecord = expectedEvent.getRecord(0);
             AccessibilityRecord receivedRecord = receivedEvent.getRecord(0);
             AccessibilityRecordTest.assertEqualAccessibilityRecord(expectedRecord, receivedRecord);
         }
@@ -558,4 +709,60 @@
         TestCase.assertEquals("eventType not properly recycled", 0, event.getEventType());
         TestCase.assertNull("packageName not properly recycled", event.getPackageName());
     }
+
+    class ScrollEventFilter extends AccessibilityEventFilter {
+        private int mCount = 0;
+        private int mTargetCount;
+
+        ScrollEventFilter(int count) {
+            mTargetCount = count;
+        }
+
+        public boolean accept(AccessibilityEvent event) {
+            if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
+                mCount += 1;
+                mEvents.add(event);
+                return mCount >= mTargetCount;
+            }
+            return false;
+        }
+    }
+
+    class StateDescriptionEventFilter extends AccessibilityEventFilter {
+        private int mCount;
+        private int mTargetCount;
+
+        StateDescriptionEventFilter(int count) {
+            mTargetCount = count;
+        }
+
+        public boolean accept(AccessibilityEvent event) {
+            if (event.getContentChangeTypes()
+                    == AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION) {
+                mCount += 1;
+                mEvents.add(event);
+                return mCount >= mTargetCount;
+            }
+            return false;
+        }
+    }
+    ;
+
+    private abstract class AccessibilityEventFilter
+            implements UiAutomation.AccessibilityEventFilter {
+        protected List<AccessibilityEvent> mEvents = new ArrayList<>();
+
+        public abstract boolean accept(AccessibilityEvent event);
+
+        void assertReceivedEventCount(int count) {
+            assertEquals(count, mEvents.size());
+        }
+
+        AccessibilityEvent getLastEvent() {
+            if (mEvents.size() > 0) {
+                return mEvents.get(mEvents.size() - 1);
+            }
+            return null;
+        }
+    }
 }
diff --git a/tests/app/src/android/app/cts/OWNERS b/tests/app/src/android/app/cts/OWNERS
new file mode 100644
index 0000000..7a6f201
--- /dev/null
+++ b/tests/app/src/android/app/cts/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 803062
+per-file NearbyMediaDevicesProviderTest.kt=file:platform/frameworks/base:/packages/SystemUI/OWNERS
+# Bug component: 803062
+per-file UpdateMediaTapToTransfer*.kt=file:platform/frameworks/base:/packages/SystemUI/OWNERS
diff --git a/tests/autofillservice/OWNERS b/tests/autofillservice/OWNERS
index 7f4d695..5c14735 100644
--- a/tests/autofillservice/OWNERS
+++ b/tests/autofillservice/OWNERS
@@ -1,7 +1,3 @@
 # Bug component: 351486
-adamhe@google.com
-augale@google.com
-joannechung@google.com
-lpeter@google.com
-svetoslavganov@google.com
-tymtsai@google.com
+
+include platform/frameworks/base:/core/java/android/view/autofill/OWNERS
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 af15ff0..b466feb 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -186,7 +186,7 @@
                     /*gpsLocation*/ sTestLocation2,
                     /* orientation */270,
                     /* jpgQuality */(byte) 100,
-                    /* thumbQuality */(byte) 100)
+                    /* thumbQuality */(byte) 80)
     };
 
     /**
diff --git a/tests/contentcaptureservice/OWNERS b/tests/contentcaptureservice/OWNERS
index 4135301..4bea4c8 100644
--- a/tests/contentcaptureservice/OWNERS
+++ b/tests/contentcaptureservice/OWNERS
@@ -1,7 +1,3 @@
 # Bug component: 544200
-adamhe@google.com
-augale@google.com
-joannechung@google.com
-lpeter@google.com
-svetoslavganov@google.com
-tymtsai@google.com
+
+include platform/frameworks/base:/core/java/android/view/contentcapture/OWNERS
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
index ad79e02..6f6aac2 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
@@ -16,9 +16,6 @@
 package android.contentcaptureservice.cts;
 
 import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
-import static android.contentcaptureservice.cts.Assertions.assertViewTextChanged;
-import static android.contentcaptureservice.cts.Assertions.assertVirtualViewAppeared;
-import static android.contentcaptureservice.cts.Assertions.assertVirtualViewsDisappeared;
 import static android.contentcaptureservice.cts.Helper.MY_PACKAGE;
 import static android.contentcaptureservice.cts.Helper.NO_ACTIVITIES;
 import static android.contentcaptureservice.cts.Helper.OTHER_PACKAGE;
@@ -278,14 +275,11 @@
         final AutofillId customViewId = activity.mCustomView.getAutofillId();
         final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession();
 
-        final int i = CustomViewActivity.MIN_EVENTS;
-
-        assertVirtualViewAppeared(events, i, mainSession, customViewId, 1, "child1");
-        assertVirtualViewAppeared(events, i + 1, mainSession, customViewId, 2, "child2");
-        assertViewTextChanged(events, i + 2, child2IdRef.get(), "The Times They Are a-Changin'");
-        assertVirtualViewsDisappeared(events, i + 3, customViewId, mainSession, 2, 1);
-
-        activity.assertInitialViewsDisappeared(events, additionalEvents);
+        new EventsAssertor(events)
+                .assertVirtualViewAppeared(mainSession, customViewId, 1, "child1")
+                .assertVirtualViewAppeared(mainSession, customViewId, 2, "child2")
+                .assertViewTextChanged(child2IdRef.get(), "The Times They Are a-Changin'")
+                .assertVirtualViewsDisappeared(customViewId, mainSession, 2, 1);
         // TODO(b/122315042): assert views disappeared
     }
 
@@ -392,18 +386,15 @@
         final AutofillId customViewId = activity.mCustomView.getAutofillId();
         final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession();
 
-        final int i = CustomViewActivity.MIN_EVENTS;
-
-        assertVirtualViewAppeared(events, i, mainSession, customViewId, 1, "c1");
-        assertVirtualViewAppeared(events, i + 1, mainSession, customViewId, 11, "c1g1");
-        assertVirtualViewAppeared(events, i + 2, mainSession, customViewId, 12, "c1g2");
-        assertVirtualViewAppeared(events, i + 3, mainSession, customViewId, 2, "c2");
-        assertVirtualViewAppeared(events, i + 4, mainSession, customViewId, 21, "c2g1");
-        assertVirtualViewAppeared(events, i + 5, mainSession, customViewId, 211, "c2g1gg1");
-        assertVirtualViewAppeared(events, i + 6, mainSession, customViewId, 3, "c3");
-        assertVirtualViewsDisappeared(events, i + 7, customViewId, mainSession, 21, 2, 11, 1, 12);
-
-        activity.assertInitialViewsDisappeared(events, additionalEvents);
+        new EventsAssertor(events)
+                .assertVirtualViewAppeared(mainSession, customViewId, 1, "c1")
+                .assertVirtualViewAppeared(mainSession, customViewId, 11, "c1g1")
+                .assertVirtualViewAppeared(mainSession, customViewId, 12, "c1g2")
+                .assertVirtualViewAppeared(mainSession, customViewId, 2, "c2")
+                .assertVirtualViewAppeared(mainSession, customViewId, 21, "c2g1")
+                .assertVirtualViewAppeared(mainSession, customViewId, 211, "c2g1gg1")
+                .assertVirtualViewAppeared(mainSession, customViewId, 3, "c3")
+                .assertVirtualViewsDisappeared(customViewId, mainSession, 21, 2, 11, 1, 12);
         // TODO(b/122315042): assert other views disappeared
     }
 
@@ -458,13 +449,10 @@
         final AutofillId customViewId = activity.mCustomView.getAutofillId();
         final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession();
 
-        final int i = CustomViewActivity.MIN_EVENTS;
-
-        assertVirtualViewAppeared(events, i, mainSession, customViewId, 1, "child1");
-        assertVirtualViewAppeared(events, i + 1, mainSession, customViewId, 2, "child2");
-        assertVirtualViewsDisappeared(events, i + 2, customViewId, mainSession, 2, 1);
-
-        activity.assertInitialViewsDisappeared(events, additionalEvents);
+        new EventsAssertor(events)
+                .assertVirtualViewAppeared(mainSession, customViewId, 1, "child1")
+                .assertVirtualViewAppeared(mainSession, customViewId, 2, "child2")
+                .assertVirtualViewsDisappeared(customViewId, mainSession, 2, 1);
         // TODO(b/122315042): assert other views disappeared
     }
 
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/EventsAssertor.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/EventsAssertor.java
index d00b031..eaf07f9 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/EventsAssertor.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/EventsAssertor.java
@@ -200,6 +200,18 @@
     }
 
     /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_TEXT_CHANGED} event.
+     */
+    @NonNull
+    public EventsAssertor assertViewTextChanged(@NonNull AutofillId expectedId,
+            @NonNull String expectedText) {
+        assertNextEvent((event) -> assertTextChangedEvent(event, expectedId, expectedText),
+                ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED,
+                String.format("no VIEW_TEXT_CHANGED event for %s", expectedId));
+        return this;
+    }
+
+    /**
      * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED}
      * event for a virtual node.
      */
@@ -223,14 +235,30 @@
         return assertViewDisappeared(session.newAutofillId(parentId, childId));
     }
 
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_DISAPPEARED}
+     * event for many virtual nodes.
+     */
+    @NonNull
+    public EventsAssertor assertVirtualViewsDisappeared(AutofillId parentId,
+            ContentCaptureSession session, int... childId) {
+        final AutofillId[] ids = new AutofillId[childId.length];
+        for (int i = 0; i < childId.length; i++) {
+            ids[i] = session.newAutofillId(parentId, childId[i]);
+        }
+        return assertViewDisappeared(ids);
+    }
+
     @Nullable
     private String assertVirtualViewEvent(@NonNull ContentCaptureEvent event,
             @NonNull AutofillId expectedId, @Nullable String expectedText) {
         final ViewNode node = event.getViewNode();
         assertThat(node).isNotNull();
-        assertWithMessage("wrong autofill id on %s", event)
-                .that(node.getAutofillId()).isEqualTo(expectedId);
-        if (expectedText != null) {
+        if (!node.getAutofillId().equals(expectedId)) {
+            return String.format("wrong autofill id (expected %s, actual is %s) at %s",
+                    expectedId, node.getAutofillId(), event);
+        }
+        if (expectedText != null && node.getText() != null) {
             assertWithMessage("wrong text on %s", event)
                     .that(node.getText().toString()).isEqualTo(expectedText);
         } else {
@@ -266,6 +294,16 @@
         return null;
     }
 
+    @Nullable
+    private String assertTextChangedEvent(@NonNull ContentCaptureEvent event,
+            @NonNull AutofillId expectedId, @NonNull String expectedText) {
+        assertWithMessage("Wrong id on %s", event).that(event.getId())
+                .isEqualTo(expectedId);
+        assertWithMessage("Wrong text on %s", event).that(event.getText().toString())
+                .isEqualTo(expectedText);
+        return null;
+    }
+
     private void assertCommonViewDisappearedProperties(@NonNull ContentCaptureEvent event) {
         assertWithMessage("event %s should not have a ViewNode", event)
                 .that(event.getViewNode()).isNull();
diff --git a/tests/controls/src/android/controls/cts/CtsControlsPublisher.java b/tests/controls/src/android/controls/cts/CtsControlsPublisher.java
index 643d80e..c8c09c8 100644
--- a/tests/controls/src/android/controls/cts/CtsControlsPublisher.java
+++ b/tests/controls/src/android/controls/cts/CtsControlsPublisher.java
@@ -38,7 +38,7 @@
         }
     }
 
-    public void subscribe​(Subscriber<? super Control> subscriber) {
+    public void subscribe(Subscriber<? super Control> subscriber) {
         mSubscriber = subscriber;
         mSubscriber.onSubscribe(new Subscription() {
                 public void request(long n) {
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
index b7f0ec2..fa6dcde 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
@@ -52,7 +52,10 @@
 import com.android.bedstead.harrier.annotations.Postsubmit;
 import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.packages.Package;
+import com.android.bedstead.nene.packages.PackageReference;
 import com.android.bedstead.nene.permissions.PermissionContext;
+import com.android.bedstead.nene.users.UnresolvedUser;
+import com.android.bedstead.nene.users.UserReference;
 import com.android.compatibility.common.util.SystemUtil;
 
 import org.junit.ClassRule;
@@ -62,7 +65,9 @@
 import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -383,8 +388,17 @@
     }
 
     private Set<String> getInstalledPackagesOnUser(Set<String> packages, UserHandle user) {
-        return packages.stream().filter(p -> isPackageInstalledOnUser(p, user))
-                .collect(Collectors.toSet());
+        Set<String> installedPackagesOnUser = new HashSet<>();
+
+        UserReference userRef = sTestApis.users().find(user);
+        Collection<PackageReference> packageInUser = sTestApis.packages().installedForUser(userRef);
+        for (PackageReference pkg : packageInUser) {
+            if (packages.contains(pkg.packageName())) {
+                installedPackagesOnUser.add(pkg.packageName());
+            }
+        }
+
+        return installedPackagesOnUser;
     }
 
     private boolean isPackageInstalledOnCurrentUser(String packageName) {
diff --git a/tests/framework/base/biometrics/Android.bp b/tests/framework/base/biometrics/Android.bp
index 369faa7..66c8134 100644
--- a/tests/framework/base/biometrics/Android.bp
+++ b/tests/framework/base/biometrics/Android.bp
@@ -43,6 +43,10 @@
         "ub-uiautomator",
     ],
     srcs: ["src/**/*.java"],
+    data: [
+        ":CtsBiometricServiceTestApp",
+        ":CtsFingerprintServiceTestApp",
+    ],
     sdk_version: "test_current",
     per_testcase_directory: true,
 }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java
index 28608d0..dfb4252 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java
@@ -25,6 +25,7 @@
 import static android.server.wm.DisplayCutoutTests.TestActivity.EXTRA_ORIENTATION;
 import static android.server.wm.DisplayCutoutTests.TestDef.Which.DISPATCHED;
 import static android.server.wm.DisplayCutoutTests.TestDef.Which.ROOT;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
@@ -527,14 +528,9 @@
                 new Intent().putExtra(EXTRA_CUTOUT_MODE, cutoutMode)
                         .putExtra(EXTRA_ORIENTATION, orientation));
         PollingCheck.waitFor(activity::hasWindowFocus);
-        PollingCheck.waitFor(() -> {
-            final Rect appBounds = getAppBounds(activity);
-            final Point displaySize = new Point();
-            activity.getDisplay().getRealSize(displaySize);
-            // During app launch into a different rotation, we have temporarily have the display
-            // in a different rotation than the app itself. Wait for this to settle.
-            return (appBounds.width() > appBounds.height()) == (displaySize.x > displaySize.y);
-        });
+        final WindowManagerStateHelper wmState = new WindowManagerStateHelper();
+        wmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
+        wmState.waitForDisplayUnfrozen();
         return activity;
     }
 
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/SpellCheckerTest.kt b/tests/inputmethod/src/android/view/inputmethod/cts/SpellCheckerTest.kt
index 110f9d0..cac75be 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/SpellCheckerTest.kt
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/SpellCheckerTest.kt
@@ -270,36 +270,39 @@
                                 .addSuggestions("suggestion")
                                 .setAttributes(RESULT_ATTR_LOOKS_LIKE_TYPO)
                 ).build()
-        MockSpellCheckerClient.create(context, configuration).use {
-            val tsm = context.getSystemService(TextServicesManager::class.java)
-            assertThat(tsm).isNotNull()
-            val fakeListener = FakeSpellCheckerSessionListener()
-            val fakeExecutor = FakeExecutor()
-            val params = SpellCheckerSession.SpellCheckerSessionParams.Builder()
-                    .setLocale(Locale.US)
-                    .setSupportedAttributes(RESULT_ATTR_LOOKS_LIKE_TYPO)
-                    .build()
-            val session: SpellCheckerSession? = tsm?.newSpellCheckerSession(
-                    params, fakeExecutor, fakeListener)
-            assertThat(session).isNotNull()
-            session?.getSentenceSuggestions(arrayOf(TextInfo("match")), 5)
-            waitOnMainUntil({ fakeExecutor.runnables.size == 1 }, TIMEOUT)
-            fakeExecutor.runnables[0].run()
+        // Use MockIme, in case the default IME sets android:suppressesSpellChecker="true"
+        MockImeSession.create(context).use { session ->
+            MockSpellCheckerClient.create(context, configuration).use {
+                val tsm = context.getSystemService(TextServicesManager::class.java)
+                assertThat(tsm).isNotNull()
+                val fakeListener = FakeSpellCheckerSessionListener()
+                val fakeExecutor = FakeExecutor()
+                val params = SpellCheckerSession.SpellCheckerSessionParams.Builder()
+                        .setLocale(Locale.US)
+                        .setSupportedAttributes(RESULT_ATTR_LOOKS_LIKE_TYPO)
+                        .build()
+                val session: SpellCheckerSession? = tsm?.newSpellCheckerSession(
+                        params, fakeExecutor, fakeListener)
+                assertThat(session).isNotNull()
+                session?.getSentenceSuggestions(arrayOf(TextInfo("match")), 5)
+                waitOnMainUntil({ fakeExecutor.runnables.size == 1 }, TIMEOUT)
+                fakeExecutor.runnables[0].run()
 
-            assertThat(fakeListener.getSentenceSuggestionsResults).hasSize(1)
-            assertThat(fakeListener.getSentenceSuggestionsResults[0]).hasLength(1)
-            val sentenceSuggestionsInfo = fakeListener.getSentenceSuggestionsResults[0]!![0]
-            assertThat(sentenceSuggestionsInfo.suggestionsCount).isEqualTo(1)
-            assertThat(sentenceSuggestionsInfo.getOffsetAt(0)).isEqualTo(0)
-            assertThat(sentenceSuggestionsInfo.getLengthAt(0)).isEqualTo("match".length)
-            val suggestionsInfo = sentenceSuggestionsInfo.getSuggestionsInfoAt(0)
-            assertThat(suggestionsInfo.suggestionsCount).isEqualTo(1)
-            assertThat(suggestionsInfo.getSuggestionAt(0)).isEqualTo("suggestion")
+                assertThat(fakeListener.getSentenceSuggestionsResults).hasSize(1)
+                assertThat(fakeListener.getSentenceSuggestionsResults[0]).hasLength(1)
+                val sentenceSuggestionsInfo = fakeListener.getSentenceSuggestionsResults[0]!![0]
+                assertThat(sentenceSuggestionsInfo.suggestionsCount).isEqualTo(1)
+                assertThat(sentenceSuggestionsInfo.getOffsetAt(0)).isEqualTo(0)
+                assertThat(sentenceSuggestionsInfo.getLengthAt(0)).isEqualTo("match".length)
+                val suggestionsInfo = sentenceSuggestionsInfo.getSuggestionsInfoAt(0)
+                assertThat(suggestionsInfo.suggestionsCount).isEqualTo(1)
+                assertThat(suggestionsInfo.getSuggestionAt(0)).isEqualTo("suggestion")
 
-            assertThat(fakeListener.getSentenceSuggestionsResults).hasSize(1)
-            assertThat(fakeListener.getSentenceSuggestionsCallingThreads).hasSize(1)
-            assertThat(fakeListener.getSentenceSuggestionsCallingThreads[0])
-                    .isEqualTo(Thread.currentThread())
+                assertThat(fakeListener.getSentenceSuggestionsResults).hasSize(1)
+                assertThat(fakeListener.getSentenceSuggestionsCallingThreads).hasSize(1)
+                assertThat(fakeListener.getSentenceSuggestionsCallingThreads[0])
+                        .isEqualTo(Thread.currentThread())
+            }
         }
     }
 
@@ -312,24 +315,27 @@
                                 .addSuggestions("suggestion")
                                 .setAttributes(RESULT_ATTR_LOOKS_LIKE_TYPO)
                 ).build()
-        MockSpellCheckerClient.create(context, configuration).use {
-            val tsm = context.getSystemService(TextServicesManager::class.java)
-            assertThat(tsm).isNotNull()
-            val fakeListener = FakeSpellCheckerSessionListener()
-            var session: SpellCheckerSession? = null
-            runOnMainSync {
-                session = tsm?.newSpellCheckerSession(null /* bundle */, Locale.US,
-                        fakeListener, false /* referToSpellCheckerLanguageSettings */)
-            }
-            assertThat(session).isNotNull()
-            session?.getSentenceSuggestions(arrayOf(TextInfo("match")), 5)
-            waitOnMainUntil({
-                fakeListener.getSentenceSuggestionsCallingThreads.size > 0
-            }, TIMEOUT)
-            runOnMainSync {
-                assertThat(fakeListener.getSentenceSuggestionsCallingThreads).hasSize(1)
-                assertThat(fakeListener.getSentenceSuggestionsCallingThreads[0])
-                        .isEqualTo(Looper.getMainLooper().thread)
+        // Use MockIme, in case the default IME sets android:suppressesSpellChecker="true"
+        MockImeSession.create(context).use { session ->
+            MockSpellCheckerClient.create(context, configuration).use {
+                val tsm = context.getSystemService(TextServicesManager::class.java)
+                assertThat(tsm).isNotNull()
+                val fakeListener = FakeSpellCheckerSessionListener()
+                var session: SpellCheckerSession? = null
+                runOnMainSync {
+                    session = tsm?.newSpellCheckerSession(null /* bundle */, Locale.US,
+                            fakeListener, false /* referToSpellCheckerLanguageSettings */)
+                }
+                assertThat(session).isNotNull()
+                session?.getSentenceSuggestions(arrayOf(TextInfo("match")), 5)
+                waitOnMainUntil({
+                    fakeListener.getSentenceSuggestionsCallingThreads.size > 0
+                }, TIMEOUT)
+                runOnMainSync {
+                    assertThat(fakeListener.getSentenceSuggestionsCallingThreads).hasSize(1)
+                    assertThat(fakeListener.getSentenceSuggestionsCallingThreads[0])
+                            .isEqualTo(Looper.getMainLooper().thread)
+                }
             }
         }
     }
@@ -343,33 +349,36 @@
                                 .addSuggestions("suggestion")
                                 .setAttributes(RESULT_ATTR_LOOKS_LIKE_TYPO)
                 ).build()
-        MockSpellCheckerClient.create(context, configuration).use {
-            val tsm = context.getSystemService(TextServicesManager::class.java)
-            assertThat(tsm).isNotNull()
-            val fakeListener = FakeSpellCheckerSessionListener()
-            val fakeExecutor = FakeExecutor()
-            // Set a prefix. MockSpellChecker will add "test_" to the spell check result.
-            val extras = Bundle()
-            extras.putString(EXTRAS_KEY_PREFIX, "test_")
-            val params = SpellCheckerSession.SpellCheckerSessionParams.Builder()
-                    .setLocale(Locale.US)
-                    .setSupportedAttributes(RESULT_ATTR_LOOKS_LIKE_TYPO)
-                    .setExtras(extras)
-                    .build()
-            val session: SpellCheckerSession? = tsm?.newSpellCheckerSession(
-                    params, fakeExecutor, fakeListener)
-            assertThat(session).isNotNull()
-            session?.getSentenceSuggestions(arrayOf(TextInfo("match")), 5)
-            waitOnMainUntil({ fakeExecutor.runnables.size == 1 }, TIMEOUT)
-            fakeExecutor.runnables[0].run()
+        // Use MockIme, in case the default IME sets android:suppressesSpellChecker="true"
+        MockImeSession.create(context).use { session ->
+            MockSpellCheckerClient.create(context, configuration).use {
+                val tsm = context.getSystemService(TextServicesManager::class.java)
+                assertThat(tsm).isNotNull()
+                val fakeListener = FakeSpellCheckerSessionListener()
+                val fakeExecutor = FakeExecutor()
+                // Set a prefix. MockSpellChecker will add "test_" to the spell check result.
+                val extras = Bundle()
+                extras.putString(EXTRAS_KEY_PREFIX, "test_")
+                val params = SpellCheckerSession.SpellCheckerSessionParams.Builder()
+                        .setLocale(Locale.US)
+                        .setSupportedAttributes(RESULT_ATTR_LOOKS_LIKE_TYPO)
+                        .setExtras(extras)
+                        .build()
+                val session: SpellCheckerSession? = tsm?.newSpellCheckerSession(
+                        params, fakeExecutor, fakeListener)
+                assertThat(session).isNotNull()
+                session?.getSentenceSuggestions(arrayOf(TextInfo("match")), 5)
+                waitOnMainUntil({ fakeExecutor.runnables.size == 1 }, TIMEOUT)
+                fakeExecutor.runnables[0].run()
 
-            assertThat(fakeListener.getSentenceSuggestionsResults).hasSize(1)
-            assertThat(fakeListener.getSentenceSuggestionsResults[0]).hasLength(1)
-            val sentenceSuggestionsInfo = fakeListener.getSentenceSuggestionsResults[0]!![0]
-            assertThat(sentenceSuggestionsInfo.suggestionsCount).isEqualTo(1)
-            val suggestionsInfo = sentenceSuggestionsInfo.getSuggestionsInfoAt(0)
-            assertThat(suggestionsInfo.suggestionsCount).isEqualTo(1)
-            assertThat(suggestionsInfo.getSuggestionAt(0)).isEqualTo("test_suggestion")
+                assertThat(fakeListener.getSentenceSuggestionsResults).hasSize(1)
+                assertThat(fakeListener.getSentenceSuggestionsResults[0]).hasLength(1)
+                val sentenceSuggestionsInfo = fakeListener.getSentenceSuggestionsResults[0]!![0]
+                assertThat(sentenceSuggestionsInfo.suggestionsCount).isEqualTo(1)
+                val suggestionsInfo = sentenceSuggestionsInfo.getSuggestionsInfoAt(0)
+                assertThat(suggestionsInfo.suggestionsCount).isEqualTo(1)
+                assertThat(suggestionsInfo.getSuggestionAt(0)).isEqualTo("test_suggestion")
+            }
         }
     }
 
@@ -497,24 +506,27 @@
                                 .addSuggestions("suggestion")
                                 .setAttributes(RESULT_ATTR_LOOKS_LIKE_TYPO)
                 ).build()
-        MockSpellCheckerClient.create(context, configuration).use {
-            val tsm = context.getSystemService(TextServicesManager::class.java)
-            assertThat(tsm).isNotNull()
-            val fakeListener = FakeSpellCheckerSessionListener()
-            val fakeExecutor = FakeExecutor()
-            val params = SpellCheckerSession.SpellCheckerSessionParams.Builder()
-                    .setLocale(Locale.US)
-                    .setSupportedAttributes(RESULT_ATTR_LOOKS_LIKE_TYPO)
-                    .build()
-            var session: SpellCheckerSession? = tsm?.newSpellCheckerSession(
-                    params, fakeExecutor, fakeListener)
-            assertThat(session).isNotNull()
-            session?.getSentenceSuggestions(arrayOf(TextInfo(". ")), 5)
-            waitOnMainUntil({ fakeExecutor.runnables.size == 1 }, TIMEOUT)
-            fakeExecutor.runnables[0].run()
-            assertThat(fakeListener.getSentenceSuggestionsResults).hasSize(1)
-            assertThat(fakeListener.getSentenceSuggestionsResults[0]).hasLength(1)
-            assertThat(fakeListener.getSentenceSuggestionsResults[0]!![0]).isNull()
+        // Use MockIme, in case the default IME sets android:suppressesSpellChecker="true"
+        MockImeSession.create(context).use { session ->
+            MockSpellCheckerClient.create(context, configuration).use {
+                val tsm = context.getSystemService(TextServicesManager::class.java)
+                assertThat(tsm).isNotNull()
+                val fakeListener = FakeSpellCheckerSessionListener()
+                val fakeExecutor = FakeExecutor()
+                val params = SpellCheckerSession.SpellCheckerSessionParams.Builder()
+                        .setLocale(Locale.US)
+                        .setSupportedAttributes(RESULT_ATTR_LOOKS_LIKE_TYPO)
+                        .build()
+                var session: SpellCheckerSession? = tsm?.newSpellCheckerSession(
+                        params, fakeExecutor, fakeListener)
+                assertThat(session).isNotNull()
+                session?.getSentenceSuggestions(arrayOf(TextInfo(". ")), 5)
+                waitOnMainUntil({ fakeExecutor.runnables.size == 1 }, TIMEOUT)
+                fakeExecutor.runnables[0].run()
+                assertThat(fakeListener.getSentenceSuggestionsResults).hasSize(1)
+                assertThat(fakeListener.getSentenceSuggestionsResults[0]).hasLength(1)
+                assertThat(fakeListener.getSentenceSuggestionsResults[0]!![0]).isNull()
+            }
         }
     }
 
diff --git a/tests/libcore/luni/Android.bp b/tests/libcore/luni/Android.bp
index 2fc1f56..78ea004 100644
--- a/tests/libcore/luni/Android.bp
+++ b/tests/libcore/luni/Android.bp
@@ -39,11 +39,6 @@
         enabled: false,
     },
     dxflags: ["--multi-dex"],
-    // Exclude apache harmony tests from coverage instrumentation, since it breaks
-    // the tests of reflection APIs by adding fields and methods to the test classes.
-    jacoco: {
-        exclude_filter: ["org.apache.harmony.tests.**"],
-    },
     optimize: {
         enabled: false,
     },
diff --git a/tests/libcore/luni/AndroidTest.xml b/tests/libcore/luni/AndroidTest.xml
index 13fd8d4..58bb535 100644
--- a/tests/libcore/luni/AndroidTest.xml
+++ b/tests/libcore/luni/AndroidTest.xml
@@ -47,26 +47,6 @@
         <option name="device-listeners" value="org.conscrypt.ConscryptInstrumentationListener" />
         <option name="instrumentation-arg" key="conscrypt_sslsocket_implementation" value="engine" />
     </test>
-    <!-- Re-run a subset of tests using Conscrypt's file-descriptor based implementation to ensure
-         there are no regressions in this implementation before it is fully deprecated.
-
-         Expectations for these tests are the same as above, only timeout and SSLSocket
-         implementation are different.
-    -->
-    <test class="com.android.compatibility.testtype.LibcoreTest" >
-        <option name="package" value="android.libcore.cts" />
-        <option name="include-filter" value="libcore.javax.net.ssl" />
-        <option name="include-filter" value="com.android.org.conscrypt.javax.net.ssl" />
-        <option name="include-filter" value="org.apache.harmony.tests.javax.net.ssl" />
-        <option name="instrumentation-arg" key="filter"
-                value="com.android.cts.core.runner.ExpectationBasedFilter" />
-        <option name="core-expectation" value="/knownfailures.txt" />
-        <option name="virtual-device-core-expectation" value="/virtualdeviceknownfailures.txt" />
-        <option name="runtime-hint" value="5m"/>
-        <option name="hidden-api-checks" value="false"/>
-        <option name="device-listeners" value="org.conscrypt.ConscryptInstrumentationListener" />
-        <option name="instrumentation-arg" key="conscrypt_sslsocket_implementation" value="fd" />
-    </test>
 
     <object type="module_controller" class="com.android.tradefed.testtype.suite.module.TestFailureModuleController">
         <option name="screenshot-on-failure" value="false" />
diff --git a/tests/media/Android.bp b/tests/media/Android.bp
index b2a2db3..03ff17d 100644
--- a/tests/media/Android.bp
+++ b/tests/media/Android.bp
@@ -21,6 +21,7 @@
     defaults: ["cts_defaults"],
     compile_multilib: "both",
     static_libs: [
+        "androidx.test.core",
         "compatibility-device-util-axt",
         "ctstestrunner-axt",
         "ctstestserver",
diff --git a/tests/media/AndroidTest.xml b/tests/media/AndroidTest.xml
index 820fd60..8290a9f 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.0" />
+        <option name="media-folder-name" value="CtsMediaV2TestCases-2.1" />
         <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 26cf0fc..195333b 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.0.zip</value>
+      <value>https://storage.googleapis.com/android_media/cts/tests/media/CtsMediaV2TestCases-2.1.zip</value>
     </entry>
 </dynamicConfig>
diff --git a/tests/media/README.md b/tests/media/README.md
index 38fdafb..931f431 100644
--- a/tests/media/README.md
+++ b/tests/media/README.md
@@ -3,7 +3,10 @@
 
 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.0.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.1.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 Driving POV(dpov) test vectors are of 10-bit format. They are downloaded from [link](https://media.xiph.org/video/derf/) and resampled according to the test requirements.
 
 The test suite looks to cover sdk/ndk api in normal and error scenarios. Error scenarios are separated from regular usage and are placed under class *UnitTest (MuxerUnitTest, ExtractorUnitTest, ...).
 
diff --git a/tests/media/copy_media.sh b/tests/media/copy_media.sh
index 4e5a086..de8d997 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.0
+resLabel=CtsMediaV2TestCases-2.1
 srcDir="/tmp/$resLabel"
 tgtDir="/sdcard/test"
 usage="Usage: $0 [-h] [-s serial]"
diff --git a/tests/media/src/android/mediav2/cts/AdaptivePlaybackTest.java b/tests/media/src/android/mediav2/cts/AdaptivePlaybackTest.java
index ae9054f..911a29f 100644
--- a/tests/media/src/android/mediav2/cts/AdaptivePlaybackTest.java
+++ b/tests/media/src/android/mediav2/cts/AdaptivePlaybackTest.java
@@ -21,10 +21,12 @@
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.filters.LargeTest;
-import androidx.test.rule.ActivityTestRule;
 
+import org.junit.After;
 import org.junit.Assume;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -38,31 +40,43 @@
 import java.util.Collection;
 import java.util.List;
 
-import static org.junit.Assert.fail;
+import static android.mediav2.cts.CodecTestBase.SupportClass.*;
 
 @RunWith(Parameterized.class)
 public class AdaptivePlaybackTest extends CodecDecoderTestBase {
     private final String[] mSrcFiles;
-    private final int mSupport;
+    private final SupportClass mSupportRequirements;
 
     private long mMaxPts = 0;
 
-    public AdaptivePlaybackTest(String decoder, String mime, String[] srcFiles, int support) {
+    public AdaptivePlaybackTest(String decoder, String mime, String[] srcFiles,
+            SupportClass supportRequirements) {
         super(decoder, mime, null);
         mSrcFiles = srcFiles;
-        mSupport = support;
+        mSupportRequirements = supportRequirements;
     }
 
     @Rule
-    public ActivityTestRule<CodecTestActivity> mActivityRule =
-            new ActivityTestRule<>(CodecTestActivity.class);
+    public ActivityScenarioRule<CodecTestActivity> mActivityRule =
+            new ActivityScenarioRule<>(CodecTestActivity.class);
+
+    @Before
+    public void setUp() throws IOException, InterruptedException {
+        mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
+        setUpSurface(mActivity);
+    }
+
+    @After
+    public void tearDown() {
+        tearDownSurface();
+    }
 
     @Parameterized.Parameters(name = "{index}({0}_{1})")
     public static Collection<Object[]> input() {
         final boolean isEncoder = false;
         final boolean needAudio = false;
         final boolean needVideo = true;
-        // mime, array list of test files we'll play, codec should support adaptive feature
+        // mediaType, array list of test files, SupportClass
         final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
                 {MediaFormat.MIMETYPE_VIDEO_AVC, new String[]{
                         "bbb_800x640_768kbps_30fps_avc_2b.mp4",
@@ -177,21 +191,10 @@
             formats.add(setUpSource(file));
             mExtractor.release();
         }
-        if (!areFormatsSupported(mCodecName, mMime, formats)) {
-            if (mSupport == CODEC_ALL) {
-                fail("format(s) not supported by component: " + mCodecName + " for mime : " +
-                        mMime);
-            }
-            if (mSupport != CODEC_OPTIONAL && selectCodecs(mMime, formats,
-                    new String[]{MediaCodecInfo.CodecCapabilities.FEATURE_AdaptivePlayback}, false)
-                    .isEmpty()) {
-                fail("format(s) not supported by any component for mime : " + mMime);
-            }
-            return;
-        }
+        checkFormatSupport(mCodecName, mMime, formats,
+                new String[]{MediaCodecInfo.CodecCapabilities.FEATURE_AdaptivePlayback},
+                mSupportRequirements);
         formats.clear();
-        CodecTestActivity activity = mActivityRule.getActivity();
-        setUpSurface(activity);
         int totalSize = 0;
         for (String srcFile : mSrcFiles) {
             File file = new File(mInpPrefix + srcFile);
@@ -211,7 +214,7 @@
         {
             mCodec = MediaCodec.createByCodecName(mCodecName);
             MediaFormat format = formats.get(0);
-            activity.setScreenParams(getWidth(format), getHeight(format), true);
+            mActivity.setScreenParams(getWidth(format), getHeight(format), true);
             mOutputBuff.reset();
             configureCodec(format, true, false, false);
             mCodec.start();
@@ -221,6 +224,5 @@
             mCodec.reset();
             mCodec.release();
         }
-        tearDownSurface();
     }
 }
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderPauseTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderPauseTest.java
index 59b469d..1caa96b 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderPauseTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderPauseTest.java
@@ -32,8 +32,8 @@
 import java.util.Collection;
 import java.util.List;
 
+import static android.mediav2.cts.CodecTestBase.SupportClass.*;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 /**
  * The following test validates that the decode can be paused
@@ -43,11 +43,12 @@
     private static final String LOG_TAG = CodecDecoderPauseTest.class.getSimpleName();
     private final long PAUSE_TIME_MS = 10000;
     private final int NUM_FRAMES = 8;
-    private final int mSupport;
+    private final SupportClass mSupportRequirements;
 
-    public CodecDecoderPauseTest(String decoder, String mime, String srcFile, int support) {
+    public CodecDecoderPauseTest(String decoder, String mime, String srcFile,
+            SupportClass supportRequirements) {
         super(decoder, mime, srcFile);
-        mSupport = support;
+        mSupportRequirements = supportRequirements;
     }
 
     @Parameterized.Parameters(name = "{index}({0}_{1})")
@@ -55,14 +56,16 @@
         final boolean isEncoder = false;
         final boolean needAudio = true;
         final boolean needVideo = true;
-        // mime, source file, codecs required to support
+        /// mediaType, test file, SupportClass
         final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
                 {MediaFormat.MIMETYPE_AUDIO_AAC, "bbb_2ch_48kHz_he_aac.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_cif_avc_delay16.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_H263, "bbb_176x144_128kbps_15fps_h263.3gp", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_cif_hevc_delay15.mp4", CODEC_ALL},
-                {MediaFormat.MIMETYPE_VIDEO_MPEG2, "bbb_640x360_512kbps_30fps_mpeg2_2b.mp4", CODEC_ALL},
-                {MediaFormat.MIMETYPE_VIDEO_MPEG4, "bbb_176x144_192kbps_15fps_mpeg4.mp4", CODEC_ALL},
+                {MediaFormat.MIMETYPE_VIDEO_MPEG2, "bbb_640x360_512kbps_30fps_mpeg2_2b.mp4",
+                        CODEC_ALL},
+                {MediaFormat.MIMETYPE_VIDEO_MPEG4, "bbb_176x144_192kbps_15fps_mpeg4.mp4",
+                        CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_VP8, "bbb_640x360_512kbps_30fps_vp8.webm", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_cif_768kbps_30fps_vp9.mkv", CODEC_ALL},
         });
@@ -78,16 +81,7 @@
         ArrayList<MediaFormat> formats = new ArrayList<>();
         formats.add(setUpSource(mTestFile));
         mExtractor.release();
-        if (!areFormatsSupported(mCodecName, mMime, formats)) {
-            if (mSupport == CODEC_ALL) {
-                fail("format(s) not supported by component: " + mCodecName + " for mime : " +
-                        mMime);
-            }
-            if (mSupport != CODEC_OPTIONAL && selectCodecs(mMime, formats, null, false).isEmpty()) {
-                fail("format(s) not supported by any component for mime : " + mMime);
-            }
-            return;
-        }
+        checkFormatSupport(mCodecName, mMime, formats, null, mSupportRequirements);
         final boolean isAsync = true;
         MediaFormat format = setUpSource(mTestFile);
         {
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
index bea8487..0dc1e95 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
@@ -22,10 +22,12 @@
 import android.util.Log;
 import android.view.Surface;
 
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.filters.LargeTest;
-import androidx.test.rule.ActivityTestRule;
 
+import org.junit.After;
 import org.junit.Assume;
+import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
@@ -33,10 +35,12 @@
 import org.junit.runners.Parameterized;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 
+import static android.mediav2.cts.CodecTestBase.SupportClass.*;
 import static org.junit.Assert.assertTrue;
 
 @RunWith(Parameterized.class)
@@ -44,11 +48,13 @@
     private static final String LOG_TAG = CodecDecoderSurfaceTest.class.getSimpleName();
 
     private final String mReconfigFile;
+    private final SupportClass mSupportRequirements;
 
     public CodecDecoderSurfaceTest(String decoder, String mime, String testFile,
-            String reconfigFile) {
+            String reconfigFile, SupportClass supportRequirements) {
         super(decoder, mime, testFile);
         mReconfigFile = reconfigFile;
+        mSupportRequirements = supportRequirements;
     }
 
     void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
@@ -86,49 +92,66 @@
     }
 
     @Rule
-    public ActivityTestRule<CodecTestActivity> mActivityRule =
-            new ActivityTestRule<>(CodecTestActivity.class);
+    public ActivityScenarioRule<CodecTestActivity> mActivityRule =
+            new ActivityScenarioRule<>(CodecTestActivity.class);
+
+    @Before
+    public void setUp() throws IOException, InterruptedException {
+        MediaFormat format = setUpSource(mTestFile);
+        mExtractor.release();
+        ArrayList<MediaFormat> formatList = new ArrayList<>();
+        formatList.add(format);
+        checkFormatSupport(mCodecName, mMime, formatList, null, mSupportRequirements);
+        mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
+        setUpSurface(mActivity);
+    }
+
+    @After
+    public void tearDown() {
+        tearDownSurface();
+    }
 
     @Parameterized.Parameters(name = "{index}({0}_{1})")
     public static Collection<Object[]> input() {
         final boolean isEncoder = false;
         final boolean needAudio = false;
         final boolean needVideo = true;
+        // mediaType, test file, reconfig test file, SupportClass
         final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
                 {MediaFormat.MIMETYPE_VIDEO_MPEG2, "bbb_340x280_768kbps_30fps_mpeg2.mp4",
-                        "bbb_520x390_1mbps_30fps_mpeg2.mp4"},
+                        "bbb_520x390_1mbps_30fps_mpeg2.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_MPEG2,
                         "bbb_512x288_30fps_1mbps_mpeg2_interlaced_nob_2fields.mp4",
-                        "bbb_520x390_1mbps_30fps_mpeg2.mp4"},
+                        "bbb_520x390_1mbps_30fps_mpeg2.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_MPEG2,
                         "bbb_512x288_30fps_1mbps_mpeg2_interlaced_nob_1field.ts",
-                        "bbb_520x390_1mbps_30fps_mpeg2.mp4"},
+                        "bbb_520x390_1mbps_30fps_mpeg2.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_340x280_768kbps_30fps_avc.mp4",
-                        "bbb_520x390_1mbps_30fps_avc.mp4"},
+                        "bbb_520x390_1mbps_30fps_avc.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_360x640_768kbps_30fps_avc.mp4",
-                        "bbb_520x390_1mbps_30fps_avc.mp4"},
+                        "bbb_520x390_1mbps_30fps_avc.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_160x1024_1500kbps_30fps_avc.mp4",
-                        "bbb_520x390_1mbps_30fps_avc.mp4"},
+                        "bbb_520x390_1mbps_30fps_avc.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1280x120_1500kbps_30fps_avc.mp4",
-                        "bbb_340x280_768kbps_30fps_avc.mp4"},
+                        "bbb_340x280_768kbps_30fps_avc.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_520x390_1mbps_30fps_hevc.mp4",
-                        "bbb_340x280_768kbps_30fps_hevc.mp4"},
+                        "bbb_340x280_768kbps_30fps_hevc.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_MPEG4, "bbb_128x96_64kbps_12fps_mpeg4.mp4",
-                        "bbb_176x144_192kbps_15fps_mpeg4.mp4"},
+                        "bbb_176x144_192kbps_15fps_mpeg4.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_H263, "bbb_176x144_128kbps_15fps_h263.3gp",
-                        "bbb_176x144_192kbps_10fps_h263.3gp"},
+                        "bbb_176x144_192kbps_10fps_h263.3gp", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_VP8, "bbb_340x280_768kbps_30fps_vp8.webm",
-                        "bbb_520x390_1mbps_30fps_vp8.webm"},
+                        "bbb_520x390_1mbps_30fps_vp8.webm", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_340x280_768kbps_30fps_vp9.webm",
-                        "bbb_520x390_1mbps_30fps_vp9.webm"},
+                        "bbb_520x390_1mbps_30fps_vp9.webm", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_VP9,
                         "bbb_340x280_768kbps_30fps_split_non_display_frame_vp9.webm",
-                        "bbb_520x390_1mbps_30fps_split_non_display_frame_vp9.webm"},
+                        "bbb_520x390_1mbps_30fps_split_non_display_frame_vp9.webm", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_340x280_768kbps_30fps_av1.mp4",
-                        "bbb_520x390_1mbps_30fps_av1.mp4"},
+                        "bbb_520x390_1mbps_30fps_av1.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_AV1,
                         "bikes_qcif_color_bt2020_smpte2086Hlg_bt2020Ncl_fr_av1.mp4",
-                        "bbb_520x390_1mbps_30fps_av1.mp4"},
+                        "bbb_520x390_1mbps_30fps_av1.mp4", CODEC_ALL},
         });
         return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, true);
     }
@@ -145,8 +168,6 @@
         OutputManager test = new OutputManager();
         final long pts = 0;
         final int mode = MediaExtractor.SEEK_TO_CLOSEST_SYNC;
-        CodecTestActivity activity = mActivityRule.getActivity();
-        setUpSurface(activity);
         {
             decodeAndSavePts(mTestFile, mCodecName, pts, mode, Integer.MAX_VALUE);
             ref = mOutputBuff;
@@ -158,7 +179,7 @@
             }
             MediaFormat format = setUpSource(mTestFile);
             mCodec = MediaCodec.createByCodecName(mCodecName);
-            activity.setScreenParams(getWidth(format), getHeight(format), true);
+            mActivity.setScreenParams(getWidth(format), getHeight(format), true);
             for (boolean isAsync : boolStates) {
                 String log = String.format("codec: %s, file: %s, mode: %s:: ", mCodecName,
                         mTestFile, (isAsync ? "async" : "sync"));
@@ -187,7 +208,6 @@
             mCodec.release();
             mExtractor.release();
         }
-        tearDownSurface();
     }
 
     /**
@@ -211,8 +231,6 @@
         final int mode = MediaExtractor.SEEK_TO_CLOSEST_SYNC;
         boolean[] boolStates = {true, false};
         OutputManager test = new OutputManager();
-        CodecTestActivity activity = mActivityRule.getActivity();
-        setUpSurface(activity);
         {
             decodeAndSavePts(mTestFile, mCodecName, pts, mode, Integer.MAX_VALUE);
             OutputManager ref = mOutputBuff;
@@ -225,7 +243,7 @@
             mOutputBuff = test;
             setUpSource(mTestFile);
             mCodec = MediaCodec.createByCodecName(mCodecName);
-            activity.setScreenParams(getWidth(format), getHeight(format), false);
+            mActivity.setScreenParams(getWidth(format), getHeight(format), false);
             for (boolean isAsync : boolStates) {
                 String log = String.format("decoder: %s, input file: %s, mode: %s:: ", mCodecName,
                         mTestFile, (isAsync ? "async" : "sync"));
@@ -293,7 +311,6 @@
             mCodec.release();
             mExtractor.release();
         }
-        tearDownSurface();
     }
 
     /**
@@ -309,12 +326,13 @@
         mExtractor.release();
         MediaFormat newFormat = setUpSource(mReconfigFile);
         mExtractor.release();
+        ArrayList<MediaFormat> formatList = new ArrayList<>();
+        formatList.add(newFormat);
+        checkFormatSupport(mCodecName, mMime, formatList, null, mSupportRequirements);
         final long pts = 500000;
         final int mode = MediaExtractor.SEEK_TO_CLOSEST_SYNC;
         boolean[] boolStates = {true, false};
         OutputManager test = new OutputManager();
-        CodecTestActivity activity = mActivityRule.getActivity();
-        setUpSurface(activity);
         {
             decodeAndSavePts(mTestFile, mCodecName, pts, mode, Integer.MAX_VALUE);
             OutputManager ref = mOutputBuff;
@@ -332,7 +350,7 @@
             }
             mOutputBuff = test;
             mCodec = MediaCodec.createByCodecName(mCodecName);
-            activity.setScreenParams(getWidth(format), getHeight(format), false);
+            mActivity.setScreenParams(getWidth(format), getHeight(format), false);
             for (boolean isAsync : boolStates) {
                 setUpSource(mTestFile);
                 String log = String.format("decoder: %s, input file: %s, mode: %s:: ", mCodecName,
@@ -397,7 +415,7 @@
                 setUpSource(mReconfigFile);
                 log = String.format("decoder: %s, input file: %s, mode: %s:: ", mCodecName,
                         mReconfigFile, (isAsync ? "async" : "sync"));
-                activity.setScreenParams(getWidth(newFormat), getHeight(newFormat), true);
+                mActivity.setScreenParams(getWidth(newFormat), getHeight(newFormat), true);
                 reConfigureCodec(newFormat, isAsync, false, false);
                 mCodec.start();
                 test.reset();
@@ -422,7 +440,6 @@
             }
             mCodec.release();
         }
-        tearDownSurface();
     }
 
     private native boolean nativeTestSimpleDecode(String decoder, Surface surface, String mime,
@@ -430,17 +447,12 @@
 
     @LargeTest
     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    public void testSimpleDecodeToSurfaceNative() throws IOException, InterruptedException {
+    public void testSimpleDecodeToSurfaceNative() throws IOException {
         MediaFormat format = setUpSource(mTestFile);
         mExtractor.release();
-        CodecTestActivity activity = mActivityRule.getActivity();
-        setUpSurface(activity);
-        activity.setScreenParams(getWidth(format), getHeight(format), false);
-        {
-            assertTrue(nativeTestSimpleDecode(mCodecName, mSurface, mMime, mInpPrefix + mTestFile,
-                    mInpPrefix + mReconfigFile, -1.0f, 0L));
-        }
-        tearDownSurface();
+        mActivity.setScreenParams(getWidth(format), getHeight(format), false);
+        assertTrue(nativeTestSimpleDecode(mCodecName, mSurface, mMime, mInpPrefix + mTestFile,
+                mInpPrefix + mReconfigFile, -1.0f, 0L));
     }
 
     private native boolean nativeTestFlush(String decoder, Surface surface, String mime,
@@ -448,15 +460,10 @@
 
     @LargeTest
     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    public void testFlushNative() throws IOException, InterruptedException {
+    public void testFlushNative() throws IOException {
         MediaFormat format = setUpSource(mTestFile);
         mExtractor.release();
-        CodecTestActivity activity = mActivityRule.getActivity();
-        setUpSurface(activity);
-        activity.setScreenParams(getWidth(format), getHeight(format), true);
-        {
-            assertTrue(nativeTestFlush(mCodecName, mSurface, mMime, mInpPrefix + mTestFile));
-        }
-        tearDownSurface();
+        mActivity.setScreenParams(getWidth(format), getHeight(format), true);
+        assertTrue(nativeTestFlush(mCodecName, mSurface, mMime, mInpPrefix + mTestFile));
     }
 }
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
index 16faa41..072222b 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
@@ -27,6 +27,7 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Assume;
+import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -43,6 +44,7 @@
 import java.util.Collection;
 import java.util.List;
 
+import static android.mediav2.cts.CodecTestBase.SupportClass.*;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
@@ -64,14 +66,16 @@
     private final String mReconfigFile;
     private final float mRmsError;
     private final long mRefCRC;
+    private final SupportClass mSupportRequirements;
 
     public CodecDecoderTest(String decoder, String mime, String testFile, String refFile,
-            String reconfigFile, float rmsError, long refCRC) {
+            String reconfigFile, float rmsError, long refCRC, SupportClass supportRequirements) {
         super(decoder, mime, testFile);
         mRefFile = refFile;
         mReconfigFile = reconfigFile;
         mRmsError = rmsError;
         mRefCRC = refCRC;
+        mSupportRequirements = supportRequirements;
     }
 
     static short[] setUpAudioReference(String file) throws IOException {
@@ -129,53 +133,61 @@
         final boolean isEncoder = false;
         final boolean needAudio = true;
         final boolean needVideo = true;
-        // mime, testClip, referenceClip, reconfigureTestClip, refRmsError, refCRC32
+        // mediaType, testClip, referenceClip, reconfigureTestClip, refRmsError, refCRC32,
+        // SupportClass
         final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
                 {MediaFormat.MIMETYPE_AUDIO_MPEG, "bbb_1ch_8kHz_lame_cbr.mp3",
-                        "bbb_1ch_8kHz_s16le.raw", "bbb_2ch_44kHz_lame_vbr.mp3", 91.022f, -1L},
+                        "bbb_1ch_8kHz_s16le.raw", "bbb_2ch_44kHz_lame_vbr.mp3", 91.022f, -1L,
+                        CODEC_ALL},
                 {MediaFormat.MIMETYPE_AUDIO_MPEG, "bbb_2ch_44kHz_lame_cbr.mp3",
-                        "bbb_2ch_44kHz_s16le.raw", "bbb_1ch_16kHz_lame_vbr.mp3", 103.60f, -1L},
+                        "bbb_2ch_44kHz_s16le.raw", "bbb_1ch_16kHz_lame_vbr.mp3", 103.60f, -1L,
+                        CODEC_ALL},
                 {MediaFormat.MIMETYPE_AUDIO_AMR_WB, "bbb_1ch_16kHz_16kbps_amrwb.3gp",
                         "bbb_1ch_16kHz_s16le.raw", "bbb_1ch_16kHz_23kbps_amrwb.3gp", 2393.598f,
-                        -1L},
+                        -1L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_AUDIO_AMR_NB, "bbb_1ch_8kHz_10kbps_amrnb.3gp",
-                        "bbb_1ch_8kHz_s16le.raw", "bbb_1ch_8kHz_8kbps_amrnb.3gp", -1.0f, -1L},
+                        "bbb_1ch_8kHz_s16le.raw", "bbb_1ch_8kHz_8kbps_amrnb.3gp", -1.0f, -1L,
+                        CODEC_ALL},
                 {MediaFormat.MIMETYPE_AUDIO_FLAC, "bbb_1ch_16kHz_flac.mka",
-                        "bbb_1ch_16kHz_s16le.raw", "bbb_2ch_44kHz_flac.mka", 0.0f, -1L},
+                        "bbb_1ch_16kHz_s16le.raw", "bbb_2ch_44kHz_flac.mka", 0.0f, -1L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_AUDIO_FLAC, "bbb_2ch_44kHz_flac.mka",
-                        "bbb_2ch_44kHz_s16le.raw", "bbb_1ch_16kHz_flac.mka", 0.0f, -1L},
+                        "bbb_2ch_44kHz_s16le.raw", "bbb_1ch_16kHz_flac.mka", 0.0f, -1L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_AUDIO_RAW, "bbb_1ch_16kHz.wav", "bbb_1ch_16kHz_s16le.raw",
-                        "bbb_2ch_44kHz.wav", 0.0f, -1L},
+                        "bbb_2ch_44kHz.wav", 0.0f, -1L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_AUDIO_RAW, "bbb_2ch_44kHz.wav", "bbb_2ch_44kHz_s16le.raw",
-                        "bbb_1ch_16kHz.wav", 0.0f, -1L},
+                        "bbb_1ch_16kHz.wav", 0.0f, -1L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_AUDIO_G711_ALAW, "bbb_1ch_8kHz_alaw.wav",
-                        "bbb_1ch_8kHz_s16le.raw", "bbb_2ch_8kHz_alaw.wav", 23.08678f, -1L},
+                        "bbb_1ch_8kHz_s16le.raw", "bbb_2ch_8kHz_alaw.wav", 23.08678f, -1L,
+                        CODEC_ALL},
                 {MediaFormat.MIMETYPE_AUDIO_G711_MLAW, "bbb_1ch_8kHz_mulaw.wav",
-                        "bbb_1ch_8kHz_s16le.raw", "bbb_2ch_8kHz_mulaw.wav", 24.4131f, -1L},
+                        "bbb_1ch_8kHz_s16le.raw", "bbb_2ch_8kHz_mulaw.wav", 24.4131f, -1L,
+                        CODEC_ALL},
                 {MediaFormat.MIMETYPE_AUDIO_MSGSM, "bbb_1ch_8kHz_gsm.wav",
-                        "bbb_1ch_8kHz_s16le.raw", "bbb_1ch_8kHz_gsm.wav", 946.02698f, -1L},
+                        "bbb_1ch_8kHz_s16le.raw", "bbb_1ch_8kHz_gsm.wav", 946.02698f, -1L,
+                        CODEC_ALL},
                 {MediaFormat.MIMETYPE_AUDIO_VORBIS, "bbb_1ch_16kHz_vorbis.mka",
-                        "bbb_1ch_8kHz_s16le.raw", "bbb_2ch_44kHz_vorbis.mka", -1.0f, -1L},
+                        "bbb_1ch_8kHz_s16le.raw", "bbb_2ch_44kHz_vorbis.mka", -1.0f, -1L,
+                        CODEC_ALL},
                 {MediaFormat.MIMETYPE_AUDIO_OPUS, "bbb_2ch_48kHz_opus.mka",
-                        "bbb_2ch_48kHz_s16le.raw", "bbb_1ch_48kHz_opus.mka", -1.0f, -1L},
+                        "bbb_2ch_48kHz_s16le.raw", "bbb_1ch_48kHz_opus.mka", -1.0f, -1L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_AUDIO_AAC, "bbb_1ch_16kHz_aac.mp4",
-                        "bbb_1ch_16kHz_s16le.raw", "bbb_2ch_44kHz_aac.mp4", -1.0f, -1L},
+                        "bbb_1ch_16kHz_s16le.raw", "bbb_2ch_44kHz_aac.mp4", -1.0f, -1L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_MPEG2, "bbb_340x280_768kbps_30fps_mpeg2.mp4", null,
-                        "bbb_520x390_1mbps_30fps_mpeg2.mp4", -1.0f, -1L},
+                        "bbb_520x390_1mbps_30fps_mpeg2.mp4", -1.0f, -1L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_340x280_768kbps_30fps_avc.mp4", null,
-                        "bbb_520x390_1mbps_30fps_avc.mp4", -1.0f, 1746312400L},
+                        "bbb_520x390_1mbps_30fps_avc.mp4", -1.0f, 1746312400L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_520x390_1mbps_30fps_hevc.mp4", null,
-                        "bbb_340x280_768kbps_30fps_hevc.mp4", -1.0f, 3061322606L},
+                        "bbb_340x280_768kbps_30fps_hevc.mp4", -1.0f, 3061322606L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_MPEG4, "bbb_128x96_64kbps_12fps_mpeg4.mp4",
-                        null, "bbb_176x144_192kbps_15fps_mpeg4.mp4", -1.0f, -1L},
+                        null, "bbb_176x144_192kbps_15fps_mpeg4.mp4", -1.0f, -1L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_H263, "bbb_176x144_128kbps_15fps_h263.3gp",
-                        null, "bbb_176x144_192kbps_10fps_h263.3gp", -1.0f, -1L},
+                        null, "bbb_176x144_192kbps_10fps_h263.3gp", -1.0f, -1L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_VP8, "bbb_340x280_768kbps_30fps_vp8.webm", null,
-                        "bbb_520x390_1mbps_30fps_vp8.webm", -1.0f, 2030620796L},
+                        "bbb_520x390_1mbps_30fps_vp8.webm", -1.0f, 2030620796L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_340x280_768kbps_30fps_vp9.webm", null,
-                        "bbb_520x390_1mbps_30fps_vp9.webm", -1.0f, 4122701060L},
+                        "bbb_520x390_1mbps_30fps_vp9.webm", -1.0f, 4122701060L, CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_340x280_768kbps_30fps_av1.mp4", null,
-                        "bbb_520x390_1mbps_30fps_av1.mp4", -1.0f, 400672933L},
+                        "bbb_520x390_1mbps_30fps_av1.mp4", -1.0f, 400672933L, CODEC_ALL},
         });
         return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, true);
     }
@@ -196,6 +208,15 @@
         }
     }
 
+    @Before
+    public void setUp() throws IOException {
+        MediaFormat format = setUpSource(mTestFile);
+        mExtractor.release();
+        ArrayList<MediaFormat> formatList = new ArrayList<>();
+        formatList.add(format);
+        checkFormatSupport(mCodecName, mMime, formatList, null, mSupportRequirements);
+    }
+
     /**
      * Tests decoder for combinations:
      * 1. Codec Sync Mode, Signal Eos with Last frame
@@ -419,6 +440,9 @@
         mExtractor.release();
         MediaFormat newFormat = setUpSource(mReconfigFile);
         mExtractor.release();
+        ArrayList<MediaFormat> formatList = new ArrayList<>();
+        formatList.add(newFormat);
+        checkFormatSupport(mCodecName, mMime, formatList, null, mSupportRequirements);
         final long startTs = 0;
         final long seekTs = 500000;
         final int mode = MediaExtractor.SEEK_TO_CLOSEST_SYNC;
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java
index 5819bfb..4dd9923 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java
@@ -31,8 +31,8 @@
 import java.util.Collection;
 import java.util.List;
 
+import static android.mediav2.cts.CodecTestBase.SupportClass.*;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 /**
  * The following test validates decoder for the given input clip. For audio components, we check
@@ -50,16 +50,16 @@
     private final String mRefFile;
     private final float mRmsError;
     private final long mRefCRC;
-    private final int mSupport;
+    private final SupportClass mSupportRequirements;
 
     public CodecDecoderValidationTest(String decoder, String mime, String[] srcFiles,
-            String refFile, float rmsError, long refCRC, int support) {
+            String refFile, float rmsError, long refCRC, SupportClass supportRequirements) {
         super(decoder, mime, null);
         mSrcFiles = srcFiles;
         mRefFile = refFile;
         mRmsError = rmsError;
         mRefCRC = refCRC;
-        mSupport = support;
+        mSupportRequirements = supportRequirements;
     }
 
     @Parameterized.Parameters(name = "{index}({0}_{1})")
@@ -67,8 +67,8 @@
         final boolean isEncoder = false;
         final boolean needAudio = true;
         final boolean needVideo = true;
-        // mime, array list of test files (underlying elementary stream is same, except they
-        // are placed in different containers), ref file, rms error, checksum
+        // mediaType, array list of test files (underlying elementary stream is same, except they
+        // are placed in different containers), ref file, rms error, checksum, SupportClass
         final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
                 // vp9 test vectors with no-show frames signalled in alternate ways
                 {MediaFormat.MIMETYPE_VIDEO_VP9, new String[]{
@@ -471,19 +471,7 @@
             formats.add(setUpSource(file));
             mExtractor.release();
         }
-        if (!areFormatsSupported(mCodecName, mMime, formats)) {
-            if (mSupport == CODEC_ALL) {
-                fail("format(s) not supported by component: " + mCodecName + " for mime : " +
-                        mMime);
-            } else if (mSupport == CODEC_ANY && selectCodecs(mMime, formats, null,
-                    false).isEmpty()) {
-                fail("format(s) not supported by any component for mime : " + mMime);
-            } else if (mSupport == CODEC_DEFAULT && isDefaultCodec(mCodecName, mMime, false)) {
-                fail("format(s) not supported by " + mCodecName
-                        + " which is a default codec for mime : " + mMime);
-            }
-            return;
-        }
+        checkFormatSupport(mCodecName, mMime, formats, null, mSupportRequirements);
         final int mode = MediaExtractor.SEEK_TO_CLOSEST_SYNC;
         {
             OutputManager ref = null;
diff --git a/tests/media/src/android/mediav2/cts/CodecListTest.java b/tests/media/src/android/mediav2/cts/CodecListTest.java
index 07bf4ac..04568f8 100644
--- a/tests/media/src/android/mediav2/cts/CodecListTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecListTest.java
@@ -21,6 +21,8 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -52,8 +54,8 @@
                                         CodecTestBase.hasDecoder(mime));
             }
         }
-        if (CodecTestBase.hasCamera()) {
-            assertTrue("device doesn't support either VP8 or AVC video encoders",
+        if (MediaUtils.hasCamera()) {
+            assertTrue("device has neither VP8 or AVC encoding",
                     CodecTestBase.hasEncoder(MediaFormat.MIMETYPE_VIDEO_AVC) ||
                             CodecTestBase.hasEncoder(MediaFormat.MIMETYPE_VIDEO_VP8));
         }
diff --git a/tests/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index c22b896..9cd7fe6 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -38,6 +38,7 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.Assert;
+import org.junit.Assume;
 import org.junit.Before;
 
 import java.io.File;
@@ -60,6 +61,7 @@
 import java.util.zip.CRC32;
 
 import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.MediaUtils;
 
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
@@ -512,6 +514,12 @@
 abstract class CodecTestBase {
     public static final boolean IS_AT_LEAST_R = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
     private static final String LOG_TAG = CodecTestBase.class.getSimpleName();
+    enum SupportClass {
+        CODEC_ALL, // All codecs must support
+        CODEC_ANY, // At least one codec must support
+        CODEC_DEFAULT, // Default codec must support
+        CODEC_OPTIONAL // Codec support is optional
+    }
 
     static final String CODEC_PREFIX_KEY = "codec-prefix";
     static final String MIME_SEL_KEY = "mime-sel";
@@ -522,10 +530,6 @@
     static final int PER_TEST_TIMEOUT_LARGE_TEST_MS = 300000;
     static final int PER_TEST_TIMEOUT_SMALL_TEST_MS = 60000;
     static final int UNSPECIFIED = 0;
-    static final int CODEC_ALL = 0; // All codecs must support
-    static final int CODEC_ANY = 1; // At least one codec must support
-    static final int CODEC_DEFAULT = 2; // Default codec must support
-    static final int CODEC_OPTIONAL = 3; // Codec support is optional
     // 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
@@ -584,41 +588,6 @@
         codecPrefix = args.getString(CODEC_PREFIX_KEY);
     }
 
-    static boolean isTv() {
-        return pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
-    }
-
-    static boolean hasMicrophone() {
-        return pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE);
-    }
-
-    static boolean hasCamera() {
-        return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
-    }
-
-    static boolean isWatch() {
-        return pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
-    }
-
-    static boolean isAutomotive() {
-        return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
-    }
-
-    static boolean isPc() {
-        return pm.hasSystemFeature(PackageManager.FEATURE_PC);
-    }
-
-    static boolean hasAudioOutput() {
-        return pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
-    }
-
-    static boolean isHandheld() {
-        // handheld nature is not exposed to package manager, for now
-        // we check for touchscreen and NOT watch and NOT tv and NOT pc
-        return pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN) && !isWatch() && !isTv() &&
-                !isAutomotive() && !isPc();
-    }
-
     static boolean hasDecoder(String mime) {
         return CodecTestBase.selectCodecs(mime, null, null, false).size() != 0;
     }
@@ -627,6 +596,31 @@
         return CodecTestBase.selectCodecs(mime, null, null, true).size() != 0;
     }
 
+    public static void checkFormatSupport(String codecName, String mime,
+            ArrayList<MediaFormat> formats, String[] features, SupportClass supportRequirements)
+            throws IOException {
+        if (!areFormatsSupported(codecName, mime, formats)) {
+            switch (supportRequirements) {
+                case CODEC_ALL:
+                    fail("format(s) not supported by codec: " + codecName + " for mime : " + mime);
+                    break;
+                case CODEC_ANY:
+                    if (selectCodecs(mime, formats, features, false).isEmpty())
+                        fail("format(s) not supported by any component for mime : " + mime);
+                    break;
+                case CODEC_DEFAULT:
+                    if (isDefaultCodec(codecName, mime, false))
+                        fail("format(s) not supported by default codec : " + codecName +
+                                "for mime : " + mime);
+                    break;
+                case CODEC_OPTIONAL:
+                default:
+                    Assume.assumeTrue("format(s) not supported by codec: " + codecName +
+                            " for mime : " + mime, false);
+            }
+        }
+    }
+
     static boolean isFeatureSupported(String name, String mime, String feature) throws IOException {
         MediaCodec codec = MediaCodec.createByCodecName(name);
         MediaCodecInfo.CodecCapabilities codecCapabilities =
@@ -637,38 +631,39 @@
     }
 
     static boolean doesAnyFormatHaveHDRProfile(String mime, ArrayList<MediaFormat> formats) {
-        boolean isHDR = false;
         for (MediaFormat format : formats) {
             assertEquals(mime, format.getString(MediaFormat.KEY_MIME));
-            if (mime.equals(MediaFormat.MIMETYPE_VIDEO_AVC)) {
-                int profile = format.getInteger(MediaFormat.KEY_PROFILE);
-                if (profile == AVCProfileHigh10 || profile == AVCProfileHigh422 ||
-                        profile == AVCProfileHigh444) {
-                    isHDR = true;
-                    break;
+            switch (mime) {
+                case MediaFormat.MIMETYPE_VIDEO_AVC: {
+                    int profile = format.getInteger(MediaFormat.KEY_PROFILE);
+                    if (profile == AVCProfileHigh10 || profile == AVCProfileHigh422 ||
+                            profile == AVCProfileHigh444) {
+                        return true;
+                    }
                 }
-            } else if (mime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
-                int profile = format.getInteger(MediaFormat.KEY_PROFILE, VP9Profile0);
-                if (profile == VP9Profile2HDR || profile == VP9Profile3HDR ||
-                        profile == VP9Profile2HDR10Plus || profile == VP9Profile3HDR10Plus) {
-                    isHDR = true;
-                    break;
+                case MediaFormat.MIMETYPE_VIDEO_VP9: {
+                    int profile = format.getInteger(MediaFormat.KEY_PROFILE, VP9Profile0);
+                    if (profile == VP9Profile2HDR || profile == VP9Profile3HDR ||
+                            profile == VP9Profile2HDR10Plus || profile == VP9Profile3HDR10Plus) {
+                        return true;
+                    }
                 }
-            } else if (mime.equals(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
-                int profile = format.getInteger(MediaFormat.KEY_PROFILE, HEVCProfileMain);
-                if (profile == HEVCProfileMain10HDR10 || profile == HEVCProfileMain10HDR10Plus) {
-                    isHDR = true;
-                    break;
+                case MediaFormat.MIMETYPE_VIDEO_HEVC: {
+                    int profile = format.getInteger(MediaFormat.KEY_PROFILE, HEVCProfileMain);
+                    if (profile == HEVCProfileMain10HDR10 ||
+                            profile == HEVCProfileMain10HDR10Plus) {
+                        return true;
+                    }
                 }
-            } else if (mime.equals(MediaFormat.MIMETYPE_VIDEO_AV1)) {
-                int profile = format.getInteger(MediaFormat.KEY_PROFILE, AV1ProfileMain8);
-                if (profile == AV1ProfileMain10HDR10 || profile == AV1ProfileMain10HDR10Plus) {
-                    isHDR = true;
-                    break;
+                case MediaFormat.MIMETYPE_VIDEO_AV1: {
+                    int profile = format.getInteger(MediaFormat.KEY_PROFILE, AV1ProfileMain8);
+                    if (profile == AV1ProfileMain10HDR10 || profile == AV1ProfileMain10HDR10Plus) {
+                        return true;
+                    }
                 }
             }
         }
-        return isHDR;
+        return false;
     }
 
     static boolean canDisplaySupportHDRContent() {
@@ -710,7 +705,7 @@
             boolean needVideo) {
         Set<String> list = new HashSet<>();
         if (!isEncoder) {
-            if (hasAudioOutput() && needAudio) {
+            if (MediaUtils.hasAudioOutput() && needAudio) {
                 // sec 5.1.2
                 list.add(MediaFormat.MIMETYPE_AUDIO_AAC);
                 list.add(MediaFormat.MIMETYPE_AUDIO_FLAC);
@@ -719,7 +714,8 @@
                 list.add(MediaFormat.MIMETYPE_AUDIO_RAW);
                 list.add(MediaFormat.MIMETYPE_AUDIO_OPUS);
             }
-            if (isHandheld() || isTv() || isAutomotive()) {
+            if (MediaUtils.isHandheld() || MediaUtils.isTablet() || MediaUtils.isTv() ||
+                    MediaUtils.isAutomotive()) {
                 // sec 2.2.2, 2.3.2, 2.5.2
                 if (needAudio) {
                     list.add(MediaFormat.MIMETYPE_AUDIO_AAC);
@@ -732,7 +728,7 @@
                     list.add(MediaFormat.MIMETYPE_VIDEO_VP9);
                 }
             }
-            if (isHandheld()) {
+            if (MediaUtils.isHandheld() || MediaUtils.isTablet()) {
                 // sec 2.2.2
                 if (needAudio) {
                     list.add(MediaFormat.MIMETYPE_AUDIO_AMR_NB);
@@ -742,20 +738,21 @@
                     list.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
                 }
             }
-            if (isTv() && needVideo) {
+            if (MediaUtils.isTv() && needVideo) {
                 // sec 2.3.2
                 list.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
                 list.add(MediaFormat.MIMETYPE_VIDEO_MPEG2);
             }
         } else {
-            if (hasMicrophone() && needAudio) {
+            if (MediaUtils.hasMicrophone() && needAudio) {
                 // sec 5.1.1
                 // TODO(b/154423550)
                 // list.add(MediaFormat.MIMETYPE_AUDIO_RAW);
                 list.add(MediaFormat.MIMETYPE_AUDIO_FLAC);
                 list.add(MediaFormat.MIMETYPE_AUDIO_OPUS);
             }
-            if (isHandheld() || isTv() || isAutomotive()) {
+            if (MediaUtils.isHandheld() || MediaUtils.isTablet() || MediaUtils.isTv() ||
+                    MediaUtils.isAutomotive()) {
                 // sec 2.2.2, 2.3.2, 2.5.2
                 if (needAudio) {
                     list.add(MediaFormat.MIMETYPE_AUDIO_AAC);
@@ -765,7 +762,7 @@
                     list.add(MediaFormat.MIMETYPE_VIDEO_VP8);
                 }
             }
-            if (isHandheld() && needAudio) {
+            if ((MediaUtils.isHandheld() || MediaUtils.isTablet()) && needAudio) {
                 // sec 2.2.2
                 list.add(MediaFormat.MIMETYPE_AUDIO_AMR_NB);
                 list.add(MediaFormat.MIMETYPE_AUDIO_AMR_WB);
@@ -794,11 +791,14 @@
                     }
                 }
             }
-            // TODO(b/154423708): add checks for video o/p port and display length >= 2.5"
+            // feature_video_output is not exposed to package manager. Testing for video output
+            // ports, such as VGA, HDMI, DisplayPort, or a wireless port for display is also not
+            // direct.
             /* sec 5.2: device implementations include an embedded screen display with the
-            diagonal length of at least 2.5inches or include a video output port or declare the
+            diagonal length of at least 2.5 inches or include a video output port or declare the
             support of a camera */
-            if (isEncoder && hasCamera() && needVideo &&
+            if (isEncoder && needVideo &&
+                    (MediaUtils.hasCamera() || MediaUtils.getScreenSizeInInches() >= 2.5) &&
                     !mimes.contains(MediaFormat.MIMETYPE_VIDEO_AVC) &&
                     !mimes.contains(MediaFormat.MIMETYPE_VIDEO_VP8)) {
                 // Add required cdd mimes here so that respective codec tests fail.
@@ -1179,6 +1179,7 @@
     private ByteBuffer flatBuffer = ByteBuffer.allocate(4 * Integer.BYTES);
 
     MediaExtractor mExtractor;
+    CodecTestActivity mActivity;
 
     CodecDecoderTestBase(String codecName, String mime, String testFile) {
         mCodecName = codecName;
diff --git a/tests/media/src/android/mediav2/cts/DecoderColorAspectsTest.java b/tests/media/src/android/mediav2/cts/DecoderColorAspectsTest.java
index 15f5e65..4ffa782 100644
--- a/tests/media/src/android/mediav2/cts/DecoderColorAspectsTest.java
+++ b/tests/media/src/android/mediav2/cts/DecoderColorAspectsTest.java
@@ -18,10 +18,12 @@
 
 import android.media.MediaFormat;
 
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.filters.SmallTest;
-import androidx.test.rule.ActivityTestRule;
 
+import org.junit.After;
 import org.junit.Assume;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -40,6 +42,7 @@
     private final int mColorStandard;
     private final int mColorTransferCurve;
     private final boolean mCanIgnoreColorBox;
+
     private ArrayList<String> mCheckESList;
 
     public DecoderColorAspectsTest(String decoderName, String mime, String testFile, int range,
@@ -235,8 +238,19 @@
     }
 
     @Rule
-    public ActivityTestRule<CodecTestActivity> mActivityRule =
-            new ActivityTestRule<>(CodecTestActivity.class);
+    public ActivityScenarioRule<CodecTestActivity> mActivityRule =
+            new ActivityScenarioRule<>(CodecTestActivity.class);
+
+    @Before
+    public void setUp() throws IOException, InterruptedException {
+        mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
+        setUpSurface(mActivity);
+    }
+
+    @After
+    public void tearDown() {
+        tearDownSurface();
+    }
 
     @SmallTest
     @Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
@@ -249,9 +263,7 @@
         if (doesAnyFormatHaveHDRProfile(mMime, formats)) {
             Assume.assumeTrue(canDisplaySupportHDRContent());
         }
-        CodecTestActivity activity = mActivityRule.getActivity();
-        setUpSurface(activity);
-        activity.setScreenParams(getWidth(format), getHeight(format), true);
+        mActivity.setScreenParams(getWidth(format), getHeight(format), true);
         {
             validateColorAspects(mCodecName, mInpPrefix, mTestFile, mColorRange, mColorStandard,
                     mColorTransferCurve, false);
@@ -262,6 +274,5 @@
                         mColorStandard, mColorTransferCurve, true);
             }
         }
-        tearDownSurface();
     }
 }
diff --git a/tests/media/src/android/mediav2/cts/WorkDir.java b/tests/media/src/android/mediav2/cts/WorkDir.java
index b5b0d24..5edbff1 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.0/");
+            return (getTopDirString() + "test/CtsMediaV2TestCases-2.1/");
         }
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
index 056f7a4..23760fc 100644
--- a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
@@ -16,11 +16,20 @@
 
 package android.mediapc.cts;
 
+import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_SecurePlayback;
+import static android.mediapc.cts.Utils.MIN_MEMORY_PERF_CLASS_CANDIDATE_MB;
+import static android.mediapc.cts.Utils.MIN_MEMORY_PERF_CLASS_T_MB;
 import static android.util.DisplayMetrics.DENSITY_400;
+import static org.junit.Assert.assertTrue;
 
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.media.MediaDrm;
+import android.media.MediaFormat;
+import android.media.UnsupportedSchemeException;
 import android.os.Build;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -28,6 +37,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.DeviceReportLog;
 import com.android.compatibility.common.util.ResultType;
@@ -35,16 +45,26 @@
 
 import org.junit.Assume;
 import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.runner.RunWith;
 
-import static org.junit.Assert.assertTrue;
+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);
+    static ArrayList<String> mMimeSecureSupport = new ArrayList<>();
+
+    static {
+        mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_AVC);
+        mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
+        mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_VP9);
+        mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_AV1);
+    }
+
 
     private boolean isHandheld() {
         // handheld nature is not exposed to package manager, for now
@@ -59,14 +79,107 @@
 
     @SmallTest
     @Test
+    // TODO(b/218771970) Add @CddTest annotation
+    public void testSecureHwDecodeSupport() throws IOException {
+        ArrayList<String> noSecureHwDecoderForMimes = new ArrayList<>();
+        for (String mime : mMimeSecureSupport) {
+            boolean isSecureHwDecoderFoundForMime = false;
+            boolean isHwDecoderFoundForMime = false;
+            MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
+            MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
+            for (MediaCodecInfo info : codecInfos) {
+                if (info.isEncoder() || !info.isHardwareAccelerated() || info.isAlias()) continue;
+                try {
+                    MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(mime);
+                    if (caps != null) {
+                        isHwDecoderFoundForMime = true;
+                        if (caps.isFeatureSupported(FEATURE_SecurePlayback))
+                            isSecureHwDecoderFoundForMime = true;
+                    }
+                } catch (Exception ignored) {
+                }
+            }
+            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());
+        }
+    }
+
+    @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;
+
+            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;
+        }
+
+        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());
+        }
+    }
+
+    @SmallTest
+    @Test
     public void testMediaPerformanceClassScope() throws Exception {
         // if device is not of a performance class, we are done.
         Assume.assumeTrue("not a device of a valid media performance class", Utils.isPerfClass());
 
-        if (Utils.isRPerfClass()
-                || Utils.isSPerfClass()) {
-            assertTrue("performance class is only defined for Handheld devices",
-                       isHandheld());
+        if (Utils.isPerfClass()) {
+            assertTrue("performance class is only defined for Handheld devices", isHandheld());
         }
     }
 
@@ -78,7 +191,7 @@
         // Verify minimum screen density and resolution
         assertMinDpiAndPixels(context, DENSITY_400, 1920, 1080);
         // Verify minimum memory
-        assertMinMemoryMb(context, Utils.MIN_MEMORY_PERF_CLASS_CANDIDATE_MB);
+        assertMinMemoryMb(context);
     }
 
     /** Asserts that the given values conform to the specs in CDD */
@@ -105,35 +218,39 @@
             int pc = density >= minDpi && longPix >= minLong && shortPix >= minShort
                     ? Build.VERSION_CODES.S : 0;
             DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",  "Display");
-            log.addValue("DisplayDensity", density, ResultType.LOWER_BETTER, ResultUnit.NONE);
-            log.addValue("ResolutionLong", longPix, ResultType.LOWER_BETTER, ResultUnit.NONE);
-            log.addValue("ResolutionShort", shortPix, ResultType.LOWER_BETTER, ResultUnit.NONE);
+            log.addValue("DisplayDensity", density, ResultType.HIGHER_BETTER, ResultUnit.NONE);
+            log.addValue("ResolutionLong", longPix, ResultType.HIGHER_BETTER, ResultUnit.NONE);
+            log.addValue("ResolutionShort", shortPix, ResultType.HIGHER_BETTER, ResultUnit.NONE);
             log.setSummary("CDD 2.2.7.3/7.1.1.1,7.1.1.3/H-1-1,H-2-1 performance_class", pc,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
+                    ResultType.HIGHER_BETTER, ResultUnit.NONE);
             log.submit(InstrumentationRegistry.getInstrumentation());
         }
     }
 
     /** Asserts that the given values conform to the specs in CDD 7.6.1 */
-    private void assertMinMemoryMb(Context context, long minMb) {
-        ActivityManager activityManager =
-                    (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+    private void assertMinMemoryMb(Context context) {
+        ActivityManager activityManager = context.getSystemService(ActivityManager.class);
         long totalMemoryMb = getTotalMemory(activityManager) / 1024 / 1024;
 
-        Log.i(TAG, String.format("minMb=%,d", minMb));
-        Log.i(TAG, String.format("totalMemoryMb=%,d", totalMemoryMb));
+        Log.i(TAG, String.format("Total device memory = %,d MB", totalMemoryMb));
         if (Utils.isPerfClass()) {
+            long minMb = Utils.isTPerfClass() ? MIN_MEMORY_PERF_CLASS_T_MB :
+                    Utils.MIN_MEMORY_PERF_CLASS_CANDIDATE_MB;
+            Log.i(TAG, String.format("Minimum required memory = %,d MB", minMb));
             assertTrue(String.format("Does not meet minimum memory requirements (CDD 7.6.1)."
                     + "Found = %d, Minimum = %d", totalMemoryMb, minMb), totalMemoryMb >= minMb);
         } else {
-            int pc = totalMemoryMb >= minMb ? Build.VERSION_CODES.S : 0;
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",  "MinMemory");
-            log.addValue("MemoryMB", totalMemoryMb, ResultType.LOWER_BETTER, ResultUnit.NONE);
+            int pc = 0;
+            if (totalMemoryMb >= MIN_MEMORY_PERF_CLASS_T_MB)
+                pc = Build.VERSION_CODES.TIRAMISU;
+            else if (totalMemoryMb >= MIN_MEMORY_PERF_CLASS_CANDIDATE_MB)
+                pc = Build.VERSION_CODES.S;
+            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs", "MinMemory");
+            log.addValue("MemoryMB", totalMemoryMb, ResultType.HIGHER_BETTER, ResultUnit.NONE);
             log.setSummary("CDD 2.2.7.3/7.6.1/H-1-1,H-2-1  performance_class", pc,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
+                    ResultType.HIGHER_BETTER, ResultUnit.NONE);
             log.submit(InstrumentationRegistry.getInstrumentation());
         }
-
     }
 
     /**
diff --git a/tests/mediapc/src/android/mediapc/cts/Utils.java b/tests/mediapc/src/android/mediapc/cts/Utils.java
index ec50c22..6ad6146 100644
--- a/tests/mediapc/src/android/mediapc/cts/Utils.java
+++ b/tests/mediapc/src/android/mediapc/cts/Utils.java
@@ -17,6 +17,7 @@
 package android.mediapc.cts;
 
 import static android.util.DisplayMetrics.DENSITY_400;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.ActivityManager;
 import android.content.Context;
@@ -27,12 +28,10 @@
 import android.util.Log;
 import android.view.WindowManager;
 
-import com.android.compatibility.common.util.ApiLevelUtil;
-
-import static org.junit.Assume.assumeTrue;
-
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.ApiLevelUtil;
+
 
 /**
  * Test utilities.
@@ -53,6 +52,8 @@
     // 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.
     public static final long MIN_MEMORY_PERF_CLASS_CANDIDATE_MB = 5 * 1024;
+    // Android T Media performance requires 8 GB min RAM, so setting lower as above
+    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
diff --git a/tests/sample/AndroidTest.xml b/tests/sample/AndroidTest.xml
index c3731f3..408fccc 100644
--- a/tests/sample/AndroidTest.xml
+++ b/tests/sample/AndroidTest.xml
@@ -15,6 +15,8 @@
 -->
 <configuration description="Config for CTS Sample test cases">
     <option name="test-suite-tag" value="cts" />
+    <!-- Change the value field of `component` into an appropriate one.
+         See README for the full list. -->
     <option name="config-descriptor:metadata" key="component" value="misc" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
diff --git a/tests/sample/OWNERS b/tests/sample/OWNERS
index 7782fbe..d354e30 100644
--- a/tests/sample/OWNERS
+++ b/tests/sample/OWNERS
@@ -1,10 +1,7 @@
 # Bug component: 346961
 diqian@google.com
+fangqiu@google.com
 fdeng@google.com
-moonk@google.com
 normancheung@google.com
-williamgoh@google.com
 peykov@google.com
-yichunli@google.com
-yimingpan@google.com
-
+yimingpan@google.com
\ No newline at end of file
diff --git a/tests/sample/README b/tests/sample/README
new file mode 100644
index 0000000..3ab3544
--- /dev/null
+++ b/tests/sample/README
@@ -0,0 +1,15 @@
+This 'sample' folder is a sample which illustrates the basic structure and contents of a CTS module.
+
+Future users can refer to this folder to create their own CTS modules.
+
+Several things to notice:
+  1.  The users should update the `misc` value in
+      `<option name="config-descriptor:metadata" key="component" value="misc" />`
+      of the 'AndroidTest.xml' file into an appropriate group for the module they created.
+
+      The list of all available groups:
+      <https://cs.android.com/android/platform/superproject/+/master:cts/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java;l=66>.
+
+  2.  If the module is added outside the 'cts/' folder, the user should also 1) add the module
+      directory into the ayeaye checker (as shown in cl/423435565), and 2) add an OWNERS file in the
+      module directory accordingly.
\ No newline at end of file
diff --git a/tests/sample/src/android/sample/cts/SampleDeviceReportLogTest.java b/tests/sample/src/android/sample/cts/SampleDeviceReportLogTest.java
index 0970b2a..5fa5252 100644
--- a/tests/sample/src/android/sample/cts/SampleDeviceReportLogTest.java
+++ b/tests/sample/src/android/sample/cts/SampleDeviceReportLogTest.java
@@ -16,24 +16,27 @@
 package android.sample.cts;
 
 import android.sample.SampleDeviceActivity;
-import android.test.ActivityInstrumentationTestCase2;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
 
 /**
- * WARNING: This sample test is out of date. Newer tests should be written using
- * androidx testing libraries. See SampleJUnit4DeviceTest.java
- *
- * TODO(b/211678773): Update the test to use androidx testing libraries.
- *
  * A simple compatibility test which includes results in the report.
  *
  * This class has 3 no-op tests that create report logs and log fake metrics.
  */
-public class SampleDeviceReportLogTest
-        extends ActivityInstrumentationTestCase2<SampleDeviceActivity> {
+@RunWith(AndroidJUnit4.class)
+public class SampleDeviceReportLogTest {
 
     /**
      * Name of the report log. Test metrics will be written out to ths report. The name must match
@@ -56,19 +59,13 @@
     private static final String END_TAG = "actual_end";
 
     /**
-     * Constructor which passes the class of the activity to be instrumented.
-     */
-    public SampleDeviceReportLogTest() {
-        super(SampleDeviceActivity.class);
-    }
-
-    /**
      * Sample test that creates and logs test metrics into a report log.
      */
+    @Test
     public void testMultiplication() {
         // Perform test.
         int product = MULTIPLICATION_NUMBER_1 * MULTIPLICATION_NUMBER_2;
-        assertTrue("Multiplication result do not match", product == MULTIPLICATION_RESULT);
+        Assert.assertTrue("Multiplication result do not match", product == MULTIPLICATION_RESULT);
 
         // Log metrics from the test.
         String streamName = "test_multiplication";
@@ -77,12 +74,13 @@
                 ResultUnit.NONE);
         reportLog.addValue(ACTUAL_PRODUCT_TAG, 1.0 * product, ResultType.NEUTRAL, ResultUnit.NONE);
         reportLog.setSummary(ACTUAL_PRODUCT_TAG, 1.0 * product, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.submit(getInstrumentation());
+        reportLog.submit(InstrumentationRegistry.getInstrumentation());
     }
 
     /**
      * Sample test to check counting up.
      */
+    @Test
     public void testCountUp() {
         String streamName = "test_count_up";
         countHelper(1, streamName);
@@ -91,6 +89,7 @@
     /**
      * Sample test to check counting down.
      */
+    @Test
     public void testCountDown() {
         String streamName = "test_count_down";
         countHelper(2, streamName);
@@ -125,6 +124,6 @@
         reportLog.addValue(START_TAG, 1.0 * start, ResultType.NEUTRAL, ResultUnit.NONE);
         reportLog.addValue(END_TAG, 1.0 * end, ResultType.NEUTRAL, ResultUnit.NONE);
         reportLog.setSummary(END_TAG, 1.0 * end, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.submit(getInstrumentation());
+        reportLog.submit(InstrumentationRegistry.getInstrumentation());
     }
 }
diff --git a/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java b/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
index 8c4a97d..4798f5e 100644
--- a/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
+++ b/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
@@ -16,7 +16,15 @@
 package android.sample.cts;
 
 import android.sample.SampleDeviceActivity;
-import android.test.ActivityInstrumentationTestCase2;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.MeasureRun;
@@ -29,18 +37,12 @@
 import java.util.Random;
 
 /**
- * WARNING: This sample test is out of date. Newer tests should be written using
- * androidx testing libraries. See SampleJUnit4DeviceTest.java
- *
- * TODO(b/211678773): Update the test to use androidx testing libraries.
- *
- * A simple compatibility test which includes results in the report.
- *
  * A simple compatibility test which includes results in the report.
  *
  * This test measures the time taken to run a workload and adds in the report.
  */
-public class SampleDeviceResultTest extends ActivityInstrumentationTestCase2<SampleDeviceActivity> {
+@RunWith(AndroidJUnit4.class)
+public class SampleDeviceResultTest {
 
     /**
      * Name of the report log to store test metrics.
@@ -58,15 +60,9 @@
     private static final Random random = new Random(12345);
 
     /**
-     * Constructor which passes the class of the activity to be instrumented.
-     */
-    public SampleDeviceResultTest() {
-        super(SampleDeviceActivity.class);
-    }
-
-    /**
      * Measures the time taken to sort an array.
      */
+    @Test
     public void testSort() throws Exception {
         // MeasureTime runs the workload N times and records the time taken by each run.
         double[] result = MeasureTime.measure(REPEAT, new MeasureRun() {
@@ -82,7 +78,7 @@
             @Override
             public void run(int i) throws Exception {
                 Arrays.sort(array);
-                assertTrue("Array not sorted", isSorted(array));
+                Assert.assertTrue("Array not sorted", isSorted(array));
             }
         });
         // Compute the stats.
@@ -97,7 +93,7 @@
         // Set a summary.
         reportLog.setSummary("average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
         // Submit the report to the given instrumentation.
-        reportLog.submit(getInstrumentation());
+        reportLog.submit(InstrumentationRegistry.getInstrumentation());
     }
 
     /**
diff --git a/tests/sample/src/android/sample/cts/SampleDeviceTest.java b/tests/sample/src/android/sample/cts/SampleDeviceTest.java
index 653bb47..3ea4881 100644
--- a/tests/sample/src/android/sample/cts/SampleDeviceTest.java
+++ b/tests/sample/src/android/sample/cts/SampleDeviceTest.java
@@ -16,20 +16,23 @@
 package android.sample.cts;
 
 import android.sample.SampleDeviceActivity;
-import android.test.ActivityInstrumentationTestCase2;
+
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
- * WARNING: This sample test is out of date. Newer tests should be written using
- * androidx testing libraries. See SampleJUnit4DeviceTest.java
- *
- * TODO(b/211678773): This test can be probably removed.
- *
  * A simple compatibility test which tests the SharedPreferences API.
  *
- * This test uses {@link android.test.ActivityInstrumentationTestCase2} to instrument the
+ * This test uses {@link ActivityTestRule} to instrument the
  * {@link android.sample.SampleDeviceActivity}.
  */
-public class SampleDeviceTest extends ActivityInstrumentationTestCase2<SampleDeviceActivity> {
+@RunWith(AndroidJUnit4.class)
+public class SampleDeviceTest {
 
     private static final String KEY = "foo";
 
@@ -38,28 +41,9 @@
     /**
      * A reference to the activity whose shared preferences are being tested.
      */
-    private SampleDeviceActivity mActivity;
-
-    public SampleDeviceTest() {
-        super(SampleDeviceActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        // Start the activity and get a reference to it.
-        mActivity = getActivity();
-        // Wait for the UI Thread to become idle.
-        getInstrumentation().waitForIdleSync();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        // Scrub the activity so it can be freed. The next time the setUp will create a new activity
-        // rather than reusing the old one.
-        mActivity = null;
-        super.tearDown();
-    }
+    @Rule
+    public ActivityTestRule<SampleDeviceActivity> mActivityRule =
+        new ActivityTestRule(SampleDeviceActivity.class);
 
     /**
      * Tests the SharedPreferences API.
@@ -69,13 +53,16 @@
      *
      * @throws Exception
      */
+    @Test
     public void testSharedPreferences() throws Exception {
         // Save the key value pair to the preferences and assert they were saved.
-        mActivity.savePreference(KEY, VALUE);
-        assertEquals("Preferences were not saved", VALUE, mActivity.getPreference(KEY));
+        mActivityRule.getActivity().savePreference(KEY, VALUE);
+        Assert.assertEquals("Preferences were not saved", VALUE,
+            mActivityRule.getActivity().getPreference(KEY));
 
         // Clear the shared preferences and assert the data was removed.
-        mActivity.clearPreferences();
-        assertNull("Preferences were not cleared", mActivity.getPreference(KEY));
+        mActivityRule.getActivity().clearPreferences();
+        Assert.assertNull("Preferences were not cleared",
+            mActivityRule.getActivity().getPreference(KEY));
     }
 }
diff --git a/tests/sample/src/android/sample/cts/SampleJUnit4DeviceTest.java b/tests/sample/src/android/sample/cts/SampleJUnit4DeviceTest.java
deleted file mode 100755
index 3aa0cb0..0000000
--- a/tests/sample/src/android/sample/cts/SampleJUnit4DeviceTest.java
+++ /dev/null
@@ -1,64 +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 android.sample.cts;
-
-import android.sample.SampleDeviceActivity;
-
-import androidx.test.rule.ActivityTestRule;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * A simple compatibility test which tests the SharedPreferences API.
- *
- * This test uses {@link ActivityTestRule} to instrument the
- * {@link android.sample.SampleDeviceActivity}.
- */
-@RunWith(AndroidJUnit4.class)
-public class SampleJUnit4DeviceTest {
-
-    private static final String KEY = "foo";
-
-    private static final String VALUE = "bar";
-
-    @Rule
-    public ActivityTestRule<SampleDeviceActivity> mActivityRule =
-        new ActivityTestRule(SampleDeviceActivity.class);
-
-
-    /**
-     * This inserts the key value pair and assert they can be retrieved. Then it clears the
-     * preferences and asserts they can no longer be retrieved.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void shouldSaveSharedPreferences() throws Exception {
-        // Save the key value pair to the preferences and assert they were saved.
-        mActivityRule.getActivity().savePreference(KEY, VALUE);
-        Assert.assertEquals("Preferences were not saved", VALUE,
-            mActivityRule.getActivity().getPreference(KEY));
-
-        // Clear the shared preferences and assert the data was removed.
-        mActivityRule.getActivity().clearPreferences();
-        Assert.assertNull("Preferences were not cleared",
-            mActivityRule.getActivity().getPreference(KEY));
-    }
-}
diff --git a/tests/signature/api-check/Android.bp b/tests/signature/api-check/Android.bp
index b3fd278..c95cf4a 100644
--- a/tests/signature/api-check/Android.bp
+++ b/tests/signature/api-check/Android.bp
@@ -33,6 +33,7 @@
         // androidx.test.runner depends on android.test classes from this library.
         "android.test.base-minus-junit",
         "androidx.test.runner",
+        "compatibility-device-util-axt",
         "cts-signature-common",
     ],
 }
@@ -54,18 +55,6 @@
     compile_multilib: "both",
 }
 
-// Defaults for signature api checks with dynamic config.
-java_defaults {
-    name: "signature-api-check-dynamic-config-defaults",
-    defaults: ["signature-api-check-defaults"],
-    defaults_visibility: [
-        "//cts/tests/signature:__subpackages__",
-    ],
-    static_libs: [
-        "cts-signature-with-dynamic-config",
-    ],
-}
-
 // Filegroup containing the jarjar rules that need to be applied to any test that checks for
 // accessibility (or inaccesibility) of android.test and junit classes from the android.test.base
 // and android.test.runner libraries.
@@ -103,7 +92,7 @@
 // Defaults for hiddenapi blocklist checks.
 java_defaults {
     name: "hiddenapi-blocklist-check-defaults",
-    defaults: ["signature-api-check-dynamic-config-defaults"],
+    defaults: ["signature-api-check-defaults"],
     java_resources: [
         ":platform-bootclasspath{hiddenapi-flags.csv}",
         ":cts-api-hiddenapi-filter-csv"
diff --git a/tests/signature/api-check/android-test-base-29-api/Android.bp b/tests/signature/api-check/android-test-base-29-api/Android.bp
index d151a19..a4def69 100644
--- a/tests/signature/api-check/android-test-base-29-api/Android.bp
+++ b/tests/signature/api-check/android-test-base-29-api/Android.bp
@@ -33,6 +33,14 @@
     ],
     min_sdk_version: "29",
 
+    // Prevent android.test.runner and android.test.mock classes being available at runtime by
+    // excluding them from the list of libraries that are implicitly added to the manifest.
+    // Otherwise, the test would break as it is not expecting those classes to be available.
+    exclude_uses_libs: [
+        "android.test.mock",
+        "android.test.runner",
+    ],
+
     use_embedded_native_libs: false,
     test_suites: [
         "cts",
diff --git a/tests/signature/api-check/android-test-base-29-api/AndroidTest.xml b/tests/signature/api-check/android-test-base-29-api/AndroidTest.xml
index d7986be..ff65060 100644
--- a/tests/signature/api-check/android-test-base-29-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-base-29-api/AndroidTest.xml
@@ -34,7 +34,16 @@
         <option name="package" value="android.signature.cts.api.android_test_base_29" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="class" value="android.signature.cts.api.api29.test.SignatureTest" />
+        <!--
+         ! android.test.base classes must be accessible to this test as this test's targetSdkVersion
+         ! is 29 which provided the classes by default on the bootclasspath.
+         !-->
         <option name="instrumentation-arg" key="expected-api-files" value="android-test-base-current.api.gz" />
+        <!--
+         ! android.test.mock and android.test.runner classes must not be accessible to this test as
+         ! they are only provided when specifically requested using a <uses-library> element in the
+         ! manifest.
+         !-->
         <option name="instrumentation-arg" key="unexpected-api-files" value="android-test-runner-current.api.gz,android-test-mock-current.api.gz" />
         <option name="runtime-hint" value="5s" />
         <!-- Disable hidden API checks (http://b/171459260). -->
diff --git a/tests/signature/api-check/android-test-base-current-api/Android.bp b/tests/signature/api-check/android-test-base-current-api/Android.bp
index cdf3b45..737dde0 100644
--- a/tests/signature/api-check/android-test-base-current-api/Android.bp
+++ b/tests/signature/api-check/android-test-base-current-api/Android.bp
@@ -32,6 +32,16 @@
         ":cts-android-test-runner-current-api-gz",
     ],
 
+    // Prevent android.test.base, android.test.runner and android.test.mock classes being available
+    // at runtime by excluding them from the list of libraries that are implicitly added to the
+    // manifest. Otherwise, the test would break as it is not expecting those classes to be
+    // available.
+    exclude_uses_libs: [
+        "android.test.base",
+        "android.test.runner",
+        "android.test.mock",
+    ],
+
     use_embedded_native_libs: false,
     test_suites: [
         "cts",
diff --git a/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml b/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml
index ad566a4..dc72d87 100644
--- a/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml
@@ -31,6 +31,11 @@
         <option name="package" value="android.signature.cts.api.android_test_base_current" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="class" value="android.signature.cts.api.current.test.SignatureTest" />
+        <!--
+         ! android.test.base, android.test.mock and android.test.runner classes must NOT be
+         ! accessible to this test as the android.test.base classes are no longer provided by
+         ! default and the other libraries were never provided by default.
+         !-->
         <option name="instrumentation-arg" key="unexpected-api-files" value="android-test-base-current.api.gz,android-test-runner-current.api.gz,android-test-mock-current.api.gz" />
         <option name="runtime-hint" value="5s" />
         <!-- Disable hidden API checks (http://b/171459260). -->
diff --git a/tests/signature/api-check/android-test-base-uses-library-api/Android.bp b/tests/signature/api-check/android-test-base-uses-library-api/Android.bp
index b38c0d5..708d430 100644
--- a/tests/signature/api-check/android-test-base-uses-library-api/Android.bp
+++ b/tests/signature/api-check/android-test-base-uses-library-api/Android.bp
@@ -33,6 +33,14 @@
     ],
     min_sdk_version: "30",
 
+    // Prevent android.test.mock and android.test.runner classes being available at runtime by
+    // excluding them from the list of libraries that are implicitly added to the manifest.
+    // Otherwise, the test would break as it is not expecting those classes to be available.
+    exclude_uses_libs: [
+        "android.test.mock",
+        "android.test.runner",
+    ],
+
     use_embedded_native_libs: false,
     test_suites: [
         "cts",
diff --git a/tests/signature/api-check/android-test-base-uses-library-api/AndroidTest.xml b/tests/signature/api-check/android-test-base-uses-library-api/AndroidTest.xml
index dd32c49..c945e3f 100644
--- a/tests/signature/api-check/android-test-base-uses-library-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-base-uses-library-api/AndroidTest.xml
@@ -32,7 +32,16 @@
         <option name="package" value="android.signature.cts.api.android_test_base_uses_library" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="class" value="android.signature.cts.api.uses_library.test.base.SignatureTest" />
+        <!--
+         ! android.test.base classes must be accessible to this test as this test specifically
+         ! requests them using a <uses-library android:name="android.test.base"/> in its manifest.
+         !-->
         <option name="instrumentation-arg" key="expected-api-files" value="android-test-base-current.api.gz" />
+        <!--
+         ! android.test.mock and android.test.runner classes must not be accessible to this test as
+         ! they are only provided when specifically requested using a <uses-library> element in the
+         ! manifest.
+         !-->
         <option name="instrumentation-arg" key="unexpected-api-files" value="android-test-runner-current.api.gz,android-test-mock-current.api.gz" />
         <option name="runtime-hint" value="5s" />
         <!-- Disable hidden API checks (http://b/171459260). -->
diff --git a/tests/signature/api-check/android-test-mock-current-api/Android.bp b/tests/signature/api-check/android-test-mock-current-api/Android.bp
index 52fbe50..63e6bf6 100644
--- a/tests/signature/api-check/android-test-mock-current-api/Android.bp
+++ b/tests/signature/api-check/android-test-mock-current-api/Android.bp
@@ -21,8 +21,23 @@
     defaults: [
         "signature-api-check-defaults",
     ],
+
+    // Ensure that any android.test and junit classes embedded within this test do not conflict with
+    // the classes provided by the android.test.base or android.test.runner shared libraries.
+    jarjar_rules: ":cts-android-test-jarjar-rules",
+
     java_resources: [
+        ":cts-android-test-base-current-api-gz",
         ":cts-android-test-mock-current-api-gz",
+        ":cts-android-test-runner-current-api-gz",
+    ],
+
+    // Prevent android.test.base and android.test.runner classes being available at runtime by
+    // excluding them from the list of libraries that are implicitly added to the manifest.
+    // Otherwise, the test would break as it is not expecting those classes to be available.
+    exclude_uses_libs: [
+        "android.test.base",
+        "android.test.runner",
     ],
 
     use_embedded_native_libs: false,
diff --git a/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml b/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml
index a312b8a..6c7c2a7 100644
--- a/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-mock-current-api/AndroidTest.xml
@@ -27,7 +27,17 @@
         <option name="package" value="android.signature.cts.api.android_test_mock_current" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="class" value="android.signature.cts.api.current.mock.SignatureTest" />
+        <!--
+         ! android.test.mock classes must be accessible to this test as this test specifically
+         ! requests them using a <uses-library android:name="android.test.mock"/> in its manifest.
+         !-->
         <option name="instrumentation-arg" key="expected-api-files" value="android-test-mock-current.api.gz" />
+        <!--
+         ! android.test.base and android.test.runner classes must not be accessible to this test as
+         ! they are only provided when specifically requested using a <uses-library> element in the
+         ! manifest.
+         !-->
+        <option name="instrumentation-arg" key="unexpected-api-files" value="android-test-base-current.api.gz,android-test-runner-current.api.gz" />
         <option name="runtime-hint" value="5s" />
         <!-- Disable hidden API checks (http://b/171459260). -->
         <option name="hidden-api-checks" value="false" />
diff --git a/tests/signature/api-check/android-test-runner-current-api/Android.bp b/tests/signature/api-check/android-test-runner-current-api/Android.bp
index 45b3d4f..f6e3e63 100644
--- a/tests/signature/api-check/android-test-runner-current-api/Android.bp
+++ b/tests/signature/api-check/android-test-runner-current-api/Android.bp
@@ -32,6 +32,15 @@
         ":cts-android-test-runner-current-api-gz",
     ],
 
+    // Prevent android.test.base and android.test.mock libraries from being implicitly added to
+    // the manifest. Their classes should still be available at runtime as a dependency on
+    // android.test.runner should automatically add a dependency on android.test.base and
+    // android.test.mock.
+    exclude_uses_libs: [
+        "android.test.base",
+        "android.test.mock",
+    ],
+
     use_embedded_native_libs: false,
     test_suites: [
         "cts",
diff --git a/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml b/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml
index 550e70e..1c406b3 100644
--- a/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-runner-current-api/AndroidTest.xml
@@ -27,6 +27,11 @@
         <option name="package" value="android.signature.cts.api.android_test_runner_current" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="class" value="android.signature.cts.api.current.runner.SignatureTest" />
+        <!--
+         ! android.test.base, android.test.mock and android.test.runner classes must NOT be
+         ! accessible to this test as the android.test.base classes are no longer provided by
+         ! default and the other libraries were never provided by default.
+         !-->
         <option name="instrumentation-arg" key="expected-api-files" value="android-test-base-current.api.gz,android-test-mock-current.api.gz,android-test-runner-current.api.gz" />
         <option name="runtime-hint" value="5s" />
         <!-- Disable hidden API checks (http://b/171459260). -->
diff --git a/tests/signature/api-check/current-api/Android.bp b/tests/signature/api-check/current-api/Android.bp
index 4114272..88bce59 100644
--- a/tests/signature/api-check/current-api/Android.bp
+++ b/tests/signature/api-check/current-api/Android.bp
@@ -23,9 +23,6 @@
     ],
     java_resources: [
         ":cts-current-api-gz",
-        ":cts-android-test-base-current-api-gz",
-        ":cts-android-test-mock-current-api-gz",
-        ":cts-android-test-runner-current-api-gz",
     ],
 
     use_embedded_native_libs: false,
diff --git a/tests/signature/api-check/hidden-api-blocklist-27-api/src/android/signature/cts/api/api27/HiddenApiTest.java b/tests/signature/api-check/hidden-api-blocklist-27-api/src/android/signature/cts/api/api27/HiddenApiTest.java
index 13ea0f1..c940aac 100644
--- a/tests/signature/api-check/hidden-api-blocklist-27-api/src/android/signature/cts/api/api27/HiddenApiTest.java
+++ b/tests/signature/api-check/hidden-api-blocklist-27-api/src/android/signature/cts/api/api27/HiddenApiTest.java
@@ -16,7 +16,5 @@
 
 package android.signature.cts.api.api27;
 
-import android.signature.cts.api.dynamic.DynamicConfigHiddenApiTest;
-
-public class HiddenApiTest extends DynamicConfigHiddenApiTest {
+public class HiddenApiTest extends android.signature.cts.api.HiddenApiTest {
 }
diff --git a/tests/signature/api-check/hidden-api-blocklist-28-api/src/android/signature/cts/api/api28/HiddenApiTest.java b/tests/signature/api-check/hidden-api-blocklist-28-api/src/android/signature/cts/api/api28/HiddenApiTest.java
index 091a25f..f85dda3 100644
--- a/tests/signature/api-check/hidden-api-blocklist-28-api/src/android/signature/cts/api/api28/HiddenApiTest.java
+++ b/tests/signature/api-check/hidden-api-blocklist-28-api/src/android/signature/cts/api/api28/HiddenApiTest.java
@@ -16,7 +16,5 @@
 
 package android.signature.cts.api.api28;
 
-import android.signature.cts.api.dynamic.DynamicConfigHiddenApiTest;
-
-public class HiddenApiTest extends DynamicConfigHiddenApiTest {
+public class HiddenApiTest extends android.signature.cts.api.HiddenApiTest {
 }
diff --git a/tests/signature/api-check/hidden-api-blocklist-current-api/src/android/signature/cts/api/current/HiddenApiTest.java b/tests/signature/api-check/hidden-api-blocklist-current-api/src/android/signature/cts/api/current/HiddenApiTest.java
index 7726489..34f33fe 100644
--- a/tests/signature/api-check/hidden-api-blocklist-current-api/src/android/signature/cts/api/current/HiddenApiTest.java
+++ b/tests/signature/api-check/hidden-api-blocklist-current-api/src/android/signature/cts/api/current/HiddenApiTest.java
@@ -16,7 +16,5 @@
 
 package android.signature.cts.api.current;
 
-import android.signature.cts.api.dynamic.DynamicConfigHiddenApiTest;
-
-public class HiddenApiTest extends DynamicConfigHiddenApiTest {
+public class HiddenApiTest extends android.signature.cts.api.HiddenApiTest {
 }
diff --git a/tests/signature/api-check/hidden-api-blocklist-debug-class/src/android/signature/cts/api/blocklist/debug/DebugClassHiddenApiTest.java b/tests/signature/api-check/hidden-api-blocklist-debug-class/src/android/signature/cts/api/blocklist/debug/DebugClassHiddenApiTest.java
index 9266976..c8dcfca 100644
--- a/tests/signature/api-check/hidden-api-blocklist-debug-class/src/android/signature/cts/api/blocklist/debug/DebugClassHiddenApiTest.java
+++ b/tests/signature/api-check/hidden-api-blocklist-debug-class/src/android/signature/cts/api/blocklist/debug/DebugClassHiddenApiTest.java
@@ -17,11 +17,12 @@
 package android.signature.cts.api.blocklist.debug;
 
 import android.signature.cts.DexMemberChecker;
-import android.signature.cts.api.dynamic.DynamicConfigHiddenApiTest;
 
-public class DebugClassHiddenApiTest extends DynamicConfigHiddenApiTest {
+import static org.junit.Assert.assertFalse;
+
+public class DebugClassHiddenApiTest extends android.signature.cts.api.HiddenApiTest {
     @Override
-    protected void setUp() throws Exception {
+    public void setUp() throws Exception {
         super.setUp();
 
         // Try to exempt DexMemberChecker class from hidden API checks.
diff --git a/tests/signature/api-check/hidden-api-blocklist-test-api/src/android/signature/cts/api/test/HiddenApiTest.java b/tests/signature/api-check/hidden-api-blocklist-test-api/src/android/signature/cts/api/test/HiddenApiTest.java
index 3fe708c..b30bbcb 100644
--- a/tests/signature/api-check/hidden-api-blocklist-test-api/src/android/signature/cts/api/test/HiddenApiTest.java
+++ b/tests/signature/api-check/hidden-api-blocklist-test-api/src/android/signature/cts/api/test/HiddenApiTest.java
@@ -17,10 +17,9 @@
 package android.signature.cts.api.test;
 
 import android.signature.cts.DexMember;
-import android.signature.cts.api.dynamic.DynamicConfigHiddenApiTest;
 import java.util.Set;
 
-public class HiddenApiTest extends DynamicConfigHiddenApiTest {
+public class HiddenApiTest extends android.signature.cts.api.HiddenApiTest {
 
     /**
      * Override to match only those members that specify both test-api and blocked.
@@ -30,5 +29,4 @@
         Set<String> flags = member.getHiddenapiFlags();
         return flags.contains("test-api") && flags.contains("blocked");
     }
-
 }
diff --git a/tests/signature/api-check/shared-libs-api/Android.bp b/tests/signature/api-check/shared-libs-api/Android.bp
index 42db95c..afab2f3 100644
--- a/tests/signature/api-check/shared-libs-api/Android.bp
+++ b/tests/signature/api-check/shared-libs-api/Android.bp
@@ -36,7 +36,8 @@
     jarjar_rules: ":cts-android-test-jarjar-rules",
 
     java_resources: [
-        ":CtsSharedLibsApiSignatureTestCases_cts-shared-libs-all.api",
+        ":CtsSharedLibsApiSignatureTestCases_cts-shared-libs-all-current.api",
+        ":CtsSharedLibsApiSignatureTestCases_cts-shared-libs-all-previous.api",
     ],
     static_libs: [
         "cts-api-signature-multilib-test",
@@ -59,8 +60,57 @@
     srcs: ["src/**/*.java"],
 }
 
+// Generates a zip file containing the current public and system API files for shared libraries.
 genrule {
-    name: "CtsSharedLibsApiSignatureTestCases_cts-shared-libs-all.api",
+    name: "CtsSharedLibsApiSignatureTestCases_cts-shared-libs-all-current.api",
+    srcs: [
+        ":android.net.ipsec.ike{.public.api.txt}",
+        ":android.net.ipsec.ike{.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}",
+        ":com.android.libraries.tv.tvsystem{.system.api.txt}",
+        ":com.android.location.provider{.public.api.txt}",
+        ":com.android.location.provider{.system.api.txt}",
+        ":com.android.mediadrm.signer{.public.api.txt}",
+        ":com.android.mediadrm.signer{.system.api.txt}",
+        ":com.android.media.remotedisplay{.public.api.txt}",
+        ":com.android.media.remotedisplay{.system.api.txt}",
+        ":com.android.media.tv.remoteprovider{.public.api.txt}",
+        ":com.android.media.tv.remoteprovider{.system.api.txt}",
+        ":com.android.nfc_extras{.public.api.txt}",
+        ":com.android.nfc_extras{.system.api.txt}",
+        ":javax.obex{.public.api.txt}",
+        ":javax.obex{.system.api.txt}",
+    ],
+    tools: [
+        "soong_zip",
+        "metalava",
+    ],
+    out: [
+        "shared-libs-all-current.api.zip",
+    ],
+    cmd: "mkdir -p $(genDir)/list && " +
+        "for f in $(in); do " +
+        // Extract the module name from the path.
+        "  fileName=$$(basename $${f} .txt) && " +
+        "  fileName=$${fileName%%.stubs.source*} && " +
+        // Extract the api level, i.e. public|system from the path.
+        "  apiLevel=$${f##*.stubs.source} && " +
+        "  apiLevel=$${apiLevel#.} && " +
+        "  apiLevel=$${apiLevel%_api.txt} && " +
+        "  if [ -z $${apiLevel} ]; then apiLevel=public; fi && " +
+        // Convert the .txt file into its XML representation.
+        "  $(location metalava) -J--add-opens=java.base/java.util=ALL-UNNAMED --no-banner " +
+        "    -convert2xmlnostrip $${f} $(genDir)/list/$${fileName}-current-$${apiLevel}.api; " +
+        "done && " +
+        "$(location soong_zip) -o $(out) -C $(genDir)/list -D $(genDir)/list",
+}
+
+// Generates a zip file containing all the API files from previous releases >= 28 excluding the
+// android.txt and removed files.
+genrule {
+    name: "CtsSharedLibsApiSignatureTestCases_cts-shared-libs-all-previous.api",
     srcs: [
         ":prebuilt_sdk_system_public_api_txt",
     ],
@@ -69,7 +119,7 @@
         "metalava",
     ],
     out: [
-        "shared-libs-all.api.zip",
+        "shared-libs-all-previous.api.zip",
     ],
     cmd: "for f in $(in); do " +
         "  fileName=$$(basename $${f} .txt) && " +
@@ -82,4 +132,4 @@
         "    -convert2xmlnostrip $${f} $(genDir)/list/$${fileName}-$${platformSdkVersion}-$${apiLevel}.api; " +
         "done && " +
         "$(location soong_zip) -o $(out) -C $(genDir)/list -D $(genDir)/list",
-}
\ No newline at end of file
+}
diff --git a/tests/signature/api-check/shared-libs-api/AndroidTest.xml b/tests/signature/api-check/shared-libs-api/AndroidTest.xml
index 7203269..bef3c0a 100644
--- a/tests/signature/api-check/shared-libs-api/AndroidTest.xml
+++ b/tests/signature/api-check/shared-libs-api/AndroidTest.xml
@@ -27,7 +27,8 @@
         <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="expected-api-files" value="shared-libs-all.api.zip" />
+        <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" />
         <!-- Disable hidden API checks (http://b/171459260). -->
         <option name="hidden-api-checks" value="false" />
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 651c2de..c16bd04 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
@@ -16,13 +16,20 @@
 
 package android.signature.cts.api;
 
+import android.app.Instrumentation;
 import android.signature.cts.ApiComplianceChecker;
 import android.signature.cts.ApiDocumentParser;
 import android.signature.cts.VirtualPath;
 import android.signature.cts.VirtualPath.LocalFilePath;
+import androidx.test.platform.app.InstrumentationRegistry;
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import org.junit.BeforeClass;
+import org.junit.Test;
 
 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
 
@@ -38,22 +45,35 @@
 
     private static final String TAG = SignatureMultiLibsTest.class.getSimpleName();
 
+    private static Set<String> libraries;
+
+    /**
+     * Obtain a list of shared libraries from the device.
+     */
+    @BeforeClass
+    public static void retrieveListOfSharedLibrariesOnDevice() throws Exception {
+        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));
+    }
+
     /**
      * 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
      */
+    @Test
     public void testSignature() {
         runWithTestResultObserver(mResultObserver -> {
-
             ApiComplianceChecker complianceChecker =
                     new ApiComplianceChecker(mResultObserver, mClassProvider);
 
             ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
 
-            parseApiResourcesAsStream(apiDocumentParser,
-                    Stream.concat(Arrays.stream(expectedApiFiles), Arrays.stream(previousApiFiles))
-                    .toArray(String[]::new))
+            parseApiResourcesAsStream(apiDocumentParser, expectedApiFiles)
                     .forEach(complianceChecker::checkSignatureCompliance);
 
             // After done parsing all expected API files, perform any deferred checks.
@@ -62,17 +82,23 @@
     }
 
     /**
-     * Get all the shared libraries available on the device.
-     *
-     * @return a stream of available shared library names.
+     * Tests that the device's API matches the previous APIs defined in xml.
      */
-    private Stream<String> getLibraries() {
-        try {
-            String result = runShellCommand(getInstrumentation(), "cmd package list libraries");
-            return Arrays.stream(result.split("\n")).map(line -> line.split(":")[1]);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
+    @Test
+    public void testPreviousSignatures() {
+        runWithTestResultObserver(mResultObserver -> {
+            ApiComplianceChecker complianceChecker =
+                    new ApiComplianceChecker(mResultObserver, mClassProvider);
+
+            ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
+
+            parseApiResourcesAsStream(apiDocumentParser, previousApiFiles)
+                    .map(clazz -> clazz.setPreviousApiFlag(true))
+                    .forEach(complianceChecker::checkSignatureCompliance);
+
+            // After done parsing all expected API files, perform any deferred checks.
+            complianceChecker.checkDeferred();
+        });
     }
 
     /**
@@ -84,7 +110,17 @@
      */
     private boolean checkLibrary (String name) {
         String libraryName = name.substring(name.lastIndexOf('/') + 1).split("-")[0];
-        return getLibraries().anyMatch(libraryName::equals);
+        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;
     }
 
     /**
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 8150904..5bfe0bb 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
@@ -31,23 +31,35 @@
 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 java.nio.file.StandardOpenOption;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
 import java.util.stream.Stream;
 import java.util.zip.ZipFile;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 
 /**
+ * Base class for the signature tests.
  */
-public class AbstractApiTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public abstract class AbstractApiTest {
+
+    /**
+     * The name of the optional instrumentation option that contains the name of the dynamic config
+     * data set that contains the expected failures.
+     */
+    private static final String DYNAMIC_CONFIG_NAME_OPTION = "dynamic-config-name";
 
     private static final String TAG = "SignatureTest";
 
@@ -76,9 +88,8 @@
                 Settings.Global.HIDDEN_API_POLICY);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mResultObserver = new TestResultObserver();
 
         // Get the arguments passed to the instrumentation.
@@ -90,10 +101,9 @@
                         Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS),
                 getExpectedBlocklistExemptions(),
                 getGlobalExemptions());
-        assertEquals(
+        assertNull(
                 String.format("Device in bad state: %s is not as expected",
                         Settings.Global.HIDDEN_API_POLICY),
-                null,
                 getGlobalHiddenApiPolicy());
 
 
@@ -105,17 +115,25 @@
                 new BootClassPathClassesProvider(),
                 name -> name != null && name.startsWith("com.android.internal.R."));
 
+        String dynamicConfigName = instrumentationArgs.getString(DYNAMIC_CONFIG_NAME_OPTION);
+        if (dynamicConfigName != null) {
+            // Get the DynamicConfig.xml contents and extract the expected failures list.
+            DynamicConfigDeviceSide dcds = new DynamicConfigDeviceSide(dynamicConfigName);
+            Collection<String> expectedFailures = dcds.getValues("expected_failures");
+            initExpectedFailures(expectedFailures);
+        }
+
         initializeFromArgs(instrumentationArgs);
     }
 
     /**
      * Initialize the expected failures.
      *
-     * <p>Call from with {@code #initializeFromArgs}</p>
+     * <p>Call from with {@link #setUp()}</p>
      *
      * @param expectedFailures the expected failures.
      */
-    protected void initExpectedFailures(Collection<String> expectedFailures) {
+    private void initExpectedFailures(Collection<String> expectedFailures) {
         this.expectedFailures = expectedFailures;
         String tag = getClass().getName();
         Log.d(tag, "Expected failure count: " + expectedFailures.size());
@@ -129,7 +147,6 @@
     }
 
     protected void initializeFromArgs(Bundle instrumentationArgs) throws Exception {
-
     }
 
     protected interface RunnableWithResultObserver {
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 427f62d..2f77728 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
@@ -23,13 +23,14 @@
 import android.signature.cts.DexMemberChecker;
 import android.signature.cts.DexMethod;
 import android.signature.cts.FailureType;
+import org.junit.Test;
 
 public abstract class BaseKillswitchTest extends AbstractApiTest {
 
     protected String mErrorMessageAppendix;
 
     @Override
-    protected void setUp() throws Exception {
+    public void setUp() throws Exception {
         super.setUp();
         DexMemberChecker.init();
     }
@@ -43,18 +44,22 @@
     private final static Predicate<DexMember> FIELD_FILTER =
             dexMember -> (dexMember instanceof DexField);
 
+    @Test
     public void testKillswitchMechanismMethodsThroughReflection() {
         doTestKillswitchMechanism(METHOD_FILTER, /* reflection= */ true, /* jni= */ false);
     }
 
+    @Test
     public void testKillswitchMechanismMethodsThroughJni() {
         doTestKillswitchMechanism(METHOD_FILTER, /* reflection= */ false, /* jni= */ true);
     }
 
+    @Test
     public void testKillswitchMechanismFieldsThroughReflection() {
         doTestKillswitchMechanism(FIELD_FILTER, /* reflection= */ true, /* jni= */ false);
     }
 
+    @Test
     public void testKillswitchMechanismFieldsThroughJni() {
         doTestKillswitchMechanism(FIELD_FILTER, /* reflection= */ false, /* jni= */ true);
     }
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/DebugClassKillswitchTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/DebugClassKillswitchTest.java
index 7a5e900..84fabca 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/DebugClassKillswitchTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/DebugClassKillswitchTest.java
@@ -18,9 +18,11 @@
 
 import android.signature.cts.DexMemberChecker;
 
+import static org.junit.Assert.assertTrue;
+
 public class DebugClassKillswitchTest extends BaseKillswitchTest {
     @Override
-    protected void setUp() throws Exception {
+    public void setUp() throws Exception {
         super.setUp();
 
         mErrorMessageAppendix = " to exempted DexMemberChecker class";
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 97ae404..9082c47 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
@@ -31,6 +31,7 @@
 import java.util.HashSet;
 import java.util.Set;
 import java.util.function.Predicate;
+import org.junit.Test;
 
 /**
  * Checks that it is not possible to access hidden APIs.
@@ -51,7 +52,7 @@
     }
 
     @Override
-    protected void setUp() throws Exception {
+    public void setUp() throws Exception {
         super.setUp();
         DexMemberChecker.init();
         loadFilters();
@@ -65,18 +66,22 @@
     private final static Predicate<DexMember> FIELD_FILTER =
             dexMember -> (dexMember instanceof DexField);
 
+    @Test
     public void testSignatureMethodsThroughReflection() {
         doTestSignature(METHOD_FILTER,/* reflection= */ true, /* jni= */ false);
     }
 
+    @Test
     public void testSignatureMethodsThroughJni() {
         doTestSignature(METHOD_FILTER, /* reflection= */ false, /* jni= */ true);
     }
 
+    @Test
     public void testSignatureFieldsThroughReflection() {
         doTestSignature(FIELD_FILTER, /* reflection= */ true, /* jni= */ false);
     }
 
+    @Test
     public void testSignatureFieldsThroughJni() {
         doTestSignature(FIELD_FILTER, /* reflection= */ false, /* jni= */ true);
     }
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/SdkListKillswitchTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/SdkListKillswitchTest.java
index 9e85b92..fc667eb 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/SdkListKillswitchTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/SdkListKillswitchTest.java
@@ -18,7 +18,7 @@
 
 public class SdkListKillswitchTest extends BaseKillswitchTest {
     @Override
-    protected void setUp() throws Exception {
+    public void setUp() throws Exception {
         super.setUp();
         mErrorMessageAppendix = " when global setting hidden_api_blacklist_exemptions is \"L\"";
     }
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 4a0e2c2..1be75ca 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
@@ -28,6 +28,7 @@
 import java.util.TreeSet;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import org.junit.Test;
 
 /**
  * Performs the signature check via a JUnit test.
@@ -60,6 +61,7 @@
      * <p/>
      * Will check the entire API, and then report the complete list of failures
      */
+    @Test
     public void testSignature() {
         runWithTestResultObserver(mResultObserver -> {
             Set<JDiffClassDescription> unexpectedClasses = loadUnexpectedClasses();
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/WildcardKillswitchTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/WildcardKillswitchTest.java
index 1cdd7d9..8eb31c6 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/WildcardKillswitchTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/WildcardKillswitchTest.java
@@ -18,7 +18,7 @@
 
 public class WildcardKillswitchTest extends BaseKillswitchTest {
     @Override
-    protected void setUp() throws Exception {
+    public void setUp() throws Exception {
         super.setUp();
         mErrorMessageAppendix = " when global setting hidden_api_blacklist_exemptions is \"*\"";
     }
diff --git a/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java b/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java
index bdc5b2a..e6d5b06 100644
--- a/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java
+++ b/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java
@@ -32,6 +32,7 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.function.Predicate;
+import org.junit.Test;
 
 /**
  * Checks that parts of the device's API that are annotated (e.g. with android.annotation.SystemApi)
@@ -40,7 +41,6 @@
 public class AnnotationTest extends AbstractApiTest {
 
     private static final String TAG = AnnotationTest.class.getSimpleName();
-    private static final String MODULE_NAME = "CtsSystemApiAnnotationTestCases";
 
     private String[] mExpectedApiFiles;
     private String mAnnotationForExactMatch;
@@ -49,11 +49,6 @@
     protected void initializeFromArgs(Bundle instrumentationArgs) throws Exception {
         mExpectedApiFiles = getCommaSeparatedListRequired(instrumentationArgs, "expected-api-files");
         mAnnotationForExactMatch = instrumentationArgs.getString("annotation-for-exact-match");
-
-        // Get the DynamicConfig.xml contents and extract the expected failures list.
-        DynamicConfigDeviceSide dcds = new DynamicConfigDeviceSide(MODULE_NAME);
-        List<String> expectedFailures = dcds.getValues("expected_failures");
-        initExpectedFailures(expectedFailures);
     }
 
     private Predicate<? super JDiffClassDescription> androidAutoClassesFilter() {
@@ -69,6 +64,7 @@
      * Tests that the parts of the device's API that are annotated (e.g. with
      * android.annotation.SystemApi) match the API definition.
      */
+    @Test
     public void testAnnotation() {
        AnnotationChecker.ResultFilter filter = new AnnotationChecker.ResultFilter() {
             @Override
diff --git a/tests/signature/api-check/system-api/Android.bp b/tests/signature/api-check/system-api/Android.bp
index 0c3d2a5..7263c84 100644
--- a/tests/signature/api-check/system-api/Android.bp
+++ b/tests/signature/api-check/system-api/Android.bp
@@ -19,14 +19,12 @@
 
 android_test {
     name: "CtsSystemApiSignatureTestCases",
-    defaults: ["signature-api-check-dynamic-config-defaults"],
+    defaults: ["signature-api-check-defaults"],
     java_resources: [
         ":CtsSystemApiSignatureTestCases_system-all.api",
         ":cts-current-api-gz",
         ":cts-system-current-api-gz",
         ":cts-system-removed-api-gz",
-        ":cts-android-test-mock-current-api-gz",
-        ":cts-android-test-runner-current-api-gz",
     ],
     test_suites: [
         "cts",
diff --git a/tests/signature/api-check/system-api/src/android/signature/cts/api/system/SignatureTest.java b/tests/signature/api-check/system-api/src/android/signature/cts/api/system/SignatureTest.java
index e523152..1997826 100644
--- a/tests/signature/api-check/system-api/src/android/signature/cts/api/system/SignatureTest.java
+++ b/tests/signature/api-check/system-api/src/android/signature/cts/api/system/SignatureTest.java
@@ -16,7 +16,5 @@
 
 package android.signature.cts.api.system;
 
-import java.android.signature.cts.api.dynamic.DynamicConfigSignatureTest;
-
-public class SignatureTest extends DynamicConfigSignatureTest {
+public class SignatureTest extends android.signature.cts.api.SignatureTest  {
 }
diff --git a/tests/signature/api-check/with-dynamic-config/Android.bp b/tests/signature/api-check/with-dynamic-config/Android.bp
deleted file mode 100644
index bdeb878..0000000
--- a/tests/signature/api-check/with-dynamic-config/Android.bp
+++ /dev/null
@@ -1,30 +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.
-
-// Compat.
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-java_library {
-    name: "cts-signature-with-dynamic-config",
-    visibility: [
-        "//cts/tests/signature:__subpackages__",
-    ],
-    static_libs: [
-        "cts-api-signature-test",
-        "compatibility-device-util-axt",
-    ],
-    srcs: ["src/java/**/*.java"],
-}
diff --git a/tests/signature/api-check/with-dynamic-config/src/java/android/signature/cts/api/dynamic/DynamicConfigHiddenApiTest.java b/tests/signature/api-check/with-dynamic-config/src/java/android/signature/cts/api/dynamic/DynamicConfigHiddenApiTest.java
deleted file mode 100644
index 1c3dfbc..0000000
--- a/tests/signature/api-check/with-dynamic-config/src/java/android/signature/cts/api/dynamic/DynamicConfigHiddenApiTest.java
+++ /dev/null
@@ -1,48 +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.signature.cts.api.dynamic;
-
-import android.os.Bundle;
-import android.signature.cts.api.HiddenApiTest;
-import android.signature.cts.api.SignatureTest;
-import androidx.test.InstrumentationRegistry;
-import com.android.compatibility.common.util.DynamicConfigDeviceSide;
-import java.util.Collection;
-
-/**
- * A hidden API test that supports the use of dynamic config.
- */
-public class DynamicConfigHiddenApiTest extends HiddenApiTest {
-
-    /**
-     * The name of the optional instrumentation option that contains the name of the dynamic config
-     * data set that contains the expected failures.
-     */
-    private static final String DYNAMIC_CONFIG_NAME_OPTION = "dynamic-config-name";
-
-    @Override
-    protected void initializeFromArgs(Bundle instrumentationArgs) throws Exception {
-        super.initializeFromArgs(instrumentationArgs);
-
-        String dynamicConfigName = instrumentationArgs.getString(DYNAMIC_CONFIG_NAME_OPTION);
-        if (dynamicConfigName != null) {
-            // Get the DynamicConfig.xml contents and extract the expected failures list.
-            DynamicConfigDeviceSide dcds = new DynamicConfigDeviceSide(dynamicConfigName);
-            Collection<String> expectedFailures = dcds.getValues("expected_failures");
-            initExpectedFailures(expectedFailures);
-        }
-    }
-}
diff --git a/tests/signature/api-check/with-dynamic-config/src/java/android/signature/cts/api/dynamic/DynamicConfigSignatureTest.java b/tests/signature/api-check/with-dynamic-config/src/java/android/signature/cts/api/dynamic/DynamicConfigSignatureTest.java
deleted file mode 100644
index 9c57a1e..0000000
--- a/tests/signature/api-check/with-dynamic-config/src/java/android/signature/cts/api/dynamic/DynamicConfigSignatureTest.java
+++ /dev/null
@@ -1,47 +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 java.android.signature.cts.api.dynamic;
-
-import android.os.Bundle;
-import android.signature.cts.api.SignatureTest;
-import androidx.test.InstrumentationRegistry;
-import com.android.compatibility.common.util.DynamicConfigDeviceSide;
-import java.util.Collection;
-
-/**
- * A signature test that supports the use of dynamic config.
- */
-public class DynamicConfigSignatureTest extends SignatureTest {
-
-    /**
-     * The name of the optional instrumentation option that contains the name of the dynamic config
-     * data set that contains the expected failures.
-     */
-    private static final String DYNAMIC_CONFIG_NAME_OPTION = "dynamic-config-name";
-
-    @Override
-    protected void initializeFromArgs(Bundle instrumentationArgs) throws Exception {
-        super.initializeFromArgs(instrumentationArgs);
-
-        String dynamicConfigName = instrumentationArgs.getString(DYNAMIC_CONFIG_NAME_OPTION);
-        if (dynamicConfigName != null) {
-            // Get the DynamicConfig.xml contents and extract the expected failures list.
-            DynamicConfigDeviceSide dcds = new DynamicConfigDeviceSide(dynamicConfigName);
-            Collection<String> expectedFailures = dcds.getValues("expected_failures");
-            initExpectedFailures(expectedFailures);
-        }
-    }
-}
diff --git a/tests/signature/lib/common/src/android/signature/cts/ApiComplianceChecker.java b/tests/signature/lib/common/src/android/signature/cts/ApiComplianceChecker.java
index fe67157..d38e51e 100644
--- a/tests/signature/lib/common/src/android/signature/cts/ApiComplianceChecker.java
+++ b/tests/signature/lib/common/src/android/signature/cts/ApiComplianceChecker.java
@@ -31,23 +31,6 @@
  */
 public class ApiComplianceChecker extends ApiPresenceChecker {
 
-    /**
-     * A set of method signatures whose abstract modifier should be ignored.
-     *
-     * <p>If a class is not intended to be created or extended by application developers and all
-     * instances are created and supplied by Android itself then the abstract modifier has no
-     * impact on runtime compatibility.
-     */
-    private static final Set<String> IGNORE_METHOD_ABSTRACT_MODIFIER_WHITE_LIST = new HashSet<>();
-    static {
-        // This method was previously abstract and is now not abstract. As the
-        // CtsSystemApiSignatureTestCases package tests both the old and new specifications, with
-        // and without the abstract modifier this needs to ignore the abstract modifier.
-        IGNORE_METHOD_ABSTRACT_MODIFIER_WHITE_LIST.add(
-                "public int android.service.euicc.EuiccService.onDownloadSubscription("
-                        + "int,android.telephony.euicc.DownloadableSubscription,boolean,boolean)");
-    }
-
     /** Indicates that the class is an annotation. */
     private static final int CLASS_MODIFIER_ANNOTATION = 0x00002000;
 
@@ -120,21 +103,89 @@
     }
 
     /**
-     * Check if it is allowed that a class is in previous system Api and changed to abstract class
-     * in current API.
+     * Check if the class definition is from a previous API and was neither instantiable nor
+     * extensible through that API.
+     *
+     * <p>Such a class is more flexible in how it can be modified than other classes as there is
+     * no way to either create or extend the class.</p>
+     *
+     * <p>A class that has no constructors in the API cannot be instantiated or extended. Such a
+     * class has a lot more flexibility when it comes to making forwards compatible changes than
+     * other classes. e.g. Normally, a non-final class cannot be made final as that would break any
+     * code that extended the class but if there are no constructors in the API then it is
+     * impossible to extend it through the API so making it final is forwards compatible.</p>
+     *
+     * <p>Similarly, a concrete class cannot normally be made abstract as that would break any code
+     * that attempted to instantiate it but if there are no constructors in the API then it is
+     * impossible to instantiate it so making it abstract is forwards compatible.</p>
+     *
+     * <p>Finally, a non-static class cannot normally be made static (or vice versa) as that would
+     * break any code that attemped to instantiate it but if there are no constructors in the API
+     * then it is impossible to instantiate so changing the static flag is forwards compatible.</p>
+     *
+     * <p>In a similar fashion the abstract and final (but not static) modifier can be added to a
+     * method on this type of class.</p>
+     *
+     * <p>In this case forwards compatible is restricted to compile time and runtime behavior. It
+     * does not cover testing. e.g. making a class that was previously non-final could break tests
+     * that relied on mocking that class. However, that is a non-standard use of the API and so we
+     * are not strictly required to maintain compatibility in that case. It should also only be a
+     * minor issue as most mocking libraries support mocking final classes now.</p>
+     *
      * @param classDescription a description of a class in an API.
-     * @param runtimeClass the runtime class corresponding to {@code classDescription}.
-     * @return true if the change is allowed.
      */
-    private static boolean isAllowedClassAbstractionFromPreviousSystemApi(
-            JDiffClassDescription classDescription, Class<?> runtimeClass) {
-        // Allow a class that was previously final and had no visible constructors,
-        // (so could not be instantiated or extended) to be changed to an abstract class.
+    private static boolean classIsNotInstantiableOrExtensibleInPreviousApi(
+            JDiffClassDescription classDescription) {
         return classDescription.getConstructors().isEmpty()
-                && (classDescription.getModifier() & Modifier.FINAL) != 0
-                && (classDescription.getModifier() & Modifier.ABSTRACT) == 0
-                && classDescription.isPreviousApi()
-                && (runtimeClass.getModifiers() & Modifier.ABSTRACT) != 0;
+                && classDescription.isPreviousApi();
+    }
+
+    /**
+     * If a modifier (final or abstract) has been removed since the previous API was published then
+     * it is forwards compatible so clear the modifier flag in the previous API modifiers so that it
+     * does not cause a mismatch.
+     *
+     * @param previousModifiers The set of modifiers for the previous API.
+     * @param currentModifiers The set of modifiers for the current implementation class.
+     * @return the normalized previous modifiers.
+     */
+    private static int normalizePreviousModifiersIfModifierIsRemoved(
+            int previousModifiers, int currentModifiers, int... flags) {
+        for (int flag : flags) {
+            // If the flag was present in the previous API but is no longer present then the
+            // modifier has been removed.
+            if ((previousModifiers & flag) != 0 && (currentModifiers & flag) == 0) {
+                previousModifiers &= ~flag;
+            }
+        }
+
+        return previousModifiers;
+    }
+
+    /**
+     * If a modifier (final or abstract) has been added since the previous API was published then
+     * this treats it as forwards compatible and clears the modifier flag in the current API
+     * modifiers so that it does not cause a mismatch.
+     *
+     * <p>This must only be called when adding one of the supplied modifiers is forwards compatible,
+     * e.g. when called on a class or methods from a class that returns true for
+     * {@link #classIsNotInstantiableOrExtensibleInPreviousApi(JDiffClassDescription)}.</p>
+     *
+     * @param previousModifiers The set of modifiers for the previous API.
+     * @param currentModifiers The set of modifiers for the current implementation class.
+     * @return the normalized current modifiers.
+     */
+    private static int normalizeCurrentModifiersIfModifierIsAdded(
+            int previousModifiers, int currentModifiers, int... flags) {
+        for (int flag : flags) {
+            // If the flag was not present in the previous API but is present then the modifier has
+            // been added.
+            if ((previousModifiers & flag) == 0 && (currentModifiers & flag) != 0) {
+                currentModifiers &= ~flag;
+            }
+        }
+
+        return currentModifiers;
     }
 
     /**
@@ -149,22 +200,11 @@
         int reflectionModifiers = runtimeClass.getModifiers();
         int apiModifiers = classDescription.getModifier();
 
-        // If the api class isn't abstract
-        if (((apiModifiers & Modifier.ABSTRACT) == 0) &&
-                // but the reflected class is
-                ((reflectionModifiers & Modifier.ABSTRACT) != 0) &&
-                // interfaces are implicitly abstract (JLS 9.1.1.1)
-                classDescription.getClassType() != JDiffClassDescription.JDiffType.INTERFACE &&
-                // and it isn't an enum
-                !classDescription.isEnumType() &&
-                // and it isn't allowed previous api final class with no visible ctor
-                !isAllowedClassAbstractionFromPreviousSystemApi(classDescription, runtimeClass)) {
-            // that is a problem
-            return "description is abstract but class is not and is not an enum";
+        // If the api class is an interface then always treat it as abstract.
+        // interfaces are implicitly abstract (JLS 9.1.1.1)
+        if (classDescription.getClassType() == JDiffClassDescription.JDiffType.INTERFACE) {
+            apiModifiers |= Modifier.ABSTRACT;
         }
-        // ABSTRACT check passed, so mask off ABSTRACT
-        reflectionModifiers &= ~Modifier.ABSTRACT;
-        apiModifiers &= ~Modifier.ABSTRACT;
 
         if (classDescription.isAnnotation()) {
             reflectionModifiers &= ~CLASS_MODIFIER_ANNOTATION;
@@ -179,21 +219,32 @@
             // override a method from the class cannot be marked as final because those constants
             // are represented as a subclass. As enum classes cannot be extended (except for its own
             // constants) there is no benefit in checking final modifier so just ignore them.
-            reflectionModifiers &= ~Modifier.FINAL;
-            apiModifiers &= ~Modifier.FINAL;
+            //
+            // Ditto for abstract.
+            reflectionModifiers &= ~(Modifier.FINAL | Modifier.ABSTRACT);
+            apiModifiers &= ~(Modifier.FINAL | Modifier.ABSTRACT);
         }
 
-        // Allow previous final API to be changed to abstract or static, and other modifiers should
-        // not be changed.
-        boolean isAllowedPreviousApiModifierChange =
-                isAllowedClassAbstractionFromPreviousSystemApi(classDescription, runtimeClass)
-                && (apiModifiers & ~Modifier.FINAL) != 0
-                && (reflectionModifiers & ~(Modifier.ABSTRACT | Modifier.STATIC))
-                == (apiModifiers & ~Modifier.FINAL);
+        if (classDescription.isPreviousApi()) {
+            // If the final and/or abstract modifiers have been removed since the previous API was
+            // published then that is forwards compatible so remove the modifier in the previous API
+            // modifiers so they match the runtime modifiers.
+            apiModifiers = normalizePreviousModifiersIfModifierIsRemoved(
+                    apiModifiers, reflectionModifiers, Modifier.FINAL, Modifier.ABSTRACT);
+
+            if (classIsNotInstantiableOrExtensibleInPreviousApi(classDescription)) {
+                // Adding the final, abstract or static flags to the runtime class is forwards
+                // compatible as the class cannot be instantiated or extended. Clear the flags for
+                // any such added modifier from the current implementation's modifiers so that it
+                // does not cause a mismatch.
+                reflectionModifiers = normalizeCurrentModifiersIfModifierIsAdded(
+                        apiModifiers, reflectionModifiers,
+                        Modifier.FINAL, Modifier.ABSTRACT, Modifier.STATIC);
+            }
+        }
 
         if ((reflectionModifiers == apiModifiers)
-                && (classDescription.isEnumType() == runtimeClass.isEnum())
-                || isAllowedPreviousApiModifierChange) {
+                && (classDescription.isEnumType() == runtimeClass.isEnum())) {
             return null;
         } else {
             return String.format("modifier mismatch - description (%s), class (%s)",
@@ -473,16 +524,6 @@
     @Override
     protected void checkMethod(JDiffClassDescription classDescription, Class<?> runtimeClass,
             JDiffClassDescription.JDiffMethod methodDescription, Method method) {
-        if (method.isVarArgs()) {
-            methodDescription.mModifier |= METHOD_MODIFIER_VAR_ARGS;
-        }
-        if (method.isBridge()) {
-            methodDescription.mModifier |= METHOD_MODIFIER_BRIDGE;
-        }
-        if (method.isSynthetic()) {
-            methodDescription.mModifier |= METHOD_MODIFIER_SYNTHETIC;
-        }
-
         // FIXME: A workaround to fix the final mismatch on enumeration
         if (runtimeClass.isEnum() && methodDescription.mName.equals("values")) {
             return;
@@ -491,12 +532,6 @@
         String reason;
         if ((reason = areMethodsModifierCompatible(
                 classDescription, methodDescription, method)) != null) {
-            // Allow previous API method to be changed to abstract
-            if (isAllowedClassAbstractionFromPreviousSystemApi(classDescription, runtimeClass)
-                    && (method.getModifiers() & ~(Modifier.ABSTRACT))
-                    == methodDescription.mModifier) {
-                return;
-            }
             resultObserver.notifyFailure(FailureType.MISMATCH_METHOD,
                     methodDescription.toReadableString(classDescription.getAbsoluteClassName()),
                     String.format("Non-compatible method found when looking for %s - because %s",
@@ -520,17 +555,15 @@
             JDiffClassDescription.JDiffMethod apiMethod,
             Method reflectedMethod) {
 
-        // Mask off NATIVE since it is a don't care.  Also mask off
-        // SYNCHRONIZED since it is not considered API significant (b/112626813)
-        int ignoredMods = (Modifier.NATIVE | Modifier.SYNCHRONIZED | Modifier.STRICT);
+        // Mask off NATIVE since it is a don't care.
+        // Mask off SYNCHRONIZED since it is not considered API significant (b/112626813)
+        // Mask off STRICT as it has no effect (b/26082535)
+        // Mask off SYNTHETIC, VARARGS and BRIDGE as they are not represented in the API.
+        int ignoredMods = (Modifier.NATIVE | Modifier.SYNCHRONIZED | Modifier.STRICT |
+                METHOD_MODIFIER_SYNTHETIC | METHOD_MODIFIER_VAR_ARGS | METHOD_MODIFIER_BRIDGE);
         int reflectionModifiers = reflectedMethod.getModifiers() & ~ignoredMods;
         int apiModifiers = apiMethod.mModifier & ~ignoredMods;
 
-        // A method can become non-abstract
-        if ((reflectionModifiers & Modifier.ABSTRACT) == 0) {
-            apiModifiers &= ~Modifier.ABSTRACT;
-        }
-
         // We can ignore FINAL for classes
         if ((classDescription.getModifier() & Modifier.FINAL) != 0) {
             reflectionModifiers &= ~Modifier.FINAL;
@@ -538,9 +571,21 @@
         }
 
         String genericString = reflectedMethod.toGenericString();
-        if (IGNORE_METHOD_ABSTRACT_MODIFIER_WHITE_LIST.contains(genericString)) {
-            reflectionModifiers &= ~Modifier.ABSTRACT;
-            apiModifiers &= ~Modifier.ABSTRACT;
+        if (classDescription.isPreviousApi()) {
+            // If the final and/or abstract modifiers have been removed since the previous API was
+            // published then that is forwards compatible so remove the modifier in the previous API
+            // modifiers so they match the runtime modifiers.
+            apiModifiers = normalizePreviousModifiersIfModifierIsRemoved(
+                    apiModifiers, reflectionModifiers, Modifier.FINAL, Modifier.ABSTRACT);
+
+            if (classIsNotInstantiableOrExtensibleInPreviousApi(classDescription)) {
+                // Adding the final, or abstract flags to the runtime method is forwards compatible
+                // as the class cannot be instantiated or extended. Clear the flags for any such
+                // added modifier from the current implementation's modifiers so that it does not
+                // cause a mismatch.
+                reflectionModifiers = normalizeCurrentModifiersIfModifierIsAdded(
+                        apiModifiers, reflectionModifiers, Modifier.FINAL, Modifier.ABSTRACT);
+            }
         }
 
         if (reflectionModifiers == apiModifiers) {
diff --git a/tests/signature/lib/common/src/android/signature/cts/JDiffClassDescription.java b/tests/signature/lib/common/src/android/signature/cts/JDiffClassDescription.java
index 7c590e1..ab66aa8 100644
--- a/tests/signature/lib/common/src/android/signature/cts/JDiffClassDescription.java
+++ b/tests/signature/lib/common/src/android/signature/cts/JDiffClassDescription.java
@@ -516,7 +516,7 @@
      *
      * @param extendsClass the class being extended.
      */
-    void setExtendsClass(String extendsClass) {
+    public void setExtendsClass(String extendsClass) {
         mExtendedClass = extendsClass;
     }
 
diff --git a/tests/signature/tests/src/android/signature/cts/tests/AnnotationCheckerTest.java b/tests/signature/tests/src/android/signature/cts/tests/AnnotationCheckerTest.java
index 13b5fd9..aa0da74 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/AnnotationCheckerTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/AnnotationCheckerTest.java
@@ -83,29 +83,29 @@
      */
     @Test
     public void testDetectUnauthorizedConstructorApi() {
-        ExpectFailure observer = new ExpectFailure(FailureType.EXTRA_CONSTRUCTOR);
+        try (ExpectFailure observer = new ExpectFailure(FailureType.EXTRA_CONSTRUCTOR)) {
+            JDiffClassDescription clz = createClass("SystemApiClass");
+            // (omitted) addConstructor(clz);
+            addPublicVoidMethod(clz, "apiMethod");
+            addPublicBooleanField(clz, "apiField");
 
-        JDiffClassDescription clz = createClass("SystemApiClass");
-        // (omitted) addConstructor(clz);
-        addPublicVoidMethod(clz, "apiMethod");
-        addPublicBooleanField(clz, "apiField");
+            checkSignatureCompliance(clz, observer,
+                    "android.signature.cts.tests.data.PublicApiClass",
+                    "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
+        }
 
-        checkSignatureCompliance(clz, observer,
-                "android.signature.cts.tests.data.PublicApiClass",
-                "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
-        observer.validate();
+        try (ExpectFailure observer = new ExpectFailure(FailureType.EXTRA_CONSTRUCTOR)) {
+            JDiffClassDescription clz = createClass("PublicApiClass");
 
-        observer = new ExpectFailure(FailureType.EXTRA_CONSTRUCTOR);
+            // (omitted) addConstructor(clz);
+            addPublicVoidMethod(clz, "apiMethod");
 
-        clz = createClass("PublicApiClass");
-        // (omitted) addConstructor(clz);
-        addPublicVoidMethod(clz, "apiMethod");
-        addPublicBooleanField(clz, "apiField");
+            addPublicBooleanField(clz, "apiField");
 
-        checkSignatureCompliance(clz, observer,
+            checkSignatureCompliance(clz, observer,
                 "android.signature.cts.tests.data.SystemApiClass",
-                "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
-        observer.validate();
+                        "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
+        }
     }
 
     /**
@@ -113,29 +113,27 @@
      */
     @Test
     public void testDetectUnauthorizedMethodApi() {
-        ExpectFailure observer = new ExpectFailure(FailureType.EXTRA_METHOD);
+        try (ExpectFailure observer = new ExpectFailure(FailureType.EXTRA_METHOD)) {
+            JDiffClassDescription clz = createClass("SystemApiClass");
+            addConstructor(clz);
+            // (omitted) addPublicVoidMethod(clz, "apiMethod");
+            addPublicBooleanField(clz, "apiField");
 
-        JDiffClassDescription clz = createClass("SystemApiClass");
-        addConstructor(clz);
-        // (omitted) addPublicVoidMethod(clz, "apiMethod");
-        addPublicBooleanField(clz, "apiField");
+            checkSignatureCompliance(clz, observer,
+                    "android.signature.cts.tests.data.PublicApiClass",
+                    "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
+        }
 
-        checkSignatureCompliance(clz, observer,
-                "android.signature.cts.tests.data.PublicApiClass",
-                "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
-        observer.validate();
+        try (ExpectFailure observer = new ExpectFailure(FailureType.EXTRA_METHOD)) {
+            JDiffClassDescription clz = createClass("PublicApiClass");
+            addConstructor(clz);
+            // (omitted) addPublicVoidMethod(clz, "apiMethod");
+            addPublicBooleanField(clz, "apiField");
 
-        observer = new ExpectFailure(FailureType.EXTRA_METHOD);
-
-        clz = createClass("PublicApiClass");
-        addConstructor(clz);
-        // (omitted) addPublicVoidMethod(clz, "apiMethod");
-        addPublicBooleanField(clz, "apiField");
-
-        checkSignatureCompliance(clz, observer,
-                "android.signature.cts.tests.data.SystemApiClass",
-                "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
-        observer.validate();
+            checkSignatureCompliance(clz, observer,
+                    "android.signature.cts.tests.data.SystemApiClass",
+                    "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
+        }
     }
 
     /**
@@ -143,29 +141,27 @@
      */
     @Test
     public void testDetectUnauthorizedFieldApi() {
-        ExpectFailure observer = new ExpectFailure(FailureType.EXTRA_FIELD);
+        try (ExpectFailure observer = new ExpectFailure(FailureType.EXTRA_FIELD)) {
+            JDiffClassDescription clz = createClass("SystemApiClass");
+            addConstructor(clz);
+            addPublicVoidMethod(clz, "apiMethod");
+            // (omitted) addPublicBooleanField(clz, "apiField");
 
-        JDiffClassDescription clz = createClass("SystemApiClass");
-        addConstructor(clz);
-        addPublicVoidMethod(clz, "apiMethod");
-        // (omitted) addPublicBooleanField(clz, "apiField");
+            checkSignatureCompliance(clz, observer,
+                    "android.signature.cts.tests.data.PublicApiClass",
+                    "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
+        }
 
-        checkSignatureCompliance(clz, observer,
-                "android.signature.cts.tests.data.PublicApiClass",
-                "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
-        observer.validate();
+        try (ExpectFailure observer = new ExpectFailure(FailureType.EXTRA_FIELD)) {
+            JDiffClassDescription clz = createClass("PublicApiClass");
+            addConstructor(clz);
+            addPublicVoidMethod(clz, "apiMethod");
+            // (omitted) addPublicBooleanField(clz, "apiField");
 
-        observer = new ExpectFailure(FailureType.EXTRA_FIELD);
-
-        clz = createClass("PublicApiClass");
-        addConstructor(clz);
-        addPublicVoidMethod(clz, "apiMethod");
-        // (omitted) addPublicBooleanField(clz, "apiField");
-
-        checkSignatureCompliance(clz, observer,
-                "android.signature.cts.tests.data.SystemApiClass",
-                "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
-        observer.validate();
+            checkSignatureCompliance(clz, observer,
+                    "android.signature.cts.tests.data.SystemApiClass",
+                    "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
+        }
     }
 
     /**
@@ -173,28 +169,27 @@
      */
     @Test
     public void testDetectUnauthorizedClassApi() {
-        ExpectFailure observer = new ExpectFailure(FailureType.EXTRA_CLASS);
-        JDiffClassDescription clz = createClass("SystemApiClass");
-        addConstructor(clz);
-        addPublicVoidMethod(clz, "apiMethod");
-        addPublicBooleanField(clz, "apiField");
+        try (ExpectFailure observer = new ExpectFailure(FailureType.EXTRA_CLASS)) {
+            JDiffClassDescription clz = createClass("SystemApiClass");
+            addConstructor(clz);
+            addPublicVoidMethod(clz, "apiMethod");
+            addPublicBooleanField(clz, "apiField");
 
-        checkSignatureCompliance(clz, observer,
-                "android.signature.cts.tests.data.PublicApiClass");
-        // Note that ForciblyPublicizedPrivateClass is now included in the runtime classes
-        observer.validate();
+            checkSignatureCompliance(clz, observer,
+                    "android.signature.cts.tests.data.PublicApiClass");
+            // Note that ForciblyPublicizedPrivateClass is now included in the runtime classes
+        }
 
-        observer = new ExpectFailure(FailureType.EXTRA_CLASS);
+        try (ExpectFailure observer = new ExpectFailure(FailureType.EXTRA_CLASS)) {
+            JDiffClassDescription clz = createClass("PublicApiClass");
+            addConstructor(clz);
+            addPublicVoidMethod(clz, "apiMethod");
+            addPublicBooleanField(clz, "apiField");
 
-        clz = createClass("PublicApiClass");
-        addConstructor(clz);
-        addPublicVoidMethod(clz, "apiMethod");
-        addPublicBooleanField(clz, "apiField");
-
-        checkSignatureCompliance(clz, observer,
-                "android.signature.cts.tests.data.SystemApiClass");
-        // Note that ForciblyPublicizedPrivateClass is now included in the runtime classes
-        observer.validate();
+            checkSignatureCompliance(clz, observer,
+                    "android.signature.cts.tests.data.SystemApiClass");
+            // Note that ForciblyPublicizedPrivateClass is now included in the runtime classes
+        }
     }
 
     /**
@@ -243,44 +238,41 @@
      */
     @Test
     public void testDetectMissingAnnotation() {
-        ExpectFailure observer = new ExpectFailure(FailureType.MISSING_ANNOTATION);
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISSING_ANNOTATION)) {
+            JDiffClassDescription clz = createClass("PublicApiClass");
+            addConstructor(clz);
+            addPublicVoidMethod(clz, "apiMethod");
+            addPublicBooleanField(clz, "apiField");
+            addConstructor(clz, "int"); // this is not annotated
 
-        JDiffClassDescription clz = createClass("PublicApiClass");
-        addConstructor(clz);
-        addPublicVoidMethod(clz, "apiMethod");
-        addPublicBooleanField(clz, "apiField");
-        addConstructor(clz, "int"); // this is not annotated
+            checkSignatureCompliance(clz, observer,
+                    "android.signature.cts.tests.data.SystemApiClass",
+                    "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
+        }
 
-        checkSignatureCompliance(clz, observer,
-                "android.signature.cts.tests.data.SystemApiClass",
-                "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
-        observer.validate();
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISSING_ANNOTATION)) {
+            JDiffClassDescription clz = createClass("PublicApiClass");
+            addConstructor(clz);
+            addPublicVoidMethod(clz, "apiMethod");
+            addPublicBooleanField(clz, "apiField");
+            addPublicVoidMethod(clz, "privateMethod"); // this is not annotated
 
-        observer = new ExpectFailure(FailureType.MISSING_ANNOTATION);
+            checkSignatureCompliance(clz, observer,
+                    "android.signature.cts.tests.data.SystemApiClass",
+                    "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
+        }
 
-        clz = createClass("PublicApiClass");
-        addConstructor(clz);
-        addPublicVoidMethod(clz, "apiMethod");
-        addPublicBooleanField(clz, "apiField");
-        addPublicVoidMethod(clz, "privateMethod"); // this is not annotated
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISSING_ANNOTATION)) {
+            JDiffClassDescription clz = createClass("PublicApiClass");
+            addConstructor(clz);
+            addPublicVoidMethod(clz, "apiMethod");
+            addPublicBooleanField(clz, "apiField");
+            addPublicBooleanField(clz, "privateField"); // this is not annotated
 
-        checkSignatureCompliance(clz, observer,
-                "android.signature.cts.tests.data.SystemApiClass",
-                "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
-        observer.validate();
-
-        observer = new ExpectFailure(FailureType.MISSING_ANNOTATION);
-
-        clz = createClass("PublicApiClass");
-        addConstructor(clz);
-        addPublicVoidMethod(clz, "apiMethod");
-        addPublicBooleanField(clz, "apiField");
-        addPublicBooleanField(clz, "privateField"); // this is not annotated
-
-        checkSignatureCompliance(clz, observer,
-                "android.signature.cts.tests.data.SystemApiClass",
-                "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
-        observer.validate();
+            checkSignatureCompliance(clz, observer,
+                    "android.signature.cts.tests.data.SystemApiClass",
+                    "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
+        }
     }
 
     /**
diff --git a/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java b/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
index c4c87f5..7de9c9d 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
@@ -25,6 +25,8 @@
 import android.signature.cts.JDiffClassDescription;
 import android.signature.cts.ResultObserver;
 import android.signature.cts.tests.data.AbstractClass;
+import android.signature.cts.tests.data.AbstractClassWithCtor;
+import android.signature.cts.tests.data.ComplexEnum;
 import android.signature.cts.tests.data.ExtendedNormalInterface;
 import android.signature.cts.tests.data.NormalClass;
 import android.signature.cts.tests.data.NormalInterface;
@@ -68,19 +70,18 @@
 
     @Test
     public void testMissingClass() {
-        ExpectFailure observer = new ExpectFailure(FailureType.MISSING_CLASS);
-        JDiffClassDescription clz = new JDiffClassDescription(
-                "android.signature.cts.tests.data", "NoSuchClass");
-        clz.setType(JDiffClassDescription.JDiffType.CLASS);
-        checkSignatureCompliance(clz, observer);
-        observer.validate();
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISSING_CLASS)) {
+            JDiffClassDescription clz = new JDiffClassDescription(
+                    "android.signature.cts.tests.data", "NoSuchClass");
+            clz.setType(JDiffClassDescription.JDiffType.CLASS);
+            checkSignatureCompliance(clz, observer);
+        }
     }
 
     @Test
     public void testSimpleConstructor() {
         JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
-        JDiffClassDescription.JDiffConstructor constructor =
-                new JDiffClassDescription.JDiffConstructor("NormalClass", Modifier.PUBLIC);
+        JDiffClassDescription.JDiffConstructor constructor = ctor("NormalClass", Modifier.PUBLIC);
         clz.addConstructor(constructor);
         checkSignatureCompliance(clz);
         assertEquals(constructor.toSignatureString(), "public NormalClass()");
@@ -89,8 +90,7 @@
     @Test
     public void testOneArgConstructor() {
         JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
-        JDiffClassDescription.JDiffConstructor constructor =
-                new JDiffClassDescription.JDiffConstructor("NormalClass", Modifier.PRIVATE);
+        JDiffClassDescription.JDiffConstructor constructor = ctor("NormalClass", Modifier.PRIVATE);
         constructor.addParam("java.lang.String");
         clz.addConstructor(constructor);
         checkSignatureCompliance(clz);
@@ -100,8 +100,7 @@
     @Test
     public void testConstructorThrowsException() {
         JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
-        JDiffClassDescription.JDiffConstructor constructor =
-                new JDiffClassDescription.JDiffConstructor("NormalClass", Modifier.PROTECTED);
+        JDiffClassDescription.JDiffConstructor constructor = ctor("NormalClass", Modifier.PROTECTED);
         constructor.addParam("java.lang.String");
         constructor.addParam("java.lang.String");
         constructor.addException("android.signature.cts.tests.data.NormalException");
@@ -115,8 +114,7 @@
     @Test
     public void testPackageProtectedConstructor() {
         JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
-        JDiffClassDescription.JDiffConstructor constructor =
-                new JDiffClassDescription.JDiffConstructor("NormalClass", 0);
+        JDiffClassDescription.JDiffConstructor constructor = ctor("NormalClass", 0);
         constructor.addParam("java.lang.String");
         constructor.addParam("java.lang.String");
         constructor.addParam("java.lang.String");
@@ -196,6 +194,51 @@
         assertEquals(method.toSignatureString(), "public native void nativeMethod()");
     }
 
+    /**
+     * Check that a varargs method is treated as compliant.
+     */
+    @Test
+    public void testVarargsMethod() {
+        JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
+        JDiffClassDescription.JDiffMethod method = method("varargs",
+                Modifier.PUBLIC, "void");
+        method.addParam("java.lang.String...");
+        clz.addMethod(method);
+        assertEquals(method.toSignatureString(), "public void varargs(java.lang.String...)");
+
+        checkSignatureCompliance(clz);
+    }
+
+    /**
+     * Check that a clone method (which produces a special method that is marked as {@code bridge}
+     * and {@code synthetic}) is treated as compliant.
+     */
+    @Test
+    public void testCloneMethod() {
+        JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
+        // The generic method:
+        //     NormalClass clone() throws CloneNotSupportedException
+        JDiffClassDescription.JDiffMethod method = method("clone",
+                Modifier.PUBLIC, NormalClass.class.getName());
+        method.addException(CloneNotSupportedException.class.getName());
+        clz.addMethod(method);
+        assertEquals(method.toSignatureString(),
+                "public android.signature.cts.tests.data.NormalClass clone()"
+                        + " throws java.lang.CloneNotSupportedException");
+
+        // The synthetic bridge method:
+        //     Object clone() throws CloneNotSupportedException
+        method = method("clone",
+                Modifier.PUBLIC, Object.class.getName());
+        method.addException(CloneNotSupportedException.class.getName());
+        clz.addMethod(method);
+        assertEquals(method.toSignatureString(),
+                "public java.lang.Object clone()"
+                        + " throws java.lang.CloneNotSupportedException");
+
+        checkSignatureCompliance(clz);
+    }
+
     @Test
     public void testFinalField() {
         JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
@@ -281,15 +324,16 @@
 
     @Test
     public void testFieldValueChanged() {
-        ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_FIELD);
-        JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
-        JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
-                "VALUE_FIELD", "java.lang.String",
-                Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC, "\"&#9992;\"");
-        clz.addField(field);
-        checkSignatureCompliance(clz, observer);
-        assertEquals(field.toSignatureString(), "public static final java.lang.String VALUE_FIELD");
-        observer.validate();
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_FIELD)) {
+            JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
+            JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
+                    "VALUE_FIELD", "java.lang.String",
+                    Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC, "\"&#9992;\"");
+            clz.addField(field);
+            checkSignatureCompliance(clz, observer);
+            assertEquals(field.toSignatureString(),
+                    "public static final java.lang.String VALUE_FIELD");
+        }
     }
 
     @Test
@@ -335,6 +379,25 @@
         assertEquals(clz.toSignatureString(), "public interface NormalInterface");
     }
 
+    /**
+     * Always treat interfaces as if they are abstract, even when the modifiers do not specify that.
+     */
+    @Test
+    public void testInterfaceAlwaysTreatAsAbstract() {
+        JDiffClassDescription clz = createInterface("NormalInterface");
+        clz.setModifier(Modifier.PUBLIC);
+        clz.addMethod(method("doSomething", Modifier.ABSTRACT | Modifier.PUBLIC, "void"));
+        checkSignatureCompliance(clz);
+    }
+
+    @Test
+    public void testComplexEnum() {
+        JDiffClassDescription clz = createClass(ComplexEnum.class.getSimpleName());
+        clz.setExtendsClass(Enum.class.getName());
+        clz.setModifier(Modifier.PUBLIC | Modifier.FINAL);
+        checkSignatureCompliance(clz);
+    }
+
     @Test
     public void testFinalClass() {
         JDiffClassDescription clz = new JDiffClassDescription(
@@ -345,6 +408,70 @@
         assertEquals(clz.toSignatureString(), "public final class FinalClass");
     }
 
+    @Test
+    public void testRemovingFinalFromAClass() {
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) {
+            JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
+            clz.setModifier(Modifier.PUBLIC | Modifier.FINAL);
+            checkSignatureCompliance(clz, observer);
+        }
+    }
+
+    @Test
+    public void testRemovingFinalFromAClass_PreviousApi() {
+        JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
+        clz.setModifier(Modifier.PUBLIC | Modifier.FINAL);
+        clz.setPreviousApiFlag(true);
+        checkSignatureCompliance(clz);
+    }
+
+    /**
+     * Test that if the API class is final but the runtime is abstract (and not final) that it is
+     * an error.
+     *
+     * http://b/181019981
+     */
+    @Test
+    public void testRemovingFinalFromAClassSwitchToAbstract() {
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) {
+            JDiffClassDescription clz = createClass(AbstractClass.class.getSimpleName());
+            clz.setModifier(Modifier.PUBLIC | Modifier.FINAL);
+            checkSignatureCompliance(clz, observer);
+        }
+    }
+
+    /**
+     * Test that if the API class in a previous release is final but the runtime is abstract (and
+     * not final) that it is not an error.
+     *
+     * http://b/181019981
+     */
+    @Test
+    public void testRemovingFinalFromAClassSwitchToAbstract_PreviousApi() {
+        JDiffClassDescription clz = createClass(AbstractClass.class.getSimpleName());
+        clz.setModifier(Modifier.PUBLIC | Modifier.FINAL);
+        clz.setPreviousApiFlag(true);
+        checkSignatureCompliance(clz);
+    }
+
+    /**
+     * Test that if the API class in a previous release is final but the runtime is abstract (and
+     * not final) and has constructors then it is an error.
+     * 
+     * http://b/181019981
+     */
+    @Test
+    public void testRemovingFinalFromAClassWithCtorSwitchToAbstract_PreviousApi() {
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) {
+            String simpleName = AbstractClassWithCtor.class.getSimpleName();
+            JDiffClassDescription clz = createClass(simpleName);
+            clz.setModifier(Modifier.PUBLIC | Modifier.FINAL);
+            clz.setPreviousApiFlag(true);
+            clz.addConstructor(ctor(simpleName, Modifier.PUBLIC));
+            checkSignatureCompliance(clz, observer);
+        }
+    }
+
     /**
      * Test the case where the API declares the method is synchronized, but it
      * actually is not.
@@ -396,10 +523,25 @@
      */
     @Test
     public void testRemovingAbstractFromAClass() {
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) {
+            JDiffClassDescription clz = new JDiffClassDescription(
+                    "android.signature.cts.tests.data", "NormalClass");
+            clz.setType(JDiffClassDescription.JDiffType.CLASS);
+            clz.setModifier(Modifier.PUBLIC | Modifier.ABSTRACT);
+            checkSignatureCompliance(clz, observer);
+        }
+    }
+
+    /**
+     * Previous API lists class as abstract, reflection does not. http://b/1839622
+     */
+    @Test
+    public void testRemovingAbstractFromAClass_PreviousApi() {
         JDiffClassDescription clz = new JDiffClassDescription(
                 "android.signature.cts.tests.data", "NormalClass");
         clz.setType(JDiffClassDescription.JDiffType.CLASS);
         clz.setModifier(Modifier.PUBLIC | Modifier.ABSTRACT);
+        clz.setPreviousApiFlag(true);
         checkSignatureCompliance(clz);
     }
 
@@ -408,10 +550,98 @@
      */
     @Test
     public void testAddingAbstractToAClass() {
-        ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS);
-        JDiffClassDescription clz = createClass("AbstractClass");
-        checkSignatureCompliance(clz, observer);
-        observer.validate();
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) {
+            JDiffClassDescription clz = createClass("AbstractClass");
+            checkSignatureCompliance(clz, observer);
+        }
+    }
+
+    /**
+     * The current API lists the class as being final but the runtime class does not so they are
+     * incompatible.
+     */
+    @Test
+    public void testAddingFinalToAClass() {
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) {
+            JDiffClassDescription clz = createClass("FinalClass");
+            checkSignatureCompliance(clz, observer);
+        }
+    }
+
+    /**
+     * A previously released API lists the class as being final but the runtime class does not.
+     *
+     * <p>While adding a final modifier to a class is not strictly backwards compatible it is when
+     * the class has no accessible constructors and so cannot be instantiated or extended, as is the
+     * case in this test.</p>
+     */
+    @Test
+    public void testAddingFinalToAClassNoCtor_PreviousApi() {
+        JDiffClassDescription clz = createClass("FinalClass");
+        clz.setPreviousApiFlag(true);
+        checkSignatureCompliance(clz);
+    }
+
+    /**
+     * A previously released API lists the class as being final but the runtime class does not.
+     *
+     * <p>Adding a final modifier to a class is not backwards compatible when the class has some
+     * accessible constructors and so could be instantiated and/or extended, as is the case of this
+     * class.</p>
+     */
+    @Test
+    public void testAddingFinalToAClassWithCtor_PreviousApi() {
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) {
+            String simpleName = "FinalClassWithCtor";
+            JDiffClassDescription clz = createClass(simpleName);
+            clz.setPreviousApiFlag(true);
+            clz.addConstructor(ctor(simpleName, Modifier.PUBLIC));
+            checkSignatureCompliance(clz, observer);
+        }
+    }
+
+    /**
+     * The current API lists the class as being static but the runtime class does not so they are
+     * incompatible.
+     */
+    @Test
+    public void testAddingStaticToInnerClass() {
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) {
+            JDiffClassDescription clz = createClass("AbstractClass.StaticNestedClass");
+            checkSignatureCompliance(clz, observer);
+        }
+    }
+
+    /**
+     * A previously released API lists the class as being static but the runtime class does not.
+     *
+     * <p>While adding a static modifier to a class is not strictly backwards compatible it is when
+     * the class has no accessible constructors and so cannot be instantiated or extended, as is the
+     * case in this test.</p>
+     */
+    @Test
+    public void testAddingStaticToInnerClassNoCtor_PreviousApi() {
+        JDiffClassDescription clz = createClass("AbstractClass.StaticNestedClass");
+        clz.setPreviousApiFlag(true);
+        checkSignatureCompliance(clz);
+    }
+
+    /**
+     * A previously released API lists the class as being static but the runtime class does not.
+     *
+     * <p>Adding a static modifier to a class is not backwards compatible when the class has some
+     * accessible constructors and so could be instantiated and/or extended, as is the case of this
+     * class.</p>
+     */
+    @Test
+    public void testAddingStaticToInnerClassWithCtor_PreviousApi() {
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) {
+            String simpleName = "AbstractClass.StaticNestedClassWithCtor";
+            JDiffClassDescription clz = createClass(simpleName);
+            clz.setPreviousApiFlag(true);
+            clz.addConstructor(ctor(simpleName, Modifier.PUBLIC));
+            checkSignatureCompliance(clz, observer);
+        }
     }
 
     /**
@@ -430,17 +660,36 @@
     }
 
     /**
-     * Compatible (provide implementation for previous abstract method):
+     * Incompatible (provide implementation for abstract method):
      *
      * public abstract void Normal#notSyncMethod()
      * -> public void Normal#notSyncMethod()
      */
     @Test
     public void testRemovingAbstractFromMethod() {
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD)) {
+            JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
+            JDiffClassDescription.JDiffMethod method = method("notSyncMethod",
+                    Modifier.PUBLIC | Modifier.ABSTRACT, "void");
+            clz.addMethod(method);
+            checkSignatureCompliance(clz, observer);
+        }
+    }
+
+    /**
+     * A previously released API lists the method as being abstract but the runtime class does not.
+     *
+     * <p>While adding an abstract modifier to a method is not strictly backwards compatible it is 
+     * when the class has no accessible constructors and so cannot be instantiated or extended, as
+     * is the case in this test.</p>
+     */
+    @Test
+    public void testRemovingAbstractFromMethodOnClassNoCtor_PreviousApi() {
         JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
         JDiffClassDescription.JDiffMethod method = method("notSyncMethod",
                 Modifier.PUBLIC | Modifier.ABSTRACT, "void");
         clz.addMethod(method);
+        clz.setPreviousApiFlag(true);
         checkSignatureCompliance(clz);
     }
 
@@ -456,8 +705,9 @@
         JDiffClassDescription.JDiffMethod method = method("finalMethod",
                 Modifier.PUBLIC | Modifier.ABSTRACT, "void");
         clz.addMethod(method);
-        ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD);
-        checkSignatureCompliance(clz, observer);
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD)) {
+            checkSignatureCompliance(clz, observer);
+        }
     }
 
     /**
@@ -472,8 +722,9 @@
         JDiffClassDescription.JDiffMethod method = method("abstractMethod",
                 Modifier.PUBLIC, "void");
         clz.addMethod(method);
-        ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD);
-        checkSignatureCompliance(clz, observer);
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD)) {
+            checkSignatureCompliance(clz, observer);
+        }
     }
 
     @Test
@@ -523,12 +774,13 @@
      */
     @Test
     public void testAddingFinalToAMethodInANonFinalClass() {
-        ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD);
-        JDiffClassDescription clz = createClass("NormalClass");
-        JDiffClassDescription.JDiffMethod method = method("finalMethod", Modifier.PUBLIC, "void");
-        clz.addMethod(method);
-        checkSignatureCompliance(clz, observer);
-        observer.validate();
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD)) {
+            JDiffClassDescription clz = createClass("NormalClass");
+            JDiffClassDescription.JDiffMethod method = method("finalMethod", Modifier.PUBLIC,
+                    "void");
+            clz.addMethod(method);
+            checkSignatureCompliance(clz, observer);
+        }
     }
 
     @Test
diff --git a/tests/signature/tests/src/android/signature/cts/tests/ApiPresenceCheckerTest.java b/tests/signature/tests/src/android/signature/cts/tests/ApiPresenceCheckerTest.java
index 2783bba..d7d5602 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/ApiPresenceCheckerTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/ApiPresenceCheckerTest.java
@@ -112,6 +112,10 @@
         return clz;
     }
 
+    protected static JDiffClassDescription.JDiffConstructor ctor(String name, int modifiers) {
+        return new JDiffClassDescription.JDiffConstructor(name, modifiers);
+    }
+
     protected static JDiffClassDescription.JDiffMethod method(
             String name, int modifiers, String returnType) {
         return new JDiffClassDescription.JDiffMethod(name, modifiers, returnType);
@@ -127,7 +131,7 @@
         }
     }
 
-    protected static class ExpectFailure implements ResultObserver {
+    protected static class ExpectFailure implements ResultObserver, AutoCloseable {
 
         private FailureType expectedType;
 
@@ -152,6 +156,11 @@
             }
         }
 
+        @Override
+        public void close() {
+            validate();
+        }
+
         void validate() {
             Assert.assertTrue(failureSeen);
         }
diff --git a/tests/signature/tests/src/android/signature/cts/tests/ExpectedFailuresFilterAnnotationCheckerTest.java b/tests/signature/tests/src/android/signature/cts/tests/ExpectedFailuresFilterAnnotationCheckerTest.java
index 789d54f..2251c9a 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/ExpectedFailuresFilterAnnotationCheckerTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/ExpectedFailuresFilterAnnotationCheckerTest.java
@@ -69,23 +69,23 @@
 
     @Test
     public void testIgnoreExpectedFailures_TestStillFails() {
-        ExpectFailure observer = new ExpectFailure(FailureType.MISSING_ANNOTATION);
+        try (ExpectFailure observer = new ExpectFailure(FailureType.MISSING_ANNOTATION)) {
+            ResultObserver filter = new ExpectedFailuresFilter(observer, Arrays.asList(
+                    "extra_method:public void android.signature.cts.tests.data.SystemApiClass.apiMethod()",
+                    "extra_field:public boolean android.signature.cts.tests.data.SystemApiClass.apiField"
+            ));
 
-        ResultObserver filter = new ExpectedFailuresFilter(observer, Arrays.asList(
-            "extra_method:public void android.signature.cts.tests.data.SystemApiClass.apiMethod()",
-            "extra_field:public boolean android.signature.cts.tests.data.SystemApiClass.apiField"
-        ));
+            // Define the API that is expected to be provided by the SystemApiClass. Omitted members
+            // are actually provided by the SytstemApiClass definition and so will result in an
+            // extra_... error.
+            JDiffClassDescription clz = createClass("SystemApiClass");
+            addConstructor(clz);
+            // (omitted) addPublicVoidMethod(clz, "apiMethod");
+            // (omitted) addPublicBooleanField(clz, "apiField");
 
-        // Define the API that is expected to be provided by the SystemApiClass. Omitted members
-        // are actually provided by the SytstemApiClass definition and so will result in an
-        // extra_... error.
-        JDiffClassDescription clz = createClass("SystemApiClass");
-        addConstructor(clz);
-        // (omitted) addPublicVoidMethod(clz, "apiMethod");
-        // (omitted) addPublicBooleanField(clz, "apiField");
-
-        checkSignatureCompliance(clz, filter,
-            "android.signature.cts.tests.data.PublicApiClass",
-            "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
+            checkSignatureCompliance(clz, filter,
+                    "android.signature.cts.tests.data.PublicApiClass",
+                    "android.signature.cts.tests.data.ForciblyPublicizedPrivateClass");
+        }
     }
 }
diff --git a/tests/signature/tests/src/android/signature/cts/tests/data/AbstractClass.java b/tests/signature/tests/src/android/signature/cts/tests/data/AbstractClass.java
index 5fbbac1..25b90b7 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/data/AbstractClass.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/data/AbstractClass.java
@@ -22,4 +22,12 @@
 public abstract class AbstractClass {
     public abstract void abstractMethod();
     public final void finalMethod() {};
+
+    public static class StaticNestedClass {
+    }
+
+    public static class StaticNestedClassWithCtor {
+        public StaticNestedClassWithCtor() {
+        }
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/MockActivity.java b/tests/signature/tests/src/android/signature/cts/tests/data/AbstractClassWithCtor.java
similarity index 61%
copy from tests/tests/media/src/android/media/cts/MockActivity.java
copy to tests/signature/tests/src/android/signature/cts/tests/data/AbstractClassWithCtor.java
index 028cfae..eb9c88a 100644
--- a/tests/tests/media/src/android/media/cts/MockActivity.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/data/AbstractClassWithCtor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * Copyright (C) 2009 The Android Open 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,9 +14,13 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.signature.cts.tests.data;
 
-import android.app.Activity;
-
-public class MockActivity extends Activity {
+/**
+* This class is used as reference data for the JDiffClassDescriptionTest tests.
+*/
+public abstract class AbstractClassWithCtor {
+    public AbstractClassWithCtor() {}
+    public abstract void abstractMethod();
+    public final void finalMethod() {};
 }
diff --git a/tests/signature/tests/src/android/signature/cts/tests/data/ComplexEnum.java b/tests/signature/tests/src/android/signature/cts/tests/data/ComplexEnum.java
new file mode 100644
index 0000000..24e0f26
--- /dev/null
+++ b/tests/signature/tests/src/android/signature/cts/tests/data/ComplexEnum.java
@@ -0,0 +1,34 @@
+/*
+ * 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.tests.data;
+
+/**
+ * A complex enum that looks like it is concrete and final but is actually implemented at runtime
+ * as an abstract class.
+ */
+public enum ComplexEnum {
+
+    ONE() {
+        @Override
+        public void doSomething() {}
+    },
+    TWO() {
+        @Override
+        public void doSomething() {}
+    };
+
+    public abstract void doSomething();
+}
diff --git a/tests/signature/tests/src/android/signature/cts/tests/data/FinalClassWithCtor.java b/tests/signature/tests/src/android/signature/cts/tests/data/FinalClassWithCtor.java
new file mode 100644
index 0000000..d46d39c
--- /dev/null
+++ b/tests/signature/tests/src/android/signature/cts/tests/data/FinalClassWithCtor.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.signature.cts.tests.data;
+
+/**
+ * This class is used as reference data for the
+ * JDiffClassDescriptionTest tests.  These classes will actually be
+ * examined through reflection and Class.forName as part of testing
+ * JDiffClassDescription.  That is why there is no implementation for
+ * any of these methods.
+ */
+public final class FinalClassWithCtor {
+    public FinalClassWithCtor() { }
+    public final void finalMethod() { }
+    public void nonFinalMethod() { }
+}
diff --git a/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java b/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
index 4016bf6..b18cb54 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
@@ -41,6 +41,11 @@
     public native void nativeMethod();
     public void notNativeMethod() { }
     public final void finalMethod() { }
+    public void varargs(String...args) { }
+    // Generate a synthetic bridge method.
+    public NormalClass clone() throws CloneNotSupportedException {
+        return (NormalClass) super.clone();
+    }
 
     // Fields to test.
     public final String FINAL_FIELD = "";
diff --git a/tests/tests/animation/src/android/animation/cts/AnimatorTest.java b/tests/tests/animation/src/android/animation/cts/AnimatorTest.java
index 7812478..7ba460a 100644
--- a/tests/tests/animation/src/android/animation/cts/AnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/AnimatorTest.java
@@ -26,6 +26,7 @@
 import android.animation.ValueAnimator;
 import android.app.Instrumentation;
 import android.os.SystemClock;
+import android.platform.test.annotations.FlakyTest;
 import android.view.animation.AccelerateInterpolator;
 
 import androidx.test.InstrumentationRegistry;
@@ -101,6 +102,7 @@
         assertTrue(mAnimator.isRunning());
     }
 
+    @FlakyTest
     @Test
     public void testIsStarted() throws Throwable {
         assertFalse(mAnimator.isRunning());
@@ -146,6 +148,7 @@
         assertEquals(y, endY, 0.0f);
     }
 
+    @FlakyTest
     @Test
     public void testSetListener() throws Throwable {
         Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
diff --git a/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java b/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
index b9ffd34..eca0d96 100644
--- a/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
@@ -38,6 +38,7 @@
 import android.graphics.Path;
 import android.graphics.PointF;
 import android.os.SystemClock;
+import android.platform.test.annotations.FlakyTest;
 import android.util.Property;
 import android.view.View;
 import android.view.animation.AccelerateInterpolator;
@@ -141,6 +142,7 @@
         assertEquals(animator.getPropertyName(), objAnimator.getPropertyName());
     }
 
+    @FlakyTest
     @Test
     public void testOfInt() throws Throwable {
         Object object = mActivity.view.newBall;
@@ -165,6 +167,7 @@
         verify(mockListener, timeout(400)).onAnimationEnd(intAnimator, false);
     }
 
+    @FlakyTest
     @Test
     public void testOfObject() throws Throwable {
         Object object = mActivity.view.newBall;
@@ -296,6 +299,7 @@
         assertEquals(propertyName, actualPropertyName);
     }
 
+    @FlakyTest
     @Test
     public void testSetFloatValues() throws Throwable {
         Object object = mActivity.view.newBall;
diff --git a/tests/tests/animation/src/android/animation/cts/PropertyValuesHolderTest.java b/tests/tests/animation/src/android/animation/cts/PropertyValuesHolderTest.java
index c82be8e..4dbdc51 100644
--- a/tests/tests/animation/src/android/animation/cts/PropertyValuesHolderTest.java
+++ b/tests/tests/animation/src/android/animation/cts/PropertyValuesHolderTest.java
@@ -37,6 +37,7 @@
 import android.graphics.PointF;
 import android.graphics.drawable.ShapeDrawable;
 import android.os.SystemClock;
+import android.platform.test.annotations.FlakyTest;
 import android.util.FloatProperty;
 import android.util.Property;
 import android.view.View;
@@ -116,6 +117,7 @@
         assertEquals(pVHolder.getPropertyName(), cloneHolder.getPropertyName());
     }
 
+    @FlakyTest
     @Test
     public void testSetValues() throws Throwable {
         float[] dummyValues = {100, 150};
@@ -157,6 +159,7 @@
         mActivityRule.runOnUiThread(() -> mActivity.startSingleAnimation(animator));
     }
 
+    @FlakyTest
     @Test
     public void testResetValues() throws Throwable {
         final float initialY = mActivity.view.newBall.getY();
@@ -227,6 +230,7 @@
         assertEquals("Animation should run as expected", 100f, mActivity.view.newBall.getY(), 0.0f);
     }
 
+    @FlakyTest
     @Test
     public void testOfFloat() throws Throwable {
         float[] values = {mStartY, mEndY};
@@ -242,6 +246,7 @@
         assertResults(yArray, mStartY, mEndY);
     }
 
+    @FlakyTest
     @Test
     public void testOfFloat_Property() throws Throwable {
         float[] values = {mStartY, mEndY};
@@ -259,6 +264,7 @@
         assertResults(yArray, mStartY, mEndY);
     }
 
+    @FlakyTest
     @Test
     public void testOfInt() throws Throwable {
         int start = 0;
@@ -680,6 +686,7 @@
         assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
     }
 
+    @FlakyTest
     @Test
     public void testSetProperty() throws Throwable {
         float[] values = {mStartY, mEndY};
diff --git a/tests/tests/appop/Android.bp b/tests/tests/appop/Android.bp
index 70b1a57..11fdcd6 100644
--- a/tests/tests/appop/Android.bp
+++ b/tests/tests/appop/Android.bp
@@ -82,7 +82,6 @@
         "libbase",
         "libbinder",
         "libbpf_bcc",
-        "libbpf_android",
         "libc++",
         "libcgrouprc",
         "libcrypto",
diff --git a/tests/tests/batterysaving/AndroidManifest.xml b/tests/tests/batterysaving/AndroidManifest.xml
index 55e9050..c28fd40 100755
--- a/tests/tests/batterysaving/AndroidManifest.xml
+++ b/tests/tests/batterysaving/AndroidManifest.xml
@@ -19,7 +19,7 @@
     <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
-    <!-- Needed to whitelist package to be able to avoid request throttling. -->
+    <!-- Needed to allowlist package to be able to avoid request throttling. -->
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
 
diff --git a/tests/tests/binder_ndk/AndroidTest.xml b/tests/tests/binder_ndk/AndroidTest.xml
index 48bf70d..6578635 100644
--- a/tests/tests/binder_ndk/AndroidTest.xml
+++ b/tests/tests/binder_ndk/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp b/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
index 5d3611a..7dc1288 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
@@ -161,6 +161,9 @@
 cc_test_library {
     name: "libbinder_ndk_test",
     defaults: ["libbinder_ndk_test_defaults"],
+    tidy_timeout_srcs: [
+        "test_native_aidl_client.cpp",
+    ],
     srcs: [
         "test_ibinder.cpp",
         "test_ibinder_jni.cpp",
diff --git a/tests/tests/bluetooth/Android.bp b/tests/tests/bluetooth/Android.bp
index ee27a18..eb6e0e0 100644
--- a/tests/tests/bluetooth/Android.bp
+++ b/tests/tests/bluetooth/Android.bp
@@ -23,6 +23,7 @@
         "ctstestrunner-axt",
         "bluetooth-test-util-lib",
         "compatibility-device-util-axt",
+        "PlatformProperties",
     ],
     libs: [
         "android.test.runner",
diff --git a/tests/tests/bluetooth/AndroidManifest.xml b/tests/tests/bluetooth/AndroidManifest.xml
index 7b702d7..e624d2b 100644
--- a/tests/tests/bluetooth/AndroidManifest.xml
+++ b/tests/tests/bluetooth/AndroidManifest.xml
@@ -20,7 +20,7 @@
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
-    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
+    <!-- <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/> -->
     <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
deleted file mode 100644
index e465005..0000000
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothServerSocket;
-import android.bluetooth.BluetoothStatusCodes;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.os.SystemProperties;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import java.io.IOException;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Very basic test, just of the static methods of {@link
- * BluetoothAdapter}.
- */
-public class BasicAdapterTest extends AndroidTestCase {
-    private static final String TAG = "BasicAdapterTest";
-    private static final int SET_NAME_TIMEOUT = 5000; // ms timeout for setting adapter name
-
-    private boolean mHasBluetooth;
-    private ReentrantLock mAdapterNameChangedlock;
-    private Condition mConditionAdapterNameChanged;
-    private boolean mIsAdapterNameChanged;
-
-    public void setUp() throws Exception {
-        super.setUp();
-
-        mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_BLUETOOTH);
-        mAdapterNameChangedlock = new ReentrantLock();
-        mConditionAdapterNameChanged = mAdapterNameChangedlock.newCondition();
-        mIsAdapterNameChanged = false;
-    }
-
-    public void test_getDefaultAdapter() {
-        /*
-         * Note: If the target doesn't support Bluetooth at all, then
-         * this method should return null.
-         */
-        if (mHasBluetooth) {
-            assertNotNull(BluetoothAdapter.getDefaultAdapter());
-        } else {
-            assertNull(BluetoothAdapter.getDefaultAdapter());
-        }
-    }
-
-    public void test_checkBluetoothAddress() {
-        // Can't be null.
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(null));
-
-        // Must be 17 characters long.
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(""));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("0"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:0"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:0"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:0"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:00:"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:00:0"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:00:00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:00:00:"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(
-            "00:00:00:00:00:0"));
-
-        // Must have colons between octets.
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(
-            "00x00:00:00:00:00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(
-            "00:00.00:00:00:00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(
-            "00:00:00-00:00:00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(
-            "00:00:00:00900:00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(
-            "00:00:00:00:00?00"));
-
-        // Hex letters must be uppercase.
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(
-            "a0:00:00:00:00:00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(
-            "0b:00:00:00:00:00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(
-            "00:c0:00:00:00:00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(
-            "00:0d:00:00:00:00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(
-            "00:00:e0:00:00:00"));
-        assertFalse(BluetoothAdapter.checkBluetoothAddress(
-            "00:00:0f:00:00:00"));
-
-        assertTrue(BluetoothAdapter.checkBluetoothAddress(
-            "00:00:00:00:00:00"));
-        assertTrue(BluetoothAdapter.checkBluetoothAddress(
-            "12:34:56:78:9A:BC"));
-        assertTrue(BluetoothAdapter.checkBluetoothAddress(
-            "DE:F0:FE:DC:B8:76"));
-    }
-
-    /** Checks enable(), disable(), getState(), isEnabled() */
-    public void test_enableDisable() {
-        if (!mHasBluetooth) {
-            // Skip the test if bluetooth is not present.
-            return;
-        }
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
-        for (int i=0; i<5; i++) {
-            assertTrue(BTAdapterUtils.disableAdapter(adapter, mContext));
-            assertTrue(BTAdapterUtils.enableAdapter(adapter, mContext));
-        }
-    }
-
-    public void test_getAddress() {
-        if (!mHasBluetooth) {
-            // Skip the test if bluetooth is not present.
-            return;
-        }
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertTrue(BTAdapterUtils.enableAdapter(adapter, mContext));
-
-        assertTrue(BluetoothAdapter.checkBluetoothAddress(adapter.getAddress()));
-    }
-
-    public void test_setName_getName() {
-        if (!mHasBluetooth) {
-            // Skip the test if bluetooth is not present.
-            return;
-        }
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertTrue(BTAdapterUtils.enableAdapter(adapter, mContext));
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
-        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
-        mContext.registerReceiver(mAdapterNameChangeReceiver, filter);
-
-        String name = adapter.getName();
-        assertNotNull(name);
-
-        // Check renaming the adapter
-        String genericName = "Generic Device 1";
-        mIsAdapterNameChanged = false;
-        assertTrue(adapter.setName(genericName));
-        assertTrue(waitForAdapterNameChange());
-        mIsAdapterNameChanged = false;
-        assertEquals(genericName, adapter.getName());
-
-        // Check setting adapter back to original name
-        assertTrue(adapter.setName(name));
-        assertTrue(waitForAdapterNameChange());
-        mIsAdapterNameChanged = false;
-        assertEquals(name, adapter.getName());
-    }
-
-    public void test_getBondedDevices() {
-        if (!mHasBluetooth) {
-            // Skip the test if bluetooth is not present.
-            return;
-        }
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertTrue(BTAdapterUtils.enableAdapter(adapter, mContext));
-
-        Set<BluetoothDevice> devices = adapter.getBondedDevices();
-        assertNotNull(devices);
-        for (BluetoothDevice device : devices) {
-            assertTrue(BluetoothAdapter.checkBluetoothAddress(device.getAddress()));
-        }
-    }
-
-    public void test_getRemoteDevice() {
-        if (!mHasBluetooth) {
-            // Skip the test if bluetooth is not present.
-            return;
-        }
-        // getRemoteDevice() should work even with Bluetooth disabled
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertTrue(BTAdapterUtils.disableAdapter(adapter, mContext));
-
-        // test bad addresses
-        try {
-            adapter.getRemoteDevice((String)null);
-            fail("IllegalArgumentException not thrown");
-        } catch (IllegalArgumentException e) {}
-        try {
-            adapter.getRemoteDevice("00:00:00:00:00:00:00:00");
-            fail("IllegalArgumentException not thrown");
-        } catch (IllegalArgumentException e) {}
-        try {
-            adapter.getRemoteDevice((byte[])null);
-            fail("IllegalArgumentException not thrown");
-        } catch (IllegalArgumentException e) {}
-        try {
-            adapter.getRemoteDevice(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00});
-            fail("IllegalArgumentException not thrown");
-        } catch (IllegalArgumentException e) {}
-
-        // test success
-        BluetoothDevice device = adapter.getRemoteDevice("00:11:22:AA:BB:CC");
-        assertNotNull(device);
-        assertEquals("00:11:22:AA:BB:CC", device.getAddress());
-        device = adapter.getRemoteDevice(
-                new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06});
-        assertNotNull(device);
-        assertEquals("01:02:03:04:05:06", device.getAddress());
-    }
-
-    public void test_getRemoteLeDevice() {
-        if (!mHasBluetooth) {
-            // Skip the test if bluetooth is not present.
-            return;
-        }
-        // getRemoteLeDevice() should work even with Bluetooth disabled
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertTrue(BTAdapterUtils.disableAdapter(adapter, mContext));
-
-        // test bad addresses
-        try {
-            adapter.getRemoteLeDevice((String) null, BluetoothDevice.ADDRESS_TYPE_PUBLIC);
-            fail("IllegalArgumentException not thrown");
-        } catch (IllegalArgumentException e) { }
-        try {
-            adapter.getRemoteLeDevice("01:02:03:04:05:06:07:08",
-                    BluetoothDevice.ADDRESS_TYPE_PUBLIC);
-            fail("IllegalArgumentException not thrown");
-        } catch (IllegalArgumentException e) { }
-        try {
-            adapter.getRemoteLeDevice("01:02:03:04:05", BluetoothDevice.ADDRESS_TYPE_PUBLIC);
-            fail("IllegalArgumentException not thrown");
-        } catch (IllegalArgumentException e) { }
-        try {
-            adapter.getRemoteLeDevice("00:01:02:03:04:05", BluetoothDevice.ADDRESS_TYPE_RANDOM + 1);
-            fail("IllegalArgumentException not thrown");
-        } catch (IllegalArgumentException e) { }
-        try {
-            adapter.getRemoteLeDevice("00:01:02:03:04:05", BluetoothDevice.ADDRESS_TYPE_PUBLIC - 1);
-            fail("IllegalArgumentException not thrown");
-        } catch (IllegalArgumentException e) { }
-
-        // test success
-        BluetoothDevice device = adapter.getRemoteLeDevice("00:11:22:AA:BB:CC",
-                BluetoothDevice.ADDRESS_TYPE_PUBLIC);
-        assertNotNull(device);
-        assertEquals("00:11:22:AA:BB:CC", device.getAddress());
-        device = adapter.getRemoteLeDevice("01:02:03:04:05:06",
-                BluetoothDevice.ADDRESS_TYPE_RANDOM);
-        assertNotNull(device);
-        assertEquals("01:02:03:04:05:06", device.getAddress());
-    }
-
-    public void test_isLeAudioSupported() throws IOException {
-        if (!mHasBluetooth) {
-            // Skip the test if bluetooth is not present.
-            return;
-        }
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertNotSame(BluetoothStatusCodes.ERROR_UNKNOWN, adapter.isLeAudioSupported());
-    }
-
-    public void test_isLeAudioBroadcastSourceSupported() throws IOException {
-        if (!mHasBluetooth) {
-            // Skip the test if bluetooth is not present.
-            return;
-        }
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertNotSame(BluetoothStatusCodes.ERROR_UNKNOWN, adapter.isLeAudioBroadcastSourceSupported());
-    }
-
-    public void test_isLeAudioBroadcastAssistantSupported() throws IOException {
-        if (!mHasBluetooth) {
-            // Skip the test if bluetooth is not present.
-            return;
-        }
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertNotSame(BluetoothStatusCodes.ERROR_UNKNOWN, adapter.isLeAudioBroadcastAssistantSupported());
-    }
-
-    public void test_getMaxConnectedAudioDevices() {
-        if (!mHasBluetooth) {
-            // Skip the test if bluetooth is not present.
-            return;
-        }
-
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertTrue(BTAdapterUtils.enableAdapter(adapter, mContext));
-        int maxConnectedAudioDevicesConfig = 0;
-        try {
-            Resources bluetoothRes = mContext.getPackageManager()
-                    .getResourcesForApplication("com.android.bluetooth");
-            maxConnectedAudioDevicesConfig = bluetoothRes.getInteger(
-                    bluetoothRes.getIdentifier("config_bluetooth_max_connected_audio_devices",
-                    "integer", "com.android.bluetooth"));
-        } catch (PackageManager.NameNotFoundException e) {
-            e.printStackTrace();
-        }
-
-        maxConnectedAudioDevicesConfig =
-                SystemProperties.getInt("persist.bluetooth.maxconnectedaudiodevices",
-                        maxConnectedAudioDevicesConfig);
-        assertEquals(maxConnectedAudioDevicesConfig, adapter.getMaxConnectedAudioDevices());
-    }
-
-    public void test_listenUsingRfcommWithServiceRecord() throws IOException {
-        if (!mHasBluetooth) {
-            // Skip the test if bluetooth is not present.
-            return;
-        }
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertTrue(BTAdapterUtils.enableAdapter(adapter, mContext));
-
-        BluetoothServerSocket socket = adapter.listenUsingRfcommWithServiceRecord(
-                "test", UUID.randomUUID());
-        assertNotNull(socket);
-        socket.close();
-    }
-
-    private static void sleep(long t) {
-        try {
-            Thread.sleep(t);
-        } catch (InterruptedException e) {}
-    }
-
-    private boolean waitForAdapterNameChange() {
-        mAdapterNameChangedlock.lock();
-        try {
-            // Wait for the Adapter name to be changed
-            while (!mIsAdapterNameChanged) {
-                if (!mConditionAdapterNameChanged.await(
-                        SET_NAME_TIMEOUT, TimeUnit.MILLISECONDS)) {
-                    Log.e(TAG, "Timeout while waiting for adapter name change");
-                    break;
-                }
-            }
-        } catch (InterruptedException e) {
-            Log.e(TAG, "waitForAdapterNameChange: interrrupted");
-        } finally {
-            mAdapterNameChangedlock.unlock();
-        }
-        return mIsAdapterNameChanged;
-    }
-
-    private final BroadcastReceiver mAdapterNameChangeReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED)) {
-                mAdapterNameChangedlock.lock();
-                mIsAdapterNameChanged = true;
-                try {
-                    mConditionAdapterNameChanged.signal();
-                } catch (IllegalMonitorStateException ex) {
-                } finally {
-                    mAdapterNameChangedlock.unlock();
-                }
-            }
-        }
-    };
-}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicBluetoothGattTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BasicBluetoothGattTest.java
index 1e67d2a..f9531fb 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicBluetoothGattTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BasicBluetoothGattTest.java
@@ -24,6 +24,8 @@
 import android.bluetooth.BluetoothManager;
 import android.test.AndroidTestCase;
 
+import androidx.test.InstrumentationRegistry;
+
 import java.util.List;
 
 /**
@@ -41,6 +43,8 @@
         if (!TestUtils.isBleSupported(getContext())) {
             return;
         }
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+            .adoptShellPermissionIdentity(android.Manifest.permission.BLUETOOTH_CONNECT);
 
         mBluetoothAdapter = mContext.getSystemService(BluetoothManager.class).getAdapter();
         if (!mBluetoothAdapter.isEnabled()) {
@@ -59,6 +63,8 @@
         }
         mBluetoothGatt.disconnect();
         assertTrue(BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext));
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+            .dropShellPermissionIdentity();
     }
 
     public void testGetServices() throws Exception {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
new file mode 100644
index 0000000..b013b63
--- /dev/null
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
@@ -0,0 +1,228 @@
+/*
+ * 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 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;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class BluetoothA2dpTest extends AndroidTestCase {
+    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 BluetoothA2dp mBluetoothA2dp;
+    private boolean mIsA2dpSupported;
+    private boolean mIsProfileReady;
+    private Condition mConditionProfileIsConnected;
+    private ReentrantLock mProfileConnectedlock;
+
+    @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);
+
+        BluetoothManager manager = getContext().getSystemService(BluetoothManager.class);
+        mAdapter = manager.getAdapter();
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        mProfileConnectedlock = new ReentrantLock();
+        mConditionProfileIsConnected = mProfileConnectedlock.newCondition();
+        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);
+    }
+
+    @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();
+        }
+    }
+
+    public void test_getConnectedDevices() {
+        if (!(mHasBluetooth && mIsA2dpSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothA2dp);
+
+        assertEquals(mBluetoothA2dp.getConnectedDevices(),
+                new ArrayList<BluetoothDevice>());
+    }
+
+    public void test_getDevicesMatchingConnectionStates() {
+        if (!(mHasBluetooth && mIsA2dpSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothA2dp);
+
+        assertEquals(mBluetoothA2dp.getDevicesMatchingConnectionStates(
+                new int[]{BluetoothProfile.STATE_CONNECTED}),
+                new ArrayList<BluetoothDevice>());
+    }
+
+    public void test_getConnectionState() {
+        if (!(mHasBluetooth && mIsA2dpSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothA2dp);
+
+        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+
+        assertEquals(mBluetoothA2dp.getConnectionState(testDevice),
+                BluetoothProfile.STATE_DISCONNECTED);
+    }
+
+    public void test_isA2dpPlaying() {
+        if (!(mHasBluetooth && mIsA2dpSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothA2dp);
+
+        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+
+        assertFalse(mBluetoothA2dp.isA2dpPlaying(testDevice));
+    }
+
+    public void test_getCodecStatus() {
+        if (!(mHasBluetooth && mIsA2dpSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothA2dp);
+
+        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+
+        assertNull(mBluetoothA2dp.getCodecStatus(testDevice));
+        assertThrows(IllegalArgumentException.class, () -> {
+            mBluetoothA2dp.getCodecStatus(null);
+        });
+    }
+
+    public void test_setCodecConfigPreference() {
+        if (!(mHasBluetooth && mIsA2dpSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothA2dp);
+
+        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+
+        BluetoothCodecConfig codecConfig = new BluetoothCodecConfig.Builder()
+                .setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC)
+                .setCodecPriority(0)
+                .build();
+        mBluetoothA2dp.setCodecConfigPreference(testDevice, codecConfig);
+        assertNull(mBluetoothA2dp.getCodecStatus(testDevice));
+        assertThrows(IllegalArgumentException.class, () -> {
+            mBluetoothA2dp.setCodecConfigPreference(null, null);
+        });
+    }
+
+    private static <T extends Exception> void assertThrows(Class<T> clazz, Runnable r) {
+        try {
+            r.run();
+        } catch (Exception e) {
+            if (!clazz.isAssignableFrom(e.getClass())) {
+                throw e;
+            }
+        }
+    }
+
+    private boolean waitForProfileConnect() {
+        mProfileConnectedlock.lock();
+        try {
+            // Wait for the Adapter to be disabled
+            while (!mIsProfileReady) {
+                if (!mConditionProfileIsConnected.await(
+                        PROXY_CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                    // Timeout
+                    Log.e(TAG, "Timeout while waiting for Profile Connect");
+                    break;
+                } // else spurious wakeups
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "waitForProfileConnect: interrrupted");
+        } finally {
+            mProfileConnectedlock.unlock();
+        }
+        return mIsProfileReady;
+    }
+
+    private final class BluetoothA2dpServiceListener implements
+            BluetoothProfile.ServiceListener {
+
+        @Override
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            mProfileConnectedlock.lock();
+            mBluetoothA2dp = (BluetoothA2dp) proxy;
+            mIsProfileReady = true;
+            try {
+                mConditionProfileIsConnected.signal();
+            } finally {
+                mProfileConnectedlock.unlock();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(int profile) {
+        }
+    }
+}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java
new file mode 100644
index 0000000..460af3e
--- /dev/null
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java
@@ -0,0 +1,659 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 org.junit.Assert.assertThrows;
+
+import android.annotation.NonNull;
+import android.app.UiAutomation;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothStatusCodes;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.SystemProperties;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Very basic test, just of the static methods of {@link
+ * BluetoothAdapter}.
+ */
+public class BluetoothAdapterTest extends AndroidTestCase {
+    private static final String TAG = "BasicAdapterTest";
+    private static final int SET_NAME_TIMEOUT = 5000; // ms timeout for setting adapter name
+
+    private boolean mHasBluetooth;
+    private ReentrantLock mAdapterNameChangedlock;
+    private Condition mConditionAdapterNameChanged;
+    private boolean mIsAdapterNameChanged;
+
+    private BluetoothAdapter mAdapter;
+    private UiAutomation mUiAutomation;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_BLUETOOTH);
+        if (mHasBluetooth) {
+            mAdapter = getContext().getSystemService(BluetoothManager.class).getAdapter();
+            assertNotNull(mAdapter);
+            mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+            mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
+        }
+        mAdapterNameChangedlock = new ReentrantLock();
+        mConditionAdapterNameChanged = mAdapterNameChangedlock.newCondition();
+        mIsAdapterNameChanged = false;
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (mHasBluetooth) {
+            mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
+            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            mUiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+    public void test_getDefaultAdapter() {
+        /*
+         * Note: If the target doesn't support Bluetooth at all, then
+         * this method should return null.
+         */
+        if (mHasBluetooth) {
+            assertNotNull(BluetoothAdapter.getDefaultAdapter());
+        } else {
+            assertNull(BluetoothAdapter.getDefaultAdapter());
+        }
+    }
+
+    public void test_checkBluetoothAddress() {
+        // Can't be null.
+        assertFalse(BluetoothAdapter.checkBluetoothAddress(null));
+
+        // Must be 17 characters long.
+        assertFalse(BluetoothAdapter.checkBluetoothAddress(""));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("0"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:0"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:0"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:0"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:00:"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:00:0"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:00:00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:00:00:"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:00:00:0"));
+
+        // Must have colons between octets.
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00x00:00:00:00:00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00.00:00:00:00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00-00:00:00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:00900:00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:00:00:00?00"));
+
+        // Hex letters must be uppercase.
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("a0:00:00:00:00:00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("0b:00:00:00:00:00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:c0:00:00:00:00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:0d:00:00:00:00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:e0:00:00:00"));
+        assertFalse(BluetoothAdapter.checkBluetoothAddress("00:00:0f:00:00:00"));
+
+        assertTrue(BluetoothAdapter.checkBluetoothAddress("00:00:00:00:00:00"));
+        assertTrue(BluetoothAdapter.checkBluetoothAddress("12:34:56:78:9A:BC"));
+        assertTrue(BluetoothAdapter.checkBluetoothAddress("DE:F0:FE:DC:B8:76"));
+    }
+
+    /** Checks enable(), disable(), getState(), isEnabled() */
+    public void test_enableDisable() {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth is not present.
+            return;
+        }
+
+        for (int i = 0; i < 5; i++) {
+            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        }
+    }
+
+    public void test_getAddress() {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth is not present.
+            return;
+        }
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        assertTrue(BluetoothAdapter.checkBluetoothAddress(mAdapter.getAddress()));
+
+        mUiAutomation.dropShellPermissionIdentity();
+        assertThrows(SecurityException.class, () -> mAdapter.getAddress());
+
+    }
+
+    public void test_setName_getName() {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth is not present.
+            return;
+        }
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
+        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+        mContext.registerReceiver(mAdapterNameChangeReceiver, filter);
+
+        String name = mAdapter.getName();
+        assertNotNull(name);
+
+        // Check renaming the adapter
+        String genericName = "Generic Device 1";
+        mIsAdapterNameChanged = false;
+        assertTrue(mAdapter.setName(genericName));
+        assertTrue(waitForAdapterNameChange());
+        mIsAdapterNameChanged = false;
+        assertEquals(genericName, mAdapter.getName());
+
+        // Check setting adapter back to original name
+        assertTrue(mAdapter.setName(name));
+        assertTrue(waitForAdapterNameChange());
+        mIsAdapterNameChanged = false;
+        assertEquals(name, mAdapter.getName());
+
+        mUiAutomation.dropShellPermissionIdentity();
+        assertThrows(SecurityException.class, () -> mAdapter.setName("The name"));
+        assertThrows(SecurityException.class, () -> mAdapter.getName());
+    }
+
+    public void test_getBondedDevices() {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth is not present.
+            return;
+        }
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+
+        // empty value is returned when Bluetooth is disabled
+        Set<BluetoothDevice> devices = mAdapter.getBondedDevices();
+        assertNotNull(devices);
+        assertTrue(devices.isEmpty());
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        devices = mAdapter.getBondedDevices();
+        assertNotNull(devices);
+        for (BluetoothDevice device : devices) {
+            assertTrue(BluetoothAdapter.checkBluetoothAddress(device.getAddress()));
+        }
+
+        mUiAutomation.dropShellPermissionIdentity();
+        assertThrows(SecurityException.class, () -> mAdapter.getBondedDevices());
+
+    }
+
+    public void test_getRemoteDevice() {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth is not present.
+            return;
+        }
+        // getRemoteDevice() should work even with Bluetooth disabled
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        mUiAutomation.dropShellPermissionIdentity();
+
+        // test bad addresses
+        assertThrows(IllegalArgumentException.class, () -> mAdapter.getRemoteDevice((String) null));
+        assertThrows(IllegalArgumentException.class, () ->
+                mAdapter.getRemoteDevice("00:00:00:00:00:00:00:00"));
+        assertThrows(IllegalArgumentException.class, () -> mAdapter.getRemoteDevice((byte[]) null));
+        assertThrows(IllegalArgumentException.class, () ->
+                mAdapter.getRemoteDevice(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00}));
+
+        // test success
+        BluetoothDevice device = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+        assertNotNull(device);
+        assertEquals("00:11:22:AA:BB:CC", device.getAddress());
+        device = mAdapter.getRemoteDevice(
+                new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06});
+        assertNotNull(device);
+        assertEquals("01:02:03:04:05:06", device.getAddress());
+    }
+
+    public void test_getRemoteLeDevice() {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth is not present.
+            return;
+        }
+        // getRemoteLeDevice() should work even with Bluetooth disabled
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        mUiAutomation.dropShellPermissionIdentity();
+
+        // test bad addresses
+        assertThrows(IllegalArgumentException.class,
+                () -> mAdapter.getRemoteLeDevice((String) null,
+                                                 BluetoothDevice.ADDRESS_TYPE_PUBLIC));
+        assertThrows(IllegalArgumentException.class,
+                () -> mAdapter.getRemoteLeDevice("01:02:03:04:05:06:07:08",
+                                                 BluetoothDevice.ADDRESS_TYPE_PUBLIC));
+        assertThrows(IllegalArgumentException.class,
+                () -> mAdapter.getRemoteLeDevice("01:02:03:04:05",
+                                                 BluetoothDevice.ADDRESS_TYPE_PUBLIC));
+        assertThrows(IllegalArgumentException.class,
+                () -> mAdapter.getRemoteLeDevice("00:01:02:03:04:05",
+                                                 BluetoothDevice.ADDRESS_TYPE_RANDOM + 1));
+        assertThrows(IllegalArgumentException.class,
+                () -> mAdapter.getRemoteLeDevice("00:01:02:03:04:05",
+                                                 BluetoothDevice.ADDRESS_TYPE_PUBLIC - 1));
+
+        // test success
+        BluetoothDevice device = mAdapter.getRemoteLeDevice("00:11:22:AA:BB:CC",
+                BluetoothDevice.ADDRESS_TYPE_PUBLIC);
+        assertNotNull(device);
+        assertEquals("00:11:22:AA:BB:CC", device.getAddress());
+        device = mAdapter.getRemoteLeDevice("01:02:03:04:05:06",
+                BluetoothDevice.ADDRESS_TYPE_RANDOM);
+        assertNotNull(device);
+        assertEquals("01:02:03:04:05:06", device.getAddress());
+    }
+
+    public void test_isLeAudioSupported() throws IOException {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth is not present.
+            return;
+        }
+        assertNotSame(BluetoothStatusCodes.ERROR_UNKNOWN, mAdapter.isLeAudioSupported());
+    }
+
+    public void test_isLeAudioBroadcastSourceSupported() throws IOException {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth is not present.
+            return;
+        }
+        assertNotSame(BluetoothStatusCodes.ERROR_UNKNOWN,
+                mAdapter.isLeAudioBroadcastSourceSupported());
+    }
+
+    public void test_isLeAudioBroadcastAssistantSupported() throws IOException {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth is not present.
+            return;
+        }
+        assertNotSame(BluetoothStatusCodes.ERROR_UNKNOWN,
+                mAdapter.isLeAudioBroadcastAssistantSupported());
+    }
+
+    public void test_getMaxConnectedAudioDevices() {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth is not present.
+            return;
+        }
+
+        int maxConnectedAudioDevicesConfig = 0;
+        try {
+            Resources bluetoothRes = mContext.getPackageManager()
+                    .getResourcesForApplication("com.android.bluetooth");
+            maxConnectedAudioDevicesConfig = bluetoothRes.getInteger(
+                    bluetoothRes.getIdentifier("config_bluetooth_max_connected_audio_devices",
+                    "integer", "com.android.bluetooth"));
+        } catch (PackageManager.NameNotFoundException e) {
+            e.printStackTrace();
+        }
+
+        maxConnectedAudioDevicesConfig =
+                SystemProperties.getInt("persist.bluetooth.maxconnectedaudiodevices",
+                        maxConnectedAudioDevicesConfig);
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        assertEquals(maxConnectedAudioDevicesConfig, mAdapter.getMaxConnectedAudioDevices());
+
+        mUiAutomation.dropShellPermissionIdentity();
+        assertThrows(SecurityException.class, () -> mAdapter.getMaxConnectedAudioDevices());
+    }
+
+    public void test_listenUsingRfcommWithServiceRecord() throws IOException {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth is not present.
+            return;
+        }
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        BluetoothServerSocket socket = mAdapter.listenUsingRfcommWithServiceRecord(
+                "test", UUID.randomUUID());
+        assertNotNull(socket);
+        socket.close();
+
+        mUiAutomation.dropShellPermissionIdentity();
+        assertThrows(SecurityException.class, () -> mAdapter.listenUsingRfcommWithServiceRecord(
+                    "test", UUID.randomUUID()));
+    }
+
+    public void test_discoverableTimeout() {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth is not present.
+            return;
+        }
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        assertEquals(-1, mAdapter.getDiscoverableTimeout());
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        mUiAutomation.dropShellPermissionIdentity();
+        assertEquals(120, mAdapter.getDiscoverableTimeout());
+    }
+
+    public void test_getConnectionState() {
+        if (!mHasBluetooth) return;
+
+        // Verify return value if Bluetooth is not enabled
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        assertEquals(BluetoothProfile.STATE_DISCONNECTED, mAdapter.getConnectionState());
+    }
+
+    public void test_getMostRecentlyConnectedDevices() {
+        if (!mHasBluetooth) return;
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        // Verify throws SecurityException without permission.BLUETOOTH_PRIVILEGED
+        assertThrows(SecurityException.class, () -> mAdapter.getMostRecentlyConnectedDevices());
+
+        // Verify return value if Bluetooth is not enabled
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        List<BluetoothDevice> devices = mAdapter.getMostRecentlyConnectedDevices();
+        assertTrue(devices.isEmpty());
+    }
+
+    public void test_getUuids() {
+        if (!mHasBluetooth) return;
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        // Verify return value without permission.BLUETOOTH_CONNECT
+        mUiAutomation.dropShellPermissionIdentity();
+        assertThrows(SecurityException.class, () -> mAdapter.getUuids());
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
+
+        assertNotNull(mAdapter.getUuids());
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+
+        // Verify return value if Bluetooth is not enabled
+        assertNull(mAdapter.getUuids());
+
+    }
+
+    public void test_nameForState() {
+        assertEquals("ON", BluetoothAdapter.nameForState(BluetoothAdapter.STATE_ON));
+        assertEquals("OFF", BluetoothAdapter.nameForState(BluetoothAdapter.STATE_OFF));
+        assertEquals("TURNING_ON",
+                BluetoothAdapter.nameForState(BluetoothAdapter.STATE_TURNING_ON));
+        assertEquals("TURNING_OFF",
+                BluetoothAdapter.nameForState(BluetoothAdapter.STATE_TURNING_OFF));
+
+        assertEquals("BLE_ON", BluetoothAdapter.nameForState(BluetoothAdapter.STATE_BLE_ON));
+
+        // Check value before state range
+        for (int state = 0; state < BluetoothAdapter.STATE_OFF; state++) {
+            assertEquals("?!?!? (" + state + ")", BluetoothAdapter.nameForState(state));
+        }
+        // Check value after state range (skip TURNING_OFF)
+        for (int state = BluetoothAdapter.STATE_BLE_ON + 2; state < 100; state++) {
+            assertEquals("?!?!? (" + state + ")", BluetoothAdapter.nameForState(state));
+        }
+    }
+
+    public void test_BluetoothConnectionCallback_disconnectReasonText() {
+        assertEquals("Reason unknown", BluetoothAdapter.BluetoothConnectionCallback
+                .disconnectReasonText(BluetoothStatusCodes.ERROR_UNKNOWN));
+        assertEquals("Local request", BluetoothAdapter.BluetoothConnectionCallback
+                .disconnectReasonText(BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL_REQUEST));
+        assertEquals("Remote request", BluetoothAdapter.BluetoothConnectionCallback
+                .disconnectReasonText(BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE_REQUEST));
+        assertEquals("Local error", BluetoothAdapter.BluetoothConnectionCallback
+                .disconnectReasonText(BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL));
+        assertEquals("Remote error", BluetoothAdapter.BluetoothConnectionCallback
+                .disconnectReasonText(BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE));
+        assertEquals("Timeout", BluetoothAdapter.BluetoothConnectionCallback
+                .disconnectReasonText(BluetoothStatusCodes.ERROR_DISCONNECT_REASON_TIMEOUT));
+        assertEquals("Security", BluetoothAdapter.BluetoothConnectionCallback
+                .disconnectReasonText(BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SECURITY));
+        assertEquals("System policy", BluetoothAdapter.BluetoothConnectionCallback
+                .disconnectReasonText(BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SYSTEM_POLICY));
+        assertEquals("Resource constrained", BluetoothAdapter.BluetoothConnectionCallback
+                .disconnectReasonText(
+                    BluetoothStatusCodes.ERROR_DISCONNECT_REASON_RESOURCE_LIMIT_REACHED));
+        assertEquals("Connection already exists", BluetoothAdapter.BluetoothConnectionCallback
+                .disconnectReasonText(
+                    BluetoothStatusCodes.ERROR_DISCONNECT_REASON_CONNECTION_ALREADY_EXISTS));
+        assertEquals("Bad parameters", BluetoothAdapter.BluetoothConnectionCallback
+                .disconnectReasonText(BluetoothStatusCodes.ERROR_DISCONNECT_REASON_BAD_PARAMETERS));
+        final int min_reason = BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL_REQUEST - 1;
+        for (int reason = 0; reason < min_reason; reason++) {
+            assertEquals("Unrecognized disconnect reason: " + reason,
+                    BluetoothAdapter.BluetoothConnectionCallback.disconnectReasonText(reason));
+        }
+        final int max_reason = BluetoothStatusCodes.ERROR_DISCONNECT_REASON_BAD_PARAMETERS + 1;
+        // Check value after state range (skip TURNING_OFF)
+        for (int reason = max_reason; reason < max_reason + 100; reason++) {
+            assertEquals("Unrecognized disconnect reason: " + reason,
+                    BluetoothAdapter.BluetoothConnectionCallback.disconnectReasonText(reason));
+        }
+    }
+
+    public void test_registerBluetoothConnectionCallback() {
+        if (!mHasBluetooth) return;
+
+        Executor executor = mContext.getMainExecutor();
+        BluetoothAdapter.BluetoothConnectionCallback callback =
+                new BluetoothAdapter.BluetoothConnectionCallback() {
+                    @Override
+                    public void onDeviceConnected(@NonNull BluetoothDevice device) {}
+                    @Override
+                    public void onDeviceDisconnected(BluetoothDevice device, int reason) {}
+
+                };
+
+        // Verify parameter
+        assertFalse(mAdapter.registerBluetoothConnectionCallback(null, callback));
+        assertFalse(mAdapter.registerBluetoothConnectionCallback(executor, null));
+        assertFalse(mAdapter.unregisterBluetoothConnectionCallback(null));
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        // Verify throws SecurityException without permission.BLUETOOTH_PRIVILEGED
+        assertThrows(SecurityException.class,
+                () -> mAdapter.registerBluetoothConnectionCallback(executor, callback));
+
+        mUiAutomation.dropShellPermissionIdentity();
+        // Verify throws SecurityException without permission.BLUETOOTH_CONNECT
+        assertThrows(SecurityException.class, () ->
+                mAdapter.registerBluetoothConnectionCallback(executor, callback));
+        assertThrows(SecurityException.class, () ->
+                mAdapter.unregisterBluetoothConnectionCallback(callback));
+    }
+
+    public void test_registerServiceLifecycleCallback() {
+        if (!mHasBluetooth) return;
+
+        BluetoothAdapter.ServiceLifecycleCallback callback =
+                new BluetoothAdapter.ServiceLifecycleCallback() {
+                    @Override
+                    public void onBluetoothServiceUp() {}
+                    @Override
+                    public void onBluetoothServiceDown() {}
+                };
+
+        // Verify parameter
+        assertThrows(NullPointerException.class,
+                () -> mAdapter.registerServiceLifecycleCallback(null));
+
+        assertThrows(NullPointerException.class,
+                () -> mAdapter.unregisterServiceLifecycleCallback(null));
+    }
+
+    public void test_requestControllerActivityEnergyInfo() {
+        if (!mHasBluetooth) return;
+
+        // Verify parameter
+        assertThrows(NullPointerException.class,
+                () -> mAdapter.requestControllerActivityEnergyInfo(null));
+    }
+
+    public void test_factoryReset() {
+        if (!mHasBluetooth) return;
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        // Verify throws SecurityException without permission.BLUETOOTH_PRIVILEGED
+        assertThrows(SecurityException.class, () -> mAdapter.factoryReset());
+        mUiAutomation.dropShellPermissionIdentity();
+        // Verify throws SecurityException without permission.BLUETOOTH_CONNECT
+        assertThrows(SecurityException.class, () -> mAdapter.factoryReset());
+
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        // Verify throws RuntimeException when trying to save sysprop for later (permission denied)
+        assertThrows(RuntimeException.class, () -> mAdapter.factoryReset());
+    }
+
+    public void test_BluetoothProfile_getConnectionStateName() {
+        if (!mHasBluetooth) return;
+
+        assertEquals("STATE_DISCONNECTED",
+                BluetoothProfile.getConnectionStateName(BluetoothProfile.STATE_DISCONNECTED));
+        assertEquals("STATE_CONNECTED",
+                BluetoothProfile.getConnectionStateName(BluetoothProfile.STATE_CONNECTED));
+        assertEquals("STATE_CONNECTING",
+                BluetoothProfile.getConnectionStateName(BluetoothProfile.STATE_CONNECTING));
+        assertEquals("STATE_CONNECTED",
+                BluetoothProfile.getConnectionStateName(BluetoothProfile.STATE_CONNECTED));
+        assertEquals("STATE_DISCONNECTING",
+                BluetoothProfile.getConnectionStateName(BluetoothProfile.STATE_DISCONNECTING));
+        assertEquals("STATE_UNKNOWN",
+                BluetoothProfile.getConnectionStateName(BluetoothProfile.STATE_DISCONNECTING + 1));
+    }
+
+    public void test_BluetoothProfile_getProfileName() {
+        if (!mHasBluetooth) return;
+        assertEquals("HEADSET",
+                BluetoothProfile.getProfileName(BluetoothProfile.HEADSET));
+        assertEquals("A2DP",
+                BluetoothProfile.getProfileName(BluetoothProfile.A2DP));
+        assertEquals("HID_HOST",
+                BluetoothProfile.getProfileName(BluetoothProfile.HID_HOST));
+        assertEquals("PAN",
+                BluetoothProfile.getProfileName(BluetoothProfile.PAN));
+        assertEquals("PBAP",
+                BluetoothProfile.getProfileName(BluetoothProfile.PBAP));
+        assertEquals("GATT",
+                BluetoothProfile.getProfileName(BluetoothProfile.GATT));
+        assertEquals("GATT_SERVER",
+                BluetoothProfile.getProfileName(BluetoothProfile.GATT_SERVER));
+        assertEquals("MAP",
+                BluetoothProfile.getProfileName(BluetoothProfile.MAP));
+        assertEquals("SAP",
+                BluetoothProfile.getProfileName(BluetoothProfile.SAP));
+        assertEquals("A2DP_SINK",
+                BluetoothProfile.getProfileName(BluetoothProfile.A2DP_SINK));
+        assertEquals("AVRCP_CONTROLLER",
+                BluetoothProfile.getProfileName(BluetoothProfile.AVRCP_CONTROLLER));
+        assertEquals("AVRCP",
+                BluetoothProfile.getProfileName(BluetoothProfile.AVRCP));
+        assertEquals("HEADSET_CLIENT",
+                BluetoothProfile.getProfileName(BluetoothProfile.HEADSET_CLIENT));
+        assertEquals("PBAP_CLIENT",
+                BluetoothProfile.getProfileName(BluetoothProfile.PBAP_CLIENT));
+        assertEquals("MAP_CLIENT",
+                BluetoothProfile.getProfileName(BluetoothProfile.MAP_CLIENT));
+        assertEquals("HID_DEVICE",
+                BluetoothProfile.getProfileName(BluetoothProfile.HID_DEVICE));
+        assertEquals("OPP",
+                BluetoothProfile.getProfileName(BluetoothProfile.OPP));
+        assertEquals("HEARING_AID",
+                BluetoothProfile.getProfileName(BluetoothProfile.HEARING_AID));
+        assertEquals("LE_AUDIO",
+                BluetoothProfile.getProfileName(BluetoothProfile.LE_AUDIO));
+        assertEquals("HAP_CLIENT",
+                BluetoothProfile.getProfileName(BluetoothProfile.HAP_CLIENT));
+        assertEquals("UNKNOWN_PROFILE",
+                BluetoothProfile.getProfileName(BluetoothProfile.HAP_CLIENT + 1));
+    }
+
+    private static void sleep(long t) {
+        try {
+            Thread.sleep(t);
+        } catch (InterruptedException e) { }
+    }
+
+    private boolean waitForAdapterNameChange() {
+        mAdapterNameChangedlock.lock();
+        try {
+            // Wait for the Adapter name to be changed
+            while (!mIsAdapterNameChanged) {
+                if (!mConditionAdapterNameChanged.await(
+                        SET_NAME_TIMEOUT, TimeUnit.MILLISECONDS)) {
+                    Log.e(TAG, "Timeout while waiting for adapter name change");
+                    break;
+                }
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "waitForAdapterNameChange: interrrupted");
+        } finally {
+            mAdapterNameChangedlock.unlock();
+        }
+        return mIsAdapterNameChanged;
+    }
+
+    private final BroadcastReceiver mAdapterNameChangeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED)) {
+                mAdapterNameChangedlock.lock();
+                mIsAdapterNameChanged = true;
+                try {
+                    mConditionAdapterNameChanged.signal();
+                } catch (IllegalMonitorStateException ex) {
+                } finally {
+                    mAdapterNameChangedlock.unlock();
+                }
+            }
+        }
+    };
+}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothClassTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothClassTest.java
index 3d407df..a22c2c8 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothClassTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothClassTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -17,6 +17,7 @@
 package android.bluetooth.cts;
 
 import android.bluetooth.BluetoothClass;
+import android.os.Parcel;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -32,11 +33,21 @@
     private BluetoothClass mBluetoothClassPhone;
     private BluetoothClass mBluetoothClassService;
 
+    private BluetoothClass createBtClass(int deviceClass) {
+        Parcel p = Parcel.obtain();
+        p.writeInt(deviceClass);
+        p.setDataPosition(0); // reset position of parcel before passing to constructor
+
+        BluetoothClass bluetoothClass = BluetoothClass.CREATOR.createFromParcel(p);
+        p.recycle();
+        return bluetoothClass;
+    }
+
     @Override
     protected void setUp() {
-        mBluetoothClassHeadphones = new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
-        mBluetoothClassPhone = new BluetoothClass(BluetoothClass.Device.Major.PHONE);
-        mBluetoothClassService = new BluetoothClass(BluetoothClass.Service.NETWORKING);
+        mBluetoothClassHeadphones = createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
+        mBluetoothClassPhone = createBtClass(BluetoothClass.Device.Major.PHONE);
+        mBluetoothClassService = createBtClass(BluetoothClass.Service.NETWORKING);
     }
 
     @SmallTest
@@ -47,20 +58,27 @@
 
     @SmallTest
     public void testGetMajorDeviceClass() {
-        assertEquals(mBluetoothClassHeadphones.getMajorDeviceClass(), BluetoothClass.Device.Major.AUDIO_VIDEO);
+        assertEquals(
+                mBluetoothClassHeadphones.getMajorDeviceClass(),
+                BluetoothClass.Device.Major.AUDIO_VIDEO);
         assertEquals(mBluetoothClassPhone.getMajorDeviceClass(), BluetoothClass.Device.Major.PHONE);
     }
 
     @SmallTest
     public void testGetDeviceClass() {
-        assertEquals(mBluetoothClassHeadphones.getDeviceClass(), BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
-        assertEquals(mBluetoothClassPhone.getDeviceClass(), BluetoothClass.Device.PHONE_UNCATEGORIZED);
+        assertEquals(
+                mBluetoothClassHeadphones.getDeviceClass(),
+                BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
+        assertEquals(
+                mBluetoothClassPhone.getDeviceClass(),
+                BluetoothClass.Device.PHONE_UNCATEGORIZED);
     }
 
     @SmallTest
     public void testGetClassOfDevice() {
-        assertEquals(mBluetoothClassHeadphones.getClassOfDevice(), BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
-        assertEquals(mBluetoothClassPhone.getClassOfDevice(), BluetoothClass.Device.Major.PHONE);
+        assertEquals(mBluetoothClassHeadphones.getDeviceClass(),
+                BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
+        assertEquals(mBluetoothClassPhone.getMajorDeviceClass(), BluetoothClass.Device.Major.PHONE);
     }
 
     @SmallTest
@@ -74,4 +92,13 @@
         assertTrue(mBluetoothClassService.doesClassMatch(BluetoothClass.PROFILE_PANU));
         assertFalse(mBluetoothClassService.doesClassMatch(BluetoothClass.PROFILE_OPP));
     }
+
+    @SmallTest
+    public void testInnerClasses() {
+        // Just instantiate static inner classes for exposing constants
+        // to make test coverage tool happy.
+        BluetoothClass.Device device = new BluetoothClass.Device();
+        BluetoothClass.Device.Major major = new BluetoothClass.Device.Major();
+        BluetoothClass.Service service = new BluetoothClass.Service();
+    }
 }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java
index 7f1a487..a615df3 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java
@@ -16,20 +16,29 @@
 
 package android.bluetooth.cts;
 
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
+
 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
 
+import static org.junit.Assert.assertThrows;
+
+import android.app.UiAutomation;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothStatusCodes;
+import android.content.AttributionSource;
 import android.content.pm.PackageManager;
 import android.test.AndroidTestCase;
 
+import androidx.test.InstrumentationRegistry;
+
 public class BluetoothDeviceTest extends AndroidTestCase {
 
     private boolean mHasBluetooth;
     private boolean mHasCompanionDevice;
     private BluetoothAdapter mAdapter;
+    private UiAutomation mUiAutomation;;
 
     @Override
     public void setUp() throws Exception {
@@ -43,6 +52,8 @@
         if (mHasBluetooth && mHasCompanionDevice) {
             BluetoothManager manager = getContext().getSystemService(BluetoothManager.class);
             mAdapter = manager.getAdapter();
+            mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+            mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
             assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
         }
     }
@@ -53,6 +64,7 @@
         if (mHasBluetooth && mHasCompanionDevice) {
             assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
             mAdapter = null;
+            mUiAutomation.dropShellPermissionIdentity();
         }
     }
 
@@ -66,20 +78,21 @@
         String packageName = mContext.getOpPackageName();
         String deviceAddress = "00:11:22:AA:BB:CC";
 
+        AttributionSource source = AttributionSource.myAttributionSource();
+        assertEquals("android.bluetooth.cts", source.getPackageName());
+
         BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
         // Verifies that when there is no alias, we return the device name
         assertNull(device.getAlias());
 
+        assertThrows(IllegalArgumentException.class, () -> device.setAlias(""));
+
         String testDeviceAlias = "Test Device Alias";
 
         // This should throw a SecurityException because there is no CDM association
-        try {
-            device.setAlias(testDeviceAlias);
-            fail("BluetoothDevice alias was able to be set without a CDM association or "
-                    + "BLUETOOTH_PRIVILEGED permission");
-        } catch (SecurityException ex) {
-            assertNull(device.getAlias());
-        }
+        assertThrows("BluetoothDevice.setAlias without"
+                + " a CDM association or BLUETOOTH_PRIVILEGED permission",
+                SecurityException.class, () -> device.setAlias(testDeviceAlias));
 
         runShellCommand(String.format(
                 "cmd companiondevice associate %d %s %s", userId, packageName, deviceAddress));
@@ -102,4 +115,111 @@
         runShellCommand(String.format(
                 "cmd companiondevice disassociate %d %s %s", userId, packageName, deviceAddress));
     }
+
+    public void test_getAnonymizedAddress() {
+        if (!mHasBluetooth || !mHasCompanionDevice) {
+            // Skip the test if bluetooth or companion device are not present.
+            return;
+        }
+        String deviceAddress = "00:11:22:AA:BB:CC";
+        BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+        assertEquals(device.getAnonymizedAddress(), "XX:XX:XX:AA:BB:CC");
+    }
+
+    public void test_getBatteryLevel() {
+        if (!mHasBluetooth || !mHasCompanionDevice) {
+            // Skip the test if bluetooth or companion device are not present.
+            return;
+        }
+        String deviceAddress = "00:11:22:AA:BB:CC";
+        BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+        assertEquals(BluetoothDevice.BATTERY_LEVEL_UNKNOWN, device.getBatteryLevel());
+
+        mUiAutomation.dropShellPermissionIdentity();
+        assertThrows(SecurityException.class, () -> device.getBatteryLevel());
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
+    }
+
+    public void test_getMessageAccessPermission() {
+        if (!mHasBluetooth || !mHasCompanionDevice) {
+            // Skip the test if bluetooth or companion device are not present.
+            return;
+        }
+        String deviceAddress = "00:11:22:AA:BB:CC";
+        BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+        assertEquals(BluetoothDevice.ACCESS_UNKNOWN, device.getMessageAccessPermission());
+
+        mUiAutomation.dropShellPermissionIdentity();
+        assertThrows(SecurityException.class, () -> device.getMessageAccessPermission());
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
+    }
+
+    public void test_getPhonebookAccessPermission() {
+        if (!mHasBluetooth || !mHasCompanionDevice) {
+            // Skip the test if bluetooth or companion device are not present.
+            return;
+        }
+        String deviceAddress = "00:11:22:AA:BB:CC";
+        BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+        assertEquals(BluetoothDevice.ACCESS_UNKNOWN, device.getPhonebookAccessPermission());
+
+        mUiAutomation.dropShellPermissionIdentity();
+        assertThrows(SecurityException.class, () -> device.getPhonebookAccessPermission());
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
+    }
+
+    public void test_isBondingInitiatedLocally() {
+        if (!mHasBluetooth || !mHasCompanionDevice) {
+            // Skip the test if bluetooth or companion device are not present.
+            return;
+        }
+        String deviceAddress = "00:11:22:AA:BB:CC";
+        BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+        assertFalse(device.isBondingInitiatedLocally());
+
+        mUiAutomation.dropShellPermissionIdentity();
+        assertThrows(SecurityException.class, () -> device.isBondingInitiatedLocally());
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
+    }
+
+    public void test_prepareToEnterProcess() {
+        if (!mHasBluetooth || !mHasCompanionDevice) {
+            // Skip the test if bluetooth or companion device are not present.
+            return;
+        }
+        String deviceAddress = "00:11:22:AA:BB:CC";
+        BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+        device.prepareToEnterProcess(null);
+    }
+
+    public void test_setPin() {
+        if (!mHasBluetooth || !mHasCompanionDevice) {
+            // Skip the test if bluetooth or companion device are not present.
+            return;
+        }
+        String deviceAddress = "00:11:22:AA:BB:CC";
+        BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+
+        assertFalse(device.setPin((String) null));
+        assertFalse(device.setPin("12345678901234567")); // check PIN too big
+
+        assertFalse(device.setPin("123456")); //device is not bonding
+
+        mUiAutomation.dropShellPermissionIdentity();
+        assertThrows(SecurityException.class, () -> device.setPin("123456"));
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
+    }
+
+    public void test_connect_disconnect() {
+        if (!mHasBluetooth || !mHasCompanionDevice) {
+            // Skip the test if bluetooth or companion device are not present.
+            return;
+        }
+        String deviceAddress = "00:11:22:AA:BB:CC";
+        BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+
+        // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission
+        assertThrows(SecurityException.class, () -> device.connect());
+        assertThrows(SecurityException.class, () -> device.disconnect());
+    }
 }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapClientTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapClientTest.java
index f4d6c3b..0b2dd82 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapClientTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapClientTest.java
@@ -19,6 +19,7 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHapClient;
+import android.bluetooth.BluetoothHapPresetInfo;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothProfile;
 import android.content.pm.PackageManager;
@@ -27,6 +28,8 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+
 import com.android.compatibility.common.util.ApiLevelUtil;
 
 import java.util.List;
@@ -57,6 +60,8 @@
                     PackageManager.FEATURE_BLUETOOTH);
 
             if (!mHasBluetooth) return;
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity(android.Manifest.permission.BLUETOOTH_CONNECT);
             BluetoothManager manager = getContext().getSystemService(BluetoothManager.class);
             mAdapter = manager.getAdapter();
             assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
@@ -90,6 +95,8 @@
             }
             assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
             mAdapter = null;
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .dropShellPermissionIdentity();
         }
     }
 
@@ -139,21 +146,6 @@
                 mBluetoothHapClient.getConnectionState(testDevice));
     }
 
-    public void testGetHapGroup() {
-        if (!(mHasBluetooth && mIsHapClientSupported)) return;
-
-        assertTrue(waitForProfileConnect());
-        assertNotNull(mBluetoothHapClient);
-
-        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
-
-        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-
-        // Verify returns BluetoothHapClient.HAP_GROUP_UNAVAILABLE if bluetooth is not enabled
-        assertEquals(BluetoothHapClient.HAP_GROUP_UNAVAILABLE,
-                mBluetoothHapClient.getHapGroup(testDevice));
-    }
-
     public void testGetActivePresetIndex() {
         if (!(mHasBluetooth && mIsHapClientSupported)) return;
 
@@ -164,11 +156,11 @@
 
         assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
 
-        // Verify returns false if bluetooth is not enabled
-        mBluetoothHapClient.getActivePresetIndex(testDevice);
+        // Verify returns null if bluetooth is not enabled
+        assertNull(mBluetoothHapClient.getActivePresetInfo(testDevice));
     }
 
-    public void testSelectActivePreset() {
+    public void testSelectPreset() {
         if (!(mHasBluetooth && mIsHapClientSupported)) return;
 
         assertTrue(waitForProfileConnect());
@@ -178,25 +170,21 @@
 
         assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
 
-        // Verify returns false if bluetooth is not enabled
         mBluetoothHapClient.selectPreset(testDevice, 1);
     }
 
-    public void testGroupSelectActivePreset() {
+    public void testSelectPresetForGroup() {
         if (!(mHasBluetooth && mIsHapClientSupported)) return;
 
         assertTrue(waitForProfileConnect());
         assertNotNull(mBluetoothHapClient);
 
-        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
-
         assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
 
-        // Verify returns false if bluetooth is not enabled
         mBluetoothHapClient.selectPresetForGroup(1, 1);
     }
 
-    public void testGetPresetInfo() {
+    public void testGetAllPresetInfo() {
         if (!(mHasBluetooth && mIsHapClientSupported)) return;
 
         assertTrue(waitForProfileConnect());
@@ -206,36 +194,9 @@
 
         assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
 
-        // Verify returns false if bluetooth is not enabled
-        mBluetoothHapClient.getPresetInfo(testDevice, 1);
-    }
-
-    public void testGetAllPresetsInfo() {
-        if (!(mHasBluetooth && mIsHapClientSupported)) return;
-
-        assertTrue(waitForProfileConnect());
-        assertNotNull(mBluetoothHapClient);
-
-        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
-
-        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-
-        // Verify returns false if bluetooth is not enabled
-        mBluetoothHapClient.getAllPresetInfo(testDevice);
-    }
-
-    public void testGetFeatures() {
-        if (!(mHasBluetooth && mIsHapClientSupported)) return;
-
-        assertTrue(waitForProfileConnect());
-        assertNotNull(mBluetoothHapClient);
-
-        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
-
-        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-
-        // Verify returns false if bluetooth is not enabled
-        assertFalse(mBluetoothHapClient.getFeatures(testDevice));
+        // Verify returns empty list if bluetooth is not enabled
+        List<BluetoothHapPresetInfo> presets = mBluetoothHapClient.getAllPresetInfo(testDevice);
+        assertTrue(presets.isEmpty());
     }
 
     public void testSetPresetName() {
@@ -248,11 +209,10 @@
 
         assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
 
-        // Verify returns false if bluetooth is not enabled
         mBluetoothHapClient.setPresetName(testDevice, 1 , "New Name");
     }
 
-    public void testGroupSetPresetName() {
+    public void testSetPresetNameForGroup() {
         if (!(mHasBluetooth && mIsHapClientSupported)) return;
 
         assertTrue(waitForProfileConnect());
@@ -260,7 +220,6 @@
 
         assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
 
-        // Verify returns false if bluetooth is not enabled
         mBluetoothHapClient.setPresetNameForGroup(1, 1 , "New Name");
     }
 
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecStatusTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecStatusTest.java
index 5f8ccb7..2ffb577 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecStatusTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecStatusTest.java
@@ -61,14 +61,14 @@
         assertTrue(LE_MONO_CODEC_STATUS.getCodecConfig().equals(LC3_MONO_CONFIG));
     }
 
-    public void testGetCodecsLocalCapabilities() {
+    public void testGetCodecLocalCapabilities() {
         assertTrue(
-                LE_STEREO_CODEC_STATUS.getCodecsLocalCapabilities().equals(CAPABILITIES_CONFIG));
+                LE_STEREO_CODEC_STATUS.getCodecLocalCapabilities().equals(CAPABILITIES_CONFIG));
     }
 
-    public void testGetCodecsSelectableCapabilities() {
+    public void testGetCodecSelectableCapabilities() {
         assertTrue(
-                LE_STEREO_CODEC_STATUS.getCodecsSelectableCapabilities().equals(SELECTABLE_CONFIG));
+                LE_STEREO_CODEC_STATUS.getCodecSelectableCapabilities().equals(SELECTABLE_CONFIG));
     }
 
     public void testIsCodecConfigSelectable() {
@@ -88,8 +88,8 @@
                 BluetoothLeAudioCodecStatus.CREATOR.createFromParcel(parcel);
         assertTrue(codecStatusFromParcel.getCodecConfig().equals(LC3_STEREO_CONFIG));
         assertTrue(
-                codecStatusFromParcel.getCodecsLocalCapabilities().equals(CAPABILITIES_CONFIG));
+                codecStatusFromParcel.getCodecLocalCapabilities().equals(CAPABILITIES_CONFIG));
         assertTrue(
-                codecStatusFromParcel.getCodecsSelectableCapabilities().equals(SELECTABLE_CONFIG));
+                codecStatusFromParcel.getCodecSelectableCapabilities().equals(SELECTABLE_CONFIG));
     }
 }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecTest.java
index 38599f5..c51142e 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecTest.java
@@ -85,16 +85,6 @@
         }
     }
 
-    public void testGetMaxCodecType() {
-        try {
-            // Checks the supported codec is greater than zero
-            // Keeps the flexibility to allow custom codec.
-            assertTrue(BluetoothLeAudioCodecConfig.getMaxCodecType() > 0);
-        } catch (Exception e) {
-            fail(e.getMessage());
-        }
-    }
-
     public void testGetCodecPriority() {
         for (int priorityIdx = 0; priorityIdx < mCodecPriorityArray.length; priorityIdx++) {
             int codecPriority = mCodecPriorityArray[priorityIdx];
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
index 214645f..6b349e7 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
@@ -16,9 +16,12 @@
 
 package android.bluetooth.cts;
 
+import static org.junit.Assert.assertThrows;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothLeAudio;
+import android.bluetooth.BluetoothLeAudioCodecConfig;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothProfile;
 import android.content.pm.PackageManager;
@@ -27,6 +30,8 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+
 import com.android.compatibility.common.util.ApiLevelUtil;
 
 import java.util.List;
@@ -58,6 +63,9 @@
                     PackageManager.FEATURE_BLUETOOTH);
 
             if (!mHasBluetooth) return;
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity(android.Manifest.permission.BLUETOOTH_CONNECT);
+
             BluetoothManager manager = getContext().getSystemService(BluetoothManager.class);
             mAdapter = manager.getAdapter();
             assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
@@ -90,6 +98,8 @@
                 mIsProfileReady = false;
             }
             assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .dropShellPermissionIdentity();
             mAdapter = null;
         }
     }
@@ -155,6 +165,60 @@
                 mBluetoothLeAudio.getAudioLocation(testDevice));
     }
 
+    public void test_setgetConnectionPolicy() {
+        if (!(mHasBluetooth && mIsLeAudioSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothLeAudio);
+
+        assertFalse(mBluetoothLeAudio.setConnectionPolicy(null, 0));
+        assertEquals(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN,
+                mBluetoothLeAudio.getConnectionPolicy(null));
+    }
+
+    public void test_setVolume() {
+        if (!(mHasBluetooth && mIsLeAudioSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothLeAudio);
+
+        // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission
+        assertThrows(SecurityException.class, () -> mBluetoothLeAudio.setVolume(42));
+    }
+
+    public void testGetCodecStatus() {
+        if (!(mHasBluetooth && mIsLeAudioSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothLeAudio);
+
+        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+
+        assertNull(mBluetoothLeAudio.getCodecStatus(testDevice));
+        assertThrows(IllegalArgumentException.class, () -> {
+            mBluetoothLeAudio.getCodecStatus(null);
+        });
+    }
+
+    public void testSetCodecConfigPreference() {
+        if (!(mHasBluetooth && mIsLeAudioSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothLeAudio);
+
+        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+
+        BluetoothLeAudioCodecConfig codecConfig = new BluetoothLeAudioCodecConfig.Builder()
+                .setCodecType(BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3)
+                .setCodecPriority(0)
+                .build();
+        mBluetoothLeAudio.setCodecConfigPreference(testDevice, codecConfig);
+        assertNull(mBluetoothLeAudio.getCodecStatus(testDevice));
+        assertThrows(IllegalArgumentException.class, () -> {
+            mBluetoothLeAudio.setCodecConfigPreference(null, null);
+        });
+    }
+
     private boolean waitForProfileConnect() {
         mProfileConnectedlock.lock();
         try {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastAssistantTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastAssistantTest.java
index 4894546..1118fd8 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastAssistantTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastAssistantTest.java
@@ -33,9 +33,9 @@
 import android.os.Build;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.ApiLevelUtil;
 
@@ -81,6 +81,8 @@
         if (!mHasBluetooth) {
             return;
         }
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+            .adoptShellPermissionIdentity(android.Manifest.permission.BLUETOOTH_CONNECT);
         BluetoothManager manager = mContext.getSystemService(BluetoothManager.class);
         mAdapter = manager.getAdapter();
         assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
@@ -123,6 +125,8 @@
             }
             assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
             mAdapter = null;
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .dropShellPermissionIdentity();
         }
     }
 
@@ -182,7 +186,7 @@
             return;
         }
         if (mAdapter.isLeAudioBroadcastAssistantSupported()
-                == BluetoothStatusCodes.ERROR_FEATURE_NOT_SUPPORTED) {
+                == BluetoothStatusCodes.FEATURE_NOT_SUPPORTED) {
             assertFalse(mIsLeBroadcastAssistantSupported);
             return;
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastTest.java
index 0aeff6f..1ad8e3b 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastTest.java
@@ -179,7 +179,7 @@
             return;
         }
         if (mAdapter.isLeAudioBroadcastSourceSupported()
-                == BluetoothStatusCodes.ERROR_FEATURE_NOT_SUPPORTED) {
+                == BluetoothStatusCodes.FEATURE_NOT_SUPPORTED) {
             assertFalse(mIsLeBroadcastSupported);
             return;
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
index 1036095..828de6a 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
@@ -27,7 +27,6 @@
 import android.bluetooth.le.ScanSettings;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.os.ParcelUuid;
 import android.os.SystemClock;
 import android.test.AndroidTestCase;
@@ -76,6 +75,8 @@
         if (!TestUtils.isBleSupported(getContext())) {
             return;
         }
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+            .adoptShellPermissionIdentity(android.Manifest.permission.BLUETOOTH_CONNECT);
         BluetoothManager manager = (BluetoothManager) mContext.getSystemService(
                 Context.BLUETOOTH_SERVICE);
         mBluetoothAdapter = manager.getAdapter();
@@ -102,6 +103,8 @@
             TestUtils.disableLocation(getContext());
         }
         assertTrue(BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext));
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+            .dropShellPermissionIdentity();
     }
 
     /**
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothSapTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothSapTest.java
new file mode 100644
index 0000000..dfe22d1
--- /dev/null
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothSapTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.bluetooth.cts;
+
+import static org.junit.Assert.assertThrows;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSap;
+import android.content.pm.PackageManager;
+import android.sysprop.BluetoothProperties;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class BluetoothSapTest extends AndroidTestCase {
+    private static final String TAG = BluetoothLeAudioTest.class.getSimpleName();
+
+    private static final int PROXY_CONNECTION_TIMEOUT_MS = 500;  // ms timeout for Proxy Connect
+
+    private boolean mHasBluetooth;
+    private BluetoothAdapter mAdapter;
+
+    private BluetoothSap mBluetoothSap;
+    private boolean mIsProfileReady;
+    private Condition mConditionProfileIsConnected;
+    private ReentrantLock mProfileConnectedlock;
+
+    private boolean mIsSapSupported;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_BLUETOOTH);
+
+        if (!mHasBluetooth) return;
+
+        mIsSapSupported = BluetoothProperties.isProfileSapServerEnabled().orElse(false);
+        if (!mIsSapSupported) return;
+
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+            .adoptShellPermissionIdentity(android.Manifest.permission.BLUETOOTH_CONNECT);
+
+        mAdapter = getContext().getSystemService(BluetoothManager.class).getAdapter();
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        mProfileConnectedlock = new ReentrantLock();
+        mConditionProfileIsConnected  = mProfileConnectedlock.newCondition();
+        mIsProfileReady = false;
+        mBluetoothSap = null;
+
+        mAdapter.getProfileProxy(getContext(), new BluetoothSapServiceListener(),
+                BluetoothProfile.SAP);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (mHasBluetooth && mIsSapSupported) {
+            if (mAdapter != null && mBluetoothSap != null) {
+                mBluetoothSap.close();
+                mBluetoothSap = null;
+                mIsProfileReady = false;
+            }
+            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .dropShellPermissionIdentity();
+            mAdapter = null;
+        }
+    }
+
+    public void test_setgetConnectionPolicy() {
+        if (!mHasBluetooth || !mIsSapSupported) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothSap);
+
+        assertThrows(NullPointerException.class, () -> mBluetoothSap.setConnectionPolicy(null, 0));
+        assertThrows(NullPointerException.class, () -> mBluetoothSap.getConnectionPolicy(null));
+    }
+
+    private boolean waitForProfileConnect() {
+        mProfileConnectedlock.lock();
+        try {
+            // Wait for the Adapter to be disabled
+            while (!mIsProfileReady) {
+                if (!mConditionProfileIsConnected.await(
+                        PROXY_CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                    // Timeout
+                    Log.e(TAG, "Timeout while waiting for Profile Connect");
+                    break;
+                } // else spurious wakeups
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "waitForProfileConnect: interrrupted");
+        } finally {
+            mProfileConnectedlock.unlock();
+        }
+        return mIsProfileReady;
+    }
+
+    private final class BluetoothSapServiceListener implements BluetoothProfile.ServiceListener {
+
+        @Override
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            mProfileConnectedlock.lock();
+            mBluetoothSap = (BluetoothSap) proxy;
+            mIsProfileReady = true;
+            try {
+                mConditionProfileIsConnected.signal();
+            } finally {
+                mProfileConnectedlock.unlock();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(int profile) {
+        }
+    }
+}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BufferConstraintsTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BufferConstraintsTest.java
index cc29ccf..1e0ff7b 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BufferConstraintsTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BufferConstraintsTest.java
@@ -60,7 +60,7 @@
         }
         mBufferConstraints = new BufferConstraints(mBufferConstraintList);
 
-        for (int i = 0; i < BluetoothCodecConfig.getMaxCodecType(); i++) {
+        for (int i = 0; i < 6; i++) {
             assertEquals(DEFAULT_BUFFER_TIME, mBufferConstraints.forCodec(i).getDefaultMillis());
             assertEquals(MAXIMUM_BUFFER_TIME, mBufferConstraints.forCodec(i).getMaxMillis());
             assertEquals(MINIMUM_BUFFER_TIME, mBufferConstraints.forCodec(i).getMinMillis());
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java
index 4e1419a..570633e 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java
@@ -16,6 +16,11 @@
 
 package android.bluetooth.cts;
 
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
+
+import static org.junit.Assert.assertThrows;
+
+import android.app.UiAutomation;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHearingAid;
@@ -30,13 +35,14 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 
-import java.io.IOException;
-import java.util.List;
+import androidx.test.InstrumentationRegistry;
+
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Unit test cases for {@link BluetoothHearingAid}.
@@ -61,6 +67,7 @@
     private BluetoothHearingAid mService;
     private BluetoothAdapter mBluetoothAdapter;
     private BroadcastReceiver mIntentReceiver;
+    private UiAutomation mUiAutomation;;
 
     private Condition mConditionProfileIsConnected;
     private ReentrantLock mProfileConnectedlock;
@@ -76,15 +83,14 @@
         if (!isBleSupported()) return;
         mIsBleSupported = true;
 
+        mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
+
         BluetoothManager manager = (BluetoothManager) mContext.getSystemService(
                 Context.BLUETOOTH_SERVICE);
         mBluetoothAdapter = manager.getAdapter();
 
-        if (!BTAdapterUtils.enableAdapter(mBluetoothAdapter, mContext)) {
-            Log.e(TAG, "Unable to enable Bluetooth Adapter!");
-            assertTrue(mBluetoothAdapter.isEnabled());
-        }
-
+        assertTrue(BTAdapterUtils.enableAdapter(mBluetoothAdapter, mContext));
         mProfileConnectedlock = new ReentrantLock();
         mConditionProfileIsConnected  = mProfileConnectedlock.newCondition();
         mIsProfileReady = false;
@@ -99,10 +105,8 @@
     public void tearDown() {
         if (!mIsBleSupported) return;
 
-        if (!BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext)) {
-            Log.e(TAG, "Unable to disable Bluetooth Adapter!");
-            assertTrue(mBluetoothAdapter.isEnabled());
-        }
+        assertTrue(BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext));
+        mUiAutomation.dropShellPermissionIdentity();
     }
 
     /**
@@ -140,6 +144,24 @@
     }
 
     /**
+     * Basic test case to make sure that a fictional device is disconnected.
+     */
+    @MediumTest
+    public void test_setVolume() {
+        if (!(mIsBleSupported && mIsHearingAidSupported)) {
+            return;
+        }
+
+        waitForProfileConnect();
+        assertTrue(mIsProfileReady);
+        assertNotNull(mService);
+
+        // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission
+        assertThrows(SecurityException.class, () -> mService.setVolume(42));
+    }
+
+
+    /**
      * Basic test case to get the list of connected Hearing Aid devices.
      */
     @MediumTest
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java
index b9a93a1..d152d84 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java
@@ -19,7 +19,8 @@
 import android.bluetooth.BluetoothServerSocket;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
 
 import java.io.IOException;
 
@@ -35,6 +36,8 @@
         if (!TestUtils.isBleSupported(getContext())) {
             return;
         }
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+            .adoptShellPermissionIdentity(android.Manifest.permission.BLUETOOTH_CONNECT);
         mAdapter = BluetoothAdapter.getDefaultAdapter();
         assertNotNull("BluetoothAdapter.getDefaultAdapter() returned null. "
                 + "Does this device have a Bluetooth adapter?", mAdapter);
@@ -50,6 +53,8 @@
         }
         assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
         mAdapter = null;
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+            .dropShellPermissionIdentity();
         super.tearDown();
     }
 
diff --git a/tests/tests/content/OWNERS b/tests/tests/content/OWNERS
index 5f3add2..41e033d 100644
--- a/tests/tests/content/OWNERS
+++ b/tests/tests/content/OWNERS
@@ -1,7 +1,8 @@
 # Bug component: 36137
+alexbuy@google.com
+chiuwinson@google.com
 patb@google.com
 schfan@google.com
-alexbuy@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
diff --git a/tests/tests/content/src/android/content/cts/LocusIdTest.java b/tests/tests/content/src/android/content/cts/LocusIdTest.java
index e386f47..c0636e0 100644
--- a/tests/tests/content/src/android/content/cts/LocusIdTest.java
+++ b/tests/tests/content/src/android/content/cts/LocusIdTest.java
@@ -81,7 +81,7 @@
 
         try {
             // Write to parcel
-            parcel.setDataPosition(0); // Sanity / paranoid check
+            parcel.setDataPosition(0); // Initial check
             original.writeToParcel(parcel, 0);
 
             // Read from parcel
diff --git a/tests/tests/dreams/OWNERS b/tests/tests/dreams/OWNERS
index f70efe9..f8c069e 100644
--- a/tests/tests/dreams/OWNERS
+++ b/tests/tests/dreams/OWNERS
@@ -1,3 +1,6 @@
 # Bug component: 345010
+brycelee@google.com
+galinap@google.com
+jjaggi@google.com
 michaelwr@google.com
 santoscordon@google.com
diff --git a/tests/tests/graphics/src/android/graphics/cts/OpenGlEsDeqpLevelTest.java b/tests/tests/graphics/src/android/graphics/cts/OpenGlEsDeqpLevelTest.java
index c6e4b96..1bb1106 100644
--- a/tests/tests/graphics/src/android/graphics/cts/OpenGlEsDeqpLevelTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/OpenGlEsDeqpLevelTest.java
@@ -16,16 +16,16 @@
 
 package android.graphics.cts;
 
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
+import android.content.pm.FeatureInfo;
 import android.content.pm.PackageManager;
 import android.platform.test.annotations.AppModeFull;
-import android.util.Log;
 
-import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.PropertyUtil;
 
@@ -42,31 +42,37 @@
 @AppModeFull(reason = "Instant apps cannot access ro.board.* system properties")
 public class OpenGlEsDeqpLevelTest {
 
-    private static final String TAG = OpenGlEsDeqpLevelTest.class.getSimpleName();
-    private static final boolean DEBUG = false;
-
     private static final int MINIMUM_OPENGLES_DEQP_LEVEL = 0x07E40301; // Corresponds to 2020-03-01
 
-    private PackageManager mPm;
+    private FeatureInfo mFeatureGlesDeqpLevel = null;
 
     @Before
     public void setup() {
-        mPm = InstrumentationRegistry.getTargetContext().getPackageManager();
+        final PackageManager pm =
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager();
+        final FeatureInfo[] features = pm.getSystemAvailableFeatures();
+        if (features != null) {
+            for (FeatureInfo feature : features) {
+                if (PackageManager.FEATURE_OPENGLES_DEQP_LEVEL.equals(feature.name)) {
+                    mFeatureGlesDeqpLevel = feature;
+                }
+            }
+        }
     }
 
     @Test
     public void testOpenGlEsDeqpLevel() {
         assumeTrue(
-                "Test only applies for vendor image with API level >= 31 (Android 12)",
-                PropertyUtil.isVendorApiLevelNewerThan(30));
-        if (DEBUG) {
-            Log.d(TAG, "Checking whether " + PackageManager.FEATURE_OPENGLES_DEQP_LEVEL
-                    + " has an acceptable value");
-        }
-        assertTrue("Feature " + PackageManager.FEATURE_OPENGLES_DEQP_LEVEL + " must be present "
-                + "and have at least version " + MINIMUM_OPENGLES_DEQP_LEVEL,
-                mPm.hasSystemFeature(PackageManager.FEATURE_OPENGLES_DEQP_LEVEL,
-                        MINIMUM_OPENGLES_DEQP_LEVEL));
-    }
+                "Test only applies for API level >= 31 (Android 12)",
+                PropertyUtil.getVsrApiLevel() >= 31);
 
+        if (mFeatureGlesDeqpLevel == null
+                || mFeatureGlesDeqpLevel.version < MINIMUM_OPENGLES_DEQP_LEVEL) {
+            String message = String.format(
+                    "Feature %s must be present and have at least version %d.",
+                    PackageManager.FEATURE_OPENGLES_DEQP_LEVEL, MINIMUM_OPENGLES_DEQP_LEVEL);
+            message += "\nActual feature value: " + mFeatureGlesDeqpLevel;
+            fail(message);
+        }
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/SetFrameRateTest.java b/tests/tests/graphics/src/android/graphics/cts/SetFrameRateTest.java
index 1b41d09..379a732 100644
--- a/tests/tests/graphics/src/android/graphics/cts/SetFrameRateTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/SetFrameRateTest.java
@@ -20,16 +20,16 @@
 
 import static org.junit.Assert.assertTrue;
 
-import android.app.UiAutomation;
+import android.Manifest;
 import android.content.Context;
-import android.util.Log;
+import android.hardware.display.DisplayManager;
 import android.view.Surface;
-import android.view.SurfaceControl;
 
 import androidx.test.filters.MediumTest;
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.AdoptShellPermissionsRule;
 import com.android.compatibility.common.util.DisplayUtil;
 
 import org.junit.After;
@@ -46,38 +46,39 @@
     @Rule
     public ActivityTestRule<FrameRateCtsActivity> mActivityRule =
             new ActivityTestRule<>(FrameRateCtsActivity.class);
-    private long mFrameRateFlexibilityToken;
+
+    @Rule
+    public final AdoptShellPermissionsRule mShellPermissionsRule =
+            new AdoptShellPermissionsRule(getInstrumentation().getUiAutomation(),
+                    Manifest.permission.HDMI_CEC,
+                    Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS,
+                    Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE);
+
+    private DisplayManager mDisplayManager;
+    private int mInitialRefreshRateSwitchingType;
 
     @Before
     public void setUp() throws Exception {
-        // Surface flinger requires the ACCESS_SURFACE_FLINGER permission to acquire a frame
-        // rate flexibility token. Switch to shell permission identity so we'll have the
-        // necessary permission when surface flinger checks.
-        UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
-        uiAutomation.adoptShellPermissionIdentity();
-
         Context context = getInstrumentation().getTargetContext();
         assertTrue("Physical display is expected.", DisplayUtil.isDisplayConnected(context));
 
-        try {
-            // Take ownership of the frame rate flexibility token, if we were able
-            // to get one - we'll release it in tearDown().
-            mFrameRateFlexibilityToken = SurfaceControl.acquireFrameRateFlexibilityToken();
-        } finally {
-            uiAutomation.dropShellPermissionIdentity();
-        }
+        FrameRateCtsActivity activity = mActivityRule.getActivity();
 
-        if (mFrameRateFlexibilityToken == 0) {
-            Log.e(TAG, "Failed to acquire frame rate flexibility token."
-                    + " SetFrameRate tests may fail.");
-        }
+        // Prevent DisplayManager from limiting the allowed refresh rate range based on
+        // non-app policies (e.g. low battery, user settings, etc).
+        mDisplayManager = activity.getSystemService(DisplayManager.class);
+        mDisplayManager.setShouldAlwaysRespectAppRequestedMode(true);
+
+        mInitialRefreshRateSwitchingType = DisplayUtil.getRefreshRateSwitchingType(mDisplayManager);
+        mDisplayManager.setRefreshRateSwitchingType(
+                DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS);
     }
 
     @After
     public void tearDown() {
-        if (mFrameRateFlexibilityToken != 0) {
-            SurfaceControl.releaseFrameRateFlexibilityToken(mFrameRateFlexibilityToken);
-            mFrameRateFlexibilityToken = 0;
+        if (mDisplayManager != null) {
+            mDisplayManager.setRefreshRateSwitchingType(mInitialRefreshRateSwitchingType);
+            mDisplayManager.setShouldAlwaysRespectAppRequestedMode(false);
         }
     }
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/VulkanDeqpLevelTest.java b/tests/tests/graphics/src/android/graphics/cts/VulkanDeqpLevelTest.java
index 277ca80..178a449 100644
--- a/tests/tests/graphics/src/android/graphics/cts/VulkanDeqpLevelTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/VulkanDeqpLevelTest.java
@@ -16,17 +16,16 @@
 
 package android.graphics.cts;
 
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageManager;
 import android.platform.test.annotations.AppModeFull;
-import android.util.Log;
 
-import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.PropertyUtil;
@@ -44,29 +43,26 @@
 @AppModeFull(reason = "Instant apps cannot access ro.board.* system properties")
 public class VulkanDeqpLevelTest {
 
-    private static final String TAG = VulkanDeqpLevelTest.class.getSimpleName();
-    private static final boolean DEBUG = false;
-
     private static final int MINIMUM_VULKAN_DEQP_LEVEL = 0x07E30301; // Corresponds to 2019-03-01
 
     // Require patch version 3 for Vulkan 1.0: It was the first publicly available version,
     // and there was an important bugfix relative to 1.0.2.
     private static final int VULKAN_1_0 = 0x00400003; // 1.0.3
 
-    private PackageManager mPm;
     private FeatureInfo mVulkanHardwareVersion = null;
+    private FeatureInfo mFeatureVulkanDeqpLevel = null;
 
     @Before
     public void setup() {
-        mPm = InstrumentationRegistry.getTargetContext().getPackageManager();
-        FeatureInfo[] features = mPm.getSystemAvailableFeatures();
+        final PackageManager pm =
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager();
+        final FeatureInfo[] features = pm.getSystemAvailableFeatures();
         if (features != null) {
             for (FeatureInfo feature : features) {
                 if (PackageManager.FEATURE_VULKAN_HARDWARE_VERSION.equals(feature.name)) {
                     mVulkanHardwareVersion = feature;
-                    if (DEBUG) {
-                        Log.d(TAG, feature.name + "=0x" + Integer.toHexString(feature.version));
-                    }
+                } else if (PackageManager.FEATURE_VULKAN_DEQP_LEVEL.equals(feature.name)) {
+                    mFeatureVulkanDeqpLevel = feature;
                 }
             }
         }
@@ -76,19 +72,20 @@
     @Test
     public void testVulkanDeqpLevel() {
         assumeTrue(
-                "Test only applies for vendor image with API level >= 30 (Android 11)",
-                PropertyUtil.isVendorApiLevelNewerThan(29));
+                "Test only applies for API level >= 30 (Android 11)",
+                PropertyUtil.getVsrApiLevel() >= 30);
+
         assumeTrue(
                 "Test does not apply if Vulkan 1.0 or higher is not supported",
                 mVulkanHardwareVersion != null && mVulkanHardwareVersion.version >= VULKAN_1_0);
-        if (DEBUG) {
-            Log.d(TAG, "Checking whether " + PackageManager.FEATURE_VULKAN_DEQP_LEVEL
-                    + " has an acceptable value");
-        }
-        assertTrue("Feature " + PackageManager.FEATURE_VULKAN_DEQP_LEVEL + " must be present "
-                + "and have at least version " + MINIMUM_VULKAN_DEQP_LEVEL,
-                mPm.hasSystemFeature(PackageManager.FEATURE_VULKAN_DEQP_LEVEL,
-                        MINIMUM_VULKAN_DEQP_LEVEL));
-    }
 
+        if (mFeatureVulkanDeqpLevel == null
+                || mFeatureVulkanDeqpLevel.version < MINIMUM_VULKAN_DEQP_LEVEL) {
+            String message = String.format(
+                    "Feature %s must be present and have at least version %d.",
+                    PackageManager.FEATURE_VULKAN_DEQP_LEVEL, MINIMUM_VULKAN_DEQP_LEVEL);
+            message += "\nActual feature value: " + mFeatureVulkanDeqpLevel;
+            fail(message);
+        }
+    }
 }
diff --git a/tests/tests/jni/Android.bp b/tests/tests/jni/Android.bp
index ddb21ce..5aa391f 100644
--- a/tests/tests/jni/Android.bp
+++ b/tests/tests/jni/Android.bp
@@ -44,6 +44,7 @@
     srcs: ["src/**/*.java"],
     sdk_version: "test_current",
     use_embedded_native_libs: false,
+    per_testcase_directory: true,
 }
 
 cc_test_library {
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
index 45b2683..a1cb4bc 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
+++ b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
@@ -80,15 +80,6 @@
 
 static const std::string kWebViewPlatSupportLib = "libwebviewchromium_plat_support.so";
 
-static bool is_directory(const char* path) {
-  struct stat sb;
-  if (stat(path, &sb) != -1) {
-    return S_ISDIR(sb.st_mode);
-  }
-
-  return false;
-}
-
 static bool not_accessible(const std::string& err) {
   return err.find("dlopen failed: library \"") == 0 &&
          err.find("is not accessible for the namespace \"classloader-namespace\"") != std::string::npos;
@@ -305,11 +296,19 @@
       }
 
       std::string path = dir + "/" + dp->d_name;
-      if (is_directory(path.c_str())) {
-        dirs.push(path);
-      } else if (!check_lib(env, clazz, path, library_search_paths, public_library_basenames,
-                            test_system_load_library, check_absence, errors)) {
-        success = false;
+      struct stat sb;
+      // Use lstat to not dereference a symlink. If it links out of library_path
+      // it can be ignored because the Bionic linker derefences symlinks before
+      // checking the path. If it links inside library_path we'll get to the
+      // link target anyway.
+      if (lstat(path.c_str(), &sb) != -1) {
+        if (S_ISDIR(sb.st_mode)) {
+          dirs.push(path);
+        } else if (!S_ISLNK(sb.st_mode) &&
+                   !check_lib(env, clazz, path, library_search_paths, public_library_basenames,
+                              test_system_load_library, check_absence, errors)) {
+          success = false;
+        }
       }
     }
   }
diff --git a/tests/tests/keystore/OWNERS b/tests/tests/keystore/OWNERS
index 30685c8..21e2825 100644
--- a/tests/tests/keystore/OWNERS
+++ b/tests/tests/keystore/OWNERS
@@ -2,3 +2,5 @@
 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/CipherTest.java b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
index 94dd585..e6de053 100644
--- a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
@@ -16,6 +16,8 @@
 
 package android.keystore.cts;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -42,6 +44,9 @@
 
 import com.google.common.collect.ObjectArrays;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.security.AlgorithmParameters;
@@ -49,10 +54,10 @@
 import java.security.Key;
 import java.security.KeyStoreException;
 import java.security.Provider;
+import java.security.Provider.Service;
 import java.security.Security;
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.MGF1ParameterSpec;
-import java.security.Provider.Service;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
@@ -74,9 +79,6 @@
 import javax.crypto.spec.PSource;
 import javax.crypto.spec.SecretKeySpec;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 /**
  * Tests for algorithm-agnostic functionality of {@code Cipher} implementations backed by Android
  * Keystore.
@@ -1205,6 +1207,7 @@
                 fail("Importing auth bound keys to an insecure device should fail");
             } catch (KeyStoreException e) {
                 // Expected behavior
+                assertThat(e.getCause()).isInstanceOf(IllegalStateException.class);
             }
         }
     }
diff --git a/tests/tests/keystore/src/android/keystore/cts/ImportWrappedKeyTest.java b/tests/tests/keystore/src/android/keystore/cts/ImportWrappedKeyTest.java
index 4b66992..e61d2b3 100644
--- a/tests/tests/keystore/src/android/keystore/cts/ImportWrappedKeyTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/ImportWrappedKeyTest.java
@@ -25,16 +25,16 @@
 import static android.security.keymaster.KeymasterDefs.KM_PAD_PKCS7;
 import static android.security.keymaster.KeymasterDefs.KM_PURPOSE_DECRYPT;
 import static android.security.keymaster.KeymasterDefs.KM_PURPOSE_ENCRYPT;
-import static android.security.keystore.KeyProperties.PURPOSE_WRAP_KEY;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.keystore.cts.util.TestUtils;
-import android.os.SystemProperties;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.SecureKeyImportUnavailableException;
@@ -52,6 +52,8 @@
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERSet;
 import org.bouncycastle.asn1.DERTaggedObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.security.Key;
 import java.security.KeyPair;
@@ -63,7 +65,6 @@
 import java.security.SecureRandom;
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.MGF1ParameterSpec;
-import java.security.spec.RSAKeyGenParameterSpec;
 import java.util.Arrays;
 
 import javax.crypto.Cipher;
@@ -74,16 +75,6 @@
 import javax.crypto.spec.PSource;
 import javax.crypto.spec.SecretKeySpec;
 
-import java.lang.Process;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.lang.InterruptedException;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 @RunWith(AndroidJUnit4.class)
 public class ImportWrappedKeyTest {
     private static final String TAG = "ImportWrappedKeyTest";
@@ -146,20 +137,24 @@
     @Test
     public void testKeyStore_ImportWrappedKeyWrappingKeyMissing() throws Exception {
         final String EXPECTED_FAILURE = "Failed to import wrapped key. Keystore error code: 7";
-        String failureMessage = null;
+        KeyStoreException exception = null;
 
         try {
             byte [] fakeWrappedKey = new byte[1];
             importWrappedKey(fakeWrappedKey, WRAPPING_KEY_ALIAS + "_Missing");
         } catch (KeyStoreException e) {
-            failureMessage = e.getMessage();
+            exception = e;
+
         }
 
-        if (failureMessage == null) {
-            fail("Did not hit a failure but expected one");
-        }
+        assertWithMessage("Did not hit a failure but expected one").that(exception).isNotNull();
 
-        assertEquals(failureMessage, EXPECTED_FAILURE);
+        assertThat(exception.getMessage()).isEqualTo(EXPECTED_FAILURE);
+        assertThat(exception.getCause()).isInstanceOf(android.security.KeyStoreException.class);
+        android.security.KeyStoreException ksException =
+                (android.security.KeyStoreException) exception.getCause();
+        assertThat(ksException.getNumericErrorCode()).isEqualTo(
+                android.security.KeyStoreException.ERROR_KEY_DOES_NOT_EXIST);
     }
 
     @Test
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 27e2f30..d182cfc 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -46,7 +46,6 @@
 import static android.security.keystore.KeyProperties.SIGNATURE_PADDING_RSA_PKCS1;
 import static android.security.keystore.KeyProperties.SIGNATURE_PADDING_RSA_PSS;
 
-import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.either;
@@ -54,7 +53,6 @@
 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
 import static org.hamcrest.Matchers.hasItems;
 import static org.hamcrest.Matchers.lessThanOrEqualTo;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -77,18 +75,22 @@
 import android.security.keystore.KeyProperties;
 import android.util.ArraySet;
 import android.util.Log;
+
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.RequiresDevice;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.google.common.collect.ImmutableSet;
 
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.File;
 import java.security.GeneralSecurityException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.KeyStore;
 import java.security.NoSuchAlgorithmException;
@@ -106,14 +108,9 @@
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+
 import javax.crypto.KeyGenerator;
 
-import org.bouncycastle.asn1.x500.X500Name;
-import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 /**
  * Tests for Android Keystore attestation.
  */
@@ -211,10 +208,11 @@
                                         curves[curveIndex], keySizes[curveIndex],
                                         purposes[purposeIndex], devicePropertiesAttestation);
                             } catch (Throwable e) {
-                                if (devicePropertiesAttestation
-                                        && (e.getCause() instanceof KeyStoreException)
-                                        && KM_ERROR_CANNOT_ATTEST_IDS ==
-                                                ((KeyStoreException) e.getCause()).getErrorCode()) {
+                                boolean isIdAttestationFailure =
+                                        (e.getCause() instanceof KeyStoreException)
+                                        && KeyStoreException.ERROR_ID_ATTESTATION_FAILURE
+                                        == ((KeyStoreException) e.getCause()).getNumericErrorCode();
+                                if (devicePropertiesAttestation && isIdAttestationFailure) {
                                     Log.i(TAG, "key attestation with device IDs not supported; "
                                             + "test skipped");
                                     continue;
@@ -232,6 +230,19 @@
         }
     }
 
+    private void assertPublicAttestationError(KeyStoreException keyStoreException,
+            boolean devicePropertiesAttestation) {
+        // Assert public failure information.
+        int errorCode = keyStoreException.getNumericErrorCode();
+        String assertMessage = String.format(
+                "Error code was %d, device properties attestation? %b",
+                errorCode, devicePropertiesAttestation);
+        assertTrue(assertMessage, KeyStoreException.ERROR_INCORRECT_USAGE == errorCode
+                || (devicePropertiesAttestation
+                && KeyStoreException.ERROR_ID_ATTESTATION_FAILURE == errorCode));
+        assertFalse(keyStoreException.isTransientFailure());
+    }
+
     @Test
     public void testEcAttestation_TooLargeChallenge() throws Exception {
         if (!TestUtils.isAttestationSupported()) {
@@ -250,6 +261,7 @@
                         (devicePropertiesAttestation
                                 && KM_ERROR_CANNOT_ATTEST_IDS == cause.getErrorCode())
                 );
+                assertPublicAttestationError(cause, devicePropertiesAttestation);
             }
         }
     }
@@ -452,6 +464,9 @@
             // Attestation is expected to fail because of lack of permissions.
             KeyStoreException cause = (KeyStoreException) e.getCause();
             assertEquals(KM_ERROR_PERMISSION_DENIED, cause.getErrorCode());
+            // Assert public failure information.
+            assertEquals(KeyStoreException.ERROR_PERMISSION_DENIED, cause.getNumericErrorCode());
+            assertFalse(cause.isTransientFailure());
         } finally {
             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
             keyStore.load(null);
@@ -547,6 +562,7 @@
                         (devicePropertiesAttestation
                                 && KM_ERROR_CANNOT_ATTEST_IDS == cause.getErrorCode())
                 );
+                assertPublicAttestationError(cause, devicePropertiesAttestation);
             }
         }
     }
@@ -685,9 +701,11 @@
                 testRsaAttestation(challenge, false /* includeValidityDates */, keySize, purpose,
                         paddings, devicePropertiesAttestation);
             } catch (Throwable e) {
-                if (devicePropertiesAttestation && (e.getCause() instanceof KeyStoreException)
-                        && KM_ERROR_CANNOT_ATTEST_IDS ==
-                                ((KeyStoreException) e.getCause()).getErrorCode()) {
+                boolean isIdAttestationFailure =
+                        (e.getCause() instanceof KeyStoreException)
+                                && KeyStoreException.ERROR_ID_ATTESTATION_FAILURE
+                                == ((KeyStoreException) e.getCause()).getNumericErrorCode();
+                if (devicePropertiesAttestation && isIdAttestationFailure) {
                     Log.i(TAG, "key attestation with device IDs not supported; test skipped");
                     continue;
                 }
@@ -708,6 +726,21 @@
         testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_MEID, "Unable to retrieve MEID");
     }
 
+    @Test
+    public void testMandatoryDeviceidAttestation() {
+        // ID attestation is only mandatory on devices that have shipped with T and
+        // above.
+        if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.S) {
+            return;
+        }
+        // ID attestation is tested by other tests (outside of this class), including negative
+        // tests that ID attestation is failing if the platform does not declare support.
+        // Hence, it's safe to only test here that the feature is supported.
+        PackageManager pm = getContext().getPackageManager();
+        assertThat("As of Android T, devices must support ID attestation",
+                pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ID_ATTESTATION),is(true));
+    }
+
     @SuppressWarnings("deprecation")
     private void testRsaAttestation(byte[] challenge, boolean includeValidityDates, int keySize,
             int purposes, String[] paddingModes, boolean devicePropertiesAttestation)
@@ -1151,9 +1184,6 @@
                         + attestation.getAttestationSecurityLevel());
                 break;
         }
-
-        assertNull("Software-enforced list must not contain root of trust",
-                softwareEnforced.getRootOfTrust());
     }
 
     private void checkDeviceLocked(Attestation attestation) {
@@ -1191,7 +1221,9 @@
         assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length +
                    " bytes long", rootOfTrust.getVerifiedBootKey().length >= 32);
         if (requireLocked) {
-            assertTrue(rootOfTrust.isDeviceLocked());
+            final String unlockedDeviceMessage = "The device's bootloader must be locked. This may "
+                    + "not be the default for pre-production devices.";
+            assertTrue(unlockedDeviceMessage, rootOfTrust.isDeviceLocked());
             checkEntropy(rootOfTrust.getVerifiedBootKey());
             assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState());
         }
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyStoreExceptionTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyStoreExceptionTest.java
new file mode 100644
index 0000000..b79f443
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyStoreExceptionTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.keystore.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.security.KeyStoreException;
+import android.security.keymaster.KeymasterDefs;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+public class KeyStoreExceptionTest {
+    @Test
+    public void testAllKeymasterDefsAreCovered() throws IllegalAccessException {
+        ImmutableList<Field> kmErrors = getKeymasterDefsFields();
+        assertTrue("Test bug: there should be errors to look up",
+                kmErrors.size() > 0);
+
+        for (Field f : kmErrors) {
+            assertTrue(String.format("Missing entry for field %s", f.getName()),
+                    KeyStoreException.hasFailureInfoForError(f.getInt(null)));
+        }
+    }
+
+    @Test
+    public void testSystemErrorFlaggedCorrectly() {
+        final int[] someSystemErrors = {-4, -6, -7, -9, -28, -64, -66, -67, -72, -1000, 3, 4};
+        for (int i : someSystemErrors) {
+            KeyStoreException systemEx = new KeyStoreException(i, null);
+            assertTrue("Error code " + i + " is not correctly marked as system error.",
+                    systemEx.isSystemError());
+        }
+
+        final int[] someNonSystemErrors = {-3, -5, -8, -11, -29, 6};
+        for (int i : someNonSystemErrors) {
+            KeyStoreException nonSystemEx = new KeyStoreException(i, null);
+            assertFalse("Error code " + i + " is incorrectly marked as system error.",
+                    nonSystemEx.isSystemError());
+        }
+    }
+
+    @Test
+    public void testRequiresUserAuthenticationFlaggedCorrectly() {
+        final int[] errorsRequiringAuthentication = {-26, -72, 2};
+
+        for (int i : errorsRequiringAuthentication) {
+            KeyStoreException ex = new KeyStoreException(i, null);
+            assertTrue("Error code " + i + " is not correctly marked as requiring user auth.",
+                    ex.requiresUserAuthentication());
+        }
+
+        KeyStoreException regularEx = new KeyStoreException(6 /* permission denied */, null);
+        assertFalse(regularEx.requiresUserAuthentication());
+    }
+
+    public static ImmutableList<Field> getKeymasterDefsFields() {
+        ImmutableList.Builder<Field> errorFieldsBuilder = new ImmutableList.Builder<>();
+
+        Class kmDefsClass = KeymasterDefs.class;
+        for (Field f : kmDefsClass.getDeclaredFields()) {
+            if (f.getName().startsWith("KM_ERROR") && f.getType().equals(int.class)) {
+                errorFieldsBuilder.add(f);
+            }
+        }
+
+        return errorFieldsBuilder.build();
+    }
+}
diff --git a/tests/tests/media/Android.bp b/tests/tests/media/Android.bp
index 7ee7d2a..6e6c902 100644
--- a/tests/tests/media/Android.bp
+++ b/tests/tests/media/Android.bp
@@ -25,161 +25,3 @@
     license_kinds: ["SPDX-license-identifier-CC-BY-3.0"],
     license_text: ["LICENSE_CC_BY"],
 }
-
-java_library {
-    name: "ctsmediautil",
-    srcs: [
-        "common/src/android/media/cts/CodecImage.java",
-        "common/src/android/media/cts/YUVImage.java",
-        "common/src/android/media/cts/CodecUtils.java",
-        "common/src/android/media/cts/CodecState.java",
-        "common/src/android/media/cts/MediaCodecTunneledPlayer.java",
-        "common/src/android/media/cts/MediaTimeProvider.java",
-        "common/src/android/media/cts/NonBlockingAudioTrack.java",
-    ],
-    static_libs: [
-        "compatibility-device-util-axt",
-        "platform-test-annotations",
-    ],
-    platform_apis: true,
-    min_sdk_version: "29",
-    target_sdk_version: "31",
-}
-
-cc_test_library {
-    name: "libctscodecutils_jni",
-    srcs: [
-        "common/jni/codec-utils-jni.cpp",
-        "common/jni/md5_utils.cpp",
-    ],
-    shared_libs: [
-        "libnativehelper_compat_libc++",
-        "liblog",
-    ],
-    header_libs: ["liblog_headers"],
-    // this test suite will run on sdk 29 as part of MTS, make sure it's compatible
-    // (revisit if/when we add features to this library that require newer sdk.
-    sdk_version: "29",
-    cflags: [
-        "-Werror",
-        "-Wall",
-        "-DEGL_EGLEXT_PROTOTYPES",
-    ],
-    stl: "libc++_static",
-    gtest: false,
-}
-
-cc_test_library {
-    name: "libctsmediacommon_jni",
-    srcs: [
-        "common/jni/NdkInputSurface-jni.cpp",
-        "common/jni/NdkMediaCodec-jni.cpp",
-    ],
-    shared_libs: [
-        "libandroid",
-        "libnativehelper_compat_libc++",
-        "liblog",
-        "libmediandk",
-        "libEGL",
-    ],
-    header_libs: ["liblog_headers"],
-    stl: "libc++_static",
-    cflags: [
-        "-Werror",
-        "-Wall",
-        "-DEGL_EGLEXT_PROTOTYPES",
-    ],
-    gtest: false,
-    // this test suite will run on sdk 29 as part of MTS, make sure it's compatible
-    // (revisit if/when we add features to this library that require newer sdk.
-    sdk_version: "29",
-}
-
-android_library {
-    name: "cts-media-common",
-    srcs: [
-        "common/src/**/*.java",
-    ],
-    static_libs: [
-        "androidx.heifwriter_heifwriter",
-        "androidx.test.core",
-        "androidx.test.ext.junit",
-        "compatibility-device-util-axt",
-        "junit",
-        "platform-test-annotations",
-    ],
-    platform_apis: true,
-    libs: [
-        "org.apache.http.legacy",
-        "android.test.base",
-        "android.test.runner",
-    ],
-    min_sdk_version: "29",
-    target_sdk_version: "31",
-}
-
-android_test {
-    name: "CtsMediaTestCases",
-    defaults: ["cts_defaults"],
-    // include both the 32 and 64 bit versions
-    compile_multilib: "both",
-    static_libs: [
-        "androidx.test.core",
-        "androidx.test.ext.junit",
-        "compatibility-device-util-axt",
-        "ctsdeviceutillegacy-axt",
-        "ctsmediautil",
-        "ctstestrunner-axt",
-        "hamcrest-library",
-        "ctstestserver",
-        "cts-media-common",
-        "junit",
-        "junit-params",
-        "testng",
-        "truth-prebuilt",
-        "mockito-target-minus-junit4",
-        "androidx.heifwriter_heifwriter",
-        "CtsCameraUtils",
-    ],
-    jni_libs: [
-        "libctscodecutils_jni",
-        "libctsimagereader_jni",
-        "libctsmediacodec_jni",
-        "libctsmediacommon_jni",
-        "libnativehelper_compat_libc++",
-    ],
-    asset_dirs: ["assets"],
-    resource_dirs: ["res"],
-    aaptflags: [
-        "--auto-add-overlay",
-
-        // Do not compress these files:
-        "-0 .vp9",
-        "-0 .ts",
-        "-0 .heic",
-        "-0 .trp",
-        "-0 .ota",
-        "-0 .mxmf",
-    ],
-    srcs: [
-        "src/**/*.java",
-        "aidl/**/*.aidl",
-    ],
-    // This test uses private APIs
-    platform_apis: true,
-    jni_uses_sdk_apis: true,
-    libs: [
-        "org.apache.http.legacy",
-        "android.test.base",
-        "android.test.runner",
-    ],
-    // Tag this module as a cts test artifact
-    test_suites: [
-        "cts",
-        "general-tests",
-        "mts-media",
-    ],
-    host_required: ["cts-dynamic-config"],
-    min_sdk_version: "29",
-    target_sdk_version: "31",
-}
diff --git a/tests/tests/media/DynamicConfig.xml b/tests/tests/media/DynamicConfig.xml
deleted file mode 100644
index 62ba6b7..0000000
--- a/tests/tests/media/DynamicConfig.xml
+++ /dev/null
@@ -1,38 +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.
--->
-
-<dynamicConfig>
-    <entry key="streaming_media_player_test_http_h263_amr_video1">
-        <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=13&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=5729247E22691EBB3E804DDD523EC42DC17DD8CE.443B81C1E8E6D64E4E1555F568BA46C206507D78&amp;key=ik0&amp;user=android-device-test</value>
-    </entry>
-    <entry key="streaming_media_player_test_http_h263_amr_video2">
-        <value>http://redirector.gvt1.com/videoplayback?id=c80658495af60617&amp;itag=13&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=508D82AB36939345BF6B8D0623CB6CABDD9C64C3.9B3336A96846DF38E5343C46AA57F6CF2956E427&amp;key=ik0&amp;user=android-device-test</value>
-    </entry>
-    <entry key="streaming_media_player_test_http_h264_base_aac_video1">
-        <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=18&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=667AEEF54639926662CE62361400B8F8C1753B3F.15F46C382C68A9F121BA17BF1F56BEDEB4B06091&amp;key=ik0&amp;user=android-device-test</value>
-    </entry>
-    <entry key="streaming_media_player_test_http_h264_base_aac_video2">
-        <value>http://redirector.gvt1.com/videoplayback?id=c80658495af60617&amp;itag=18&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=46A04ED550CA83B79B60060BA80C79FDA5853D26.49582D382B4A9AFAA163DED38D2AE531D85603C0&amp;key=ik0&amp;user=android-device-test</value>
-    </entry>
-    <entry key="streaming_media_player_test_http_mpeg4_sp_aac_video1">
-        <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=17&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=837198AAADF6F36BA6B2D324F690A7C5B7AFE3FF.7138CE5E36D718220726C1FC305497FF2D082249&amp;key=ik0&amp;user=android-device-test</value>
-    </entry>
-    <entry key="streaming_media_player_test_http_mpeg4_sp_aac_video2">
-        <value>http://redirector.gvt1.com/videoplayback?id=c80658495af60617&amp;itag=17&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=70E979A621001201BC18622BDBF914FA870BDA40.6E78890B80F4A33A18835F775B1FF64F0A4D0003&amp;key=ik0&amp;user=android-device-test</value>
-    </entry>
-    <entry key="media_files_url">
-    <value>https://storage.googleapis.com/android_media/cts/tests/tests/media/CtsMediaTestCases-1.4.zip</value>
-    </entry>
-</dynamicConfig>
diff --git a/tests/tests/media/audio/AndroidManifest.xml b/tests/tests/media/audio/AndroidManifest.xml
index bc7fc4b..9ee8519 100644
--- a/tests/tests/media/audio/AndroidManifest.xml
+++ b/tests/tests/media/audio/AndroidManifest.xml
@@ -23,6 +23,8 @@
     <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"/>
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
+    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
 
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
diff --git a/tests/tests/media/codec/AndroidManifest.xml b/tests/tests/media/codec/AndroidManifest.xml
index 4ff8f2d..328929a 100644
--- a/tests/tests/media/codec/AndroidManifest.xml
+++ b/tests/tests/media/codec/AndroidManifest.xml
@@ -23,7 +23,7 @@
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"/>
-
+    <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java b/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java
index 00b2e82..4a023a0 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java
@@ -31,7 +31,6 @@
 import android.opengl.GLES20;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.annotations.RequiresDevice;
-import android.test.AndroidTestCase;
 import android.util.Log;
 
 import androidx.test.filters.FlakyTest;
@@ -42,10 +41,23 @@
 import java.io.FileOutputStream;
 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;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
 /**
  * Generates a series of video frames, encodes them, decodes them, and tests for significant
  * divergence from the original.
@@ -63,16 +75,14 @@
 @RequiresDevice
 // TODO: b/186001256
 @FlakyTest
-public class EncodeDecodeTest extends AndroidTestCase {
+@RunWith(Parameterized.class)
+public class EncodeDecodeTest {
     private static final String TAG = "EncodeDecodeTest";
     private static final boolean VERBOSE = false;           // lots of logging
     private static final boolean DEBUG_SAVE_FILE = false;   // save copy of encoded movie
     private static final String DEBUG_FILE_NAME_BASE = "/sdcard/test.";
 
     // parameters for the encoder
-                                                            // H.264 Advanced Video Coding
-    private static final String MIME_TYPE_AVC = MediaFormat.MIMETYPE_VIDEO_AVC;
-    private static final String MIME_TYPE_VP8 = MediaFormat.MIMETYPE_VIDEO_VP8;
     private static final int FRAME_RATE = 15;               // 15fps
     private static final int IFRAME_INTERVAL = 10;          // 10 seconds between I-frames
 
@@ -96,97 +106,80 @@
     private static final int TEST_B1_BT709 = 189;
     private static final boolean USE_NDK = true;
 
+    // component names
+    private final String mEncoderName;
+    private final String mDecoderName;
+    // mime
+    private final String mMimeType;
     // size of a frame, in pixels
-    private int mWidth = -1;
-    private int mHeight = -1;
+    private final int mWidth;
+    private final int mHeight;
     // bit rate, in bits per second
-    private int mBitRate = -1;
-    private String mMimeType = MIME_TYPE_AVC;
-
-    // largest color component delta seen (i.e. actual vs. expected)
-    private int mLargestColorDelta;
-
+    private final int mBitRate;
     // validate YUV->RGB decoded frames against BT.601 and/or BT.709
     private boolean mAllowBT601 = true;
     private boolean mAllowBT709 = false;
 
-    /**
-     * Tests streaming of AVC video through the encoder and decoder.  Data is encoded from
-     * a series of byte[] buffers and decoded into ByteBuffers.  The output is checked for
-     * validity.
-     */
-    public void testEncodeDecodeVideoFromBufferToBufferQCIF() throws Exception {
-        setParameters(176, 144, 1000000, MIME_TYPE_AVC, true, false);
-        encodeDecodeVideoFromBuffer(false);
-    }
-    public void testEncodeDecodeVideoFromBufferToBufferQVGA() throws Exception {
-        setParameters(320, 240, 2000000, MIME_TYPE_AVC, true, false);
-        encodeDecodeVideoFromBuffer(false);
-    }
-    public void testEncodeDecodeVideoFromBufferToBuffer720p() throws Exception {
-        setParameters(1280, 720, 6000000, MIME_TYPE_AVC, true, false);
-        encodeDecodeVideoFromBuffer(false);
+    // largest color component delta seen (i.e. actual vs. expected)
+    private int mLargestColorDelta;
+
+    static private List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList) {
+        final List<Object[]> argsList = new ArrayList<>();
+        int argLength = exhaustiveArgsList.get(0).length;
+        MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+        for (Object[] arg : exhaustiveArgsList) {
+            MediaFormat format = MediaFormat.createVideoFormat((String)arg[0], (Integer)arg[1],
+                    (Integer)arg[2]);
+
+            String eName = mcl.findEncoderForFormat(format);
+            String dName = mcl.findDecoderForFormat(format);
+
+            Object[] testArgs = new Object[argLength + 2];
+            testArgs[0] = eName;
+            testArgs[1] = dName;
+            System.arraycopy(arg, 0, testArgs, 2, argLength);
+            argsList.add(testArgs);
+        }
+        return argsList;
     }
 
-    /**
-     * Tests streaming of VP8 video through the encoder and decoder.  Data is encoded from
-     * a series of byte[] buffers and decoded into ByteBuffers.  The output is checked for
-     * validity.
-     */
-    public void testVP8EncodeDecodeVideoFromBufferToBufferQCIF() throws Exception {
-        setParameters(176, 144, 1000000, MIME_TYPE_VP8, true, false);
-        encodeDecodeVideoFromBuffer(false);
-    }
-    public void testVP8EncodeDecodeVideoFromBufferToBufferQVGA() throws Exception {
-        setParameters(320, 240, 2000000, MIME_TYPE_VP8, true, false);
-        encodeDecodeVideoFromBuffer(false);
-    }
-    public void testVP8EncodeDecodeVideoFromBufferToBuffer720p() throws Exception {
-        setParameters(1280, 720, 6000000, MIME_TYPE_VP8, true, false);
-        encodeDecodeVideoFromBuffer(false);
+    @Before
+    public void shouldSkip() {
+        MediaFormat format = MediaFormat.createVideoFormat(mMimeType, mWidth, mHeight);
+        format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
+        format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
+        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
+        assumeTrue(MediaUtils.supports(mEncoderName, format));
+        assumeTrue(MediaUtils.supports(mDecoderName, format));
     }
 
-    /**
-     * Tests streaming of AVC video through the encoder and decoder.  Data is encoded from
-     * a series of byte[] buffers and decoded into Surfaces.  The output is checked for
-     * validity.
-     * <p>
-     * Because of the way SurfaceTexture.OnFrameAvailableListener works, we need to run this
-     * test on a thread that doesn't have a Looper configured.  If we don't, the test will
-     * pass, but we won't actually test the output because we'll never receive the "frame
-     * available" notifications".  The CTS test framework seems to be configuring a Looper on
-     * the test thread, so we have to hand control off to a new thread for the duration of
-     * the test.
-     */
-    public void testEncodeDecodeVideoFromBufferToSurfaceQCIF() throws Throwable {
-        setParameters(176, 144, 1000000, MIME_TYPE_AVC, true, false);
-        BufferToSurfaceWrapper.runTest(this);
-    }
-    public void testEncodeDecodeVideoFromBufferToSurfaceQVGA() throws Throwable {
-        setParameters(320, 240, 2000000, MIME_TYPE_AVC, true, false);
-        BufferToSurfaceWrapper.runTest(this);
-    }
-    public void testEncodeDecodeVideoFromBufferToSurface720p() throws Throwable {
-        setParameters(1280, 720, 6000000, MIME_TYPE_AVC, true, true);
-        BufferToSurfaceWrapper.runTest(this);
+    @Parameterized.Parameters(name = "{index}({0}:{1})")
+    public static Collection<Object[]> input() {
+        final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+                // Mime, width, height, bit-rate, allow bt601, allow bt709
+                {MediaFormat.MIMETYPE_VIDEO_AVC, 176, 144, 1000000, true, false},
+                {MediaFormat.MIMETYPE_VIDEO_AVC, 320, 240, 2000000, true, false},
+                {MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720, 6000000, true, true},
+                {MediaFormat.MIMETYPE_VIDEO_VP8, 176, 144, 1000000, true, false},
+                {MediaFormat.MIMETYPE_VIDEO_VP8, 320, 240, 2000000, true, false},
+                {MediaFormat.MIMETYPE_VIDEO_VP8, 1280, 720, 6000000, true, true},
+        });
+        return prepareParamList(exhaustiveArgsList);
     }
 
-    /**
-     * Tests streaming of VP8 video through the encoder and decoder.  Data is encoded from
-     * a series of byte[] buffers and decoded into Surfaces.  The output is checked for
-     * validity.
-     */
-    public void testVP8EncodeDecodeVideoFromBufferToSurfaceQCIF() throws Throwable {
-        setParameters(176, 144, 1000000, MIME_TYPE_VP8, true, false);
-        BufferToSurfaceWrapper.runTest(this);
-    }
-    public void testVP8EncodeDecodeVideoFromBufferToSurfaceQVGA() throws Throwable {
-        setParameters(320, 240, 2000000, MIME_TYPE_VP8, true, false);
-        BufferToSurfaceWrapper.runTest(this);
-    }
-    public void testVP8EncodeDecodeVideoFromBufferToSurface720p() throws Throwable {
-        setParameters(1280, 720, 6000000, MIME_TYPE_VP8, true, true);
-        BufferToSurfaceWrapper.runTest(this);
+    public EncodeDecodeTest(String encoder, String decoder, String mimeType, int width, int height,
+            int bitRate, boolean allowBT601, boolean allowBT709) {
+        if ((width % 16) != 0 || (height % 16) != 0) {
+            Log.w(TAG, "WARNING: width or height not multiple of 16");
+        }
+        mEncoderName = encoder;
+        mDecoderName = decoder;
+        mMimeType = mimeType;
+        mWidth = width;
+        mHeight = height;
+        mBitRate = bitRate;
+        mAllowBT601 = allowBT601;
+        mAllowBT709 = allowBT709;
     }
 
     /** Wraps testEncodeDecodeVideoFromBuffer(true) */
@@ -221,90 +214,6 @@
         }
     }
 
-    /**
-     * Tests streaming of AVC video through the encoder and decoder.  Data is provided through
-     * a Surface and decoded onto a Surface.  The output is checked for validity.
-     */
-    public void testEncodeDecodeVideoFromSurfaceToSurfaceQCIF() throws Throwable {
-        setParameters(176, 144, 1000000, MIME_TYPE_AVC, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, false, false);
-    }
-    public void testEncodeDecodeVideoFromSurfaceToSurfaceQVGA() throws Throwable {
-        setParameters(320, 240, 2000000, MIME_TYPE_AVC, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, false, false);
-    }
-    public void testEncodeDecodeVideoFromSurfaceToSurface720p() throws Throwable {
-        setParameters(1280, 720, 6000000, MIME_TYPE_AVC, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, false, false);
-    }
-    public void testEncodeDecodeVideoFromSurfaceToSurface720pNdk() throws Throwable {
-        setParameters(1280, 720, 6000000, MIME_TYPE_AVC, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, false, USE_NDK);
-    }
-
-    /**
-     * Tests streaming of AVC video through the encoder and decoder.  Data is provided through
-     * a PersistentSurface and decoded onto a Surface.  The output is checked for validity.
-     */
-    public void testEncodeDecodeVideoFromPersistentSurfaceToSurfaceQCIF() throws Throwable {
-        setParameters(176, 144, 1000000, MIME_TYPE_AVC, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, true, false);
-    }
-    public void testEncodeDecodeVideoFromPersistentSurfaceToSurfaceQVGA() throws Throwable {
-        setParameters(320, 240, 2000000, MIME_TYPE_AVC, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, true, false);
-    }
-    public void testEncodeDecodeVideoFromPersistentSurfaceToSurface720p() throws Throwable {
-        setParameters(1280, 720, 6000000, MIME_TYPE_AVC, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, true, false);
-    }
-    public void testEncodeDecodeVideoFromPersistentSurfaceToSurface720pNdk() throws Throwable {
-        setParameters(1280, 720, 6000000, MIME_TYPE_AVC, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, true, USE_NDK);
-    }
-
-    /**
-     * Tests streaming of VP8 video through the encoder and decoder.  Data is provided through
-     * a Surface and decoded onto a Surface.  The output is checked for validity.
-     */
-    public void testVP8EncodeDecodeVideoFromSurfaceToSurfaceQCIF() throws Throwable {
-        setParameters(176, 144, 1000000, MIME_TYPE_VP8, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, false, false);
-    }
-    public void testVP8EncodeDecodeVideoFromSurfaceToSurfaceQVGA() throws Throwable {
-        setParameters(320, 240, 2000000, MIME_TYPE_VP8, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, false, false);
-    }
-    public void testVP8EncodeDecodeVideoFromSurfaceToSurface720p() throws Throwable {
-        setParameters(1280, 720, 6000000, MIME_TYPE_VP8, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, false, false);
-    }
-    public void testVP8EncodeDecodeVideoFromSurfaceToSurface720pNdk() throws Throwable {
-        setParameters(1280, 720, 6000000, MIME_TYPE_VP8, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, false, USE_NDK);
-    }
-
-    /**
-     * Tests streaming of VP8 video through the encoder and decoder.  Data is provided through
-     * a PersistentSurface and decoded onto a Surface.  The output is checked for validity.
-     */
-    public void testVP8EncodeDecodeVideoFromPersistentSurfaceToSurfaceQCIF() throws Throwable {
-        setParameters(176, 144, 1000000, MIME_TYPE_VP8, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, true, false);
-    }
-    public void testVP8EncodeDecodeVideoFromPersistentSurfaceToSurfaceQVGA() throws Throwable {
-        setParameters(320, 240, 2000000, MIME_TYPE_VP8, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, true, false);
-    }
-    public void testVP8EncodeDecodeVideoFromPersistentSurfaceToSurface720p() throws Throwable {
-        setParameters(1280, 720, 6000000, MIME_TYPE_VP8, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, true, false);
-    }
-    public void testVP8EncodeDecodeVideoFromPersistentSurfaceToSurface720pNdk() throws Throwable {
-        setParameters(1280, 720, 6000000, MIME_TYPE_VP8, true, false);
-        SurfaceToSurfaceWrapper.runTest(this, true, USE_NDK);
-    }
-
     /** Wraps testEncodeDecodeVideoFromSurfaceToSurface() */
     private static class SurfaceToSurfaceWrapper implements Runnable {
         private Throwable mThrowable;
@@ -320,10 +229,6 @@
 
         @Override
         public void run() {
-            if (mTest.shouldSkip()) {
-                return;
-            }
-
             InputSurfaceInterface inputSurface = null;
             try {
                 if (!mUsePersistentInput) {
@@ -367,38 +272,6 @@
     }
 
     /**
-     * Sets the desired frame size and bit rate.
-     */
-    protected void setParameters(int width, int height, int bitRate, String mimeType,
-	        boolean allowBT601, boolean allowBT709) {
-        if ((width % 16) != 0 || (height % 16) != 0) {
-            Log.w(TAG, "WARNING: width or height not multiple of 16");
-        }
-        mWidth = width;
-        mHeight = height;
-        mBitRate = bitRate;
-        mMimeType = mimeType;
-        mAllowBT601 = allowBT601;
-        mAllowBT709 = allowBT709;
-    }
-
-    private boolean shouldSkip() {
-        if (!MediaUtils.hasEncoder(mMimeType)) {
-            return true;
-        }
-
-        MediaFormat format = MediaFormat.createVideoFormat(mMimeType, mWidth, mHeight);
-        format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
-        format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
-        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
-        if (!MediaUtils.checkEncoderForFormat(format)) {
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
      * Tests encoding and subsequently decoding video from frames generated into a buffer.
      * <p>
      * We encode several frames of a video test pattern using MediaCodec, then decode the
@@ -407,10 +280,6 @@
      * See http://b.android.com/37769 for a discussion of input format pitfalls.
      */
     private void encodeDecodeVideoFromBuffer(boolean toSurface) throws Exception {
-        if (shouldSkip()) {
-            return;
-        }
-
         MediaCodec encoder = null;
         MediaCodec decoder = null;
 
@@ -420,24 +289,10 @@
             // We avoid the device-specific limitations on width and height by using values that
             // are multiples of 16, which all tested devices seem to be able to handle.
             MediaFormat format = MediaFormat.createVideoFormat(mMimeType, mWidth, mHeight);
-            MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-            String codec = mcl.findEncoderForFormat(format);
-            if (codec == null) {
-                // Don't fail CTS if they don't have an AVC codec (not here, anyway).
-                Log.e(TAG, "Unable to find an appropriate codec for " + format);
-                return;
-            }
-            if (VERBOSE) Log.d(TAG, "found codec: " + codec);
-
-            String codec_decoder = mcl.findDecoderForFormat(format);
-            if (codec_decoder == null) {
-                Log.e(TAG, "Unable to find an appropriate codec for " + format);
-                return;
-            }
 
             // Create a MediaCodec for the desired codec, then configure it as an encoder with
             // our desired properties.
-            encoder = MediaCodec.createByCodecName(codec);
+            encoder = MediaCodec.createByCodecName(mEncoderName);
 
             int colorFormat = selectColorFormat(encoder.getCodecInfo(), mMimeType);
             if (VERBOSE) Log.d(TAG, "found colorFormat: " + colorFormat);
@@ -455,7 +310,7 @@
 
             // Create a MediaCodec for the decoder, just based on the MIME type.  The various
             // format details will be passed through the csd-0 meta-data later on.
-            decoder = MediaCodec.createByCodecName(codec_decoder);
+            decoder = MediaCodec.createByCodecName(mDecoderName);
             if (VERBOSE) Log.d(TAG, "got decoder: " + decoder.getName());
 
             doEncodeDecodeVideoFromBuffer(encoder, colorFormat, decoder, toSurface);
@@ -492,14 +347,6 @@
             // We avoid the device-specific limitations on width and height by using values that
             // are multiples of 16, which all tested devices seem to be able to handle.
             MediaFormat format = MediaFormat.createVideoFormat(mMimeType, mWidth, mHeight);
-            MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-            String codec = mcl.findEncoderForFormat(format);
-            if (codec == null) {
-                // Don't fail CTS if they don't have an AVC codec (not here, anyway).
-                Log.e(TAG, "Unable to find an appropriate codec for " + format);
-                return;
-            }
-            if (VERBOSE) Log.d(TAG, "found codec: " + codec);
 
             int colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
 
@@ -520,14 +367,7 @@
             // Create the output surface.
             outputSurface = new OutputSurface(mWidth, mHeight);
 
-            // Create a MediaCodec for the decoder, just based on the MIME type.  The various
-            // format details will be passed through the csd-0 meta-data later on.
-            String codec_decoder = mcl.findDecoderForFormat(format);
-            if (codec_decoder == null) {
-                Log.e(TAG, "Unable to find an appropriate codec for " + format);
-                return;
-            }
-            decoder = MediaCodec.createByCodecName(codec_decoder);
+            decoder = MediaCodec.createByCodecName(mDecoderName);
             if (VERBOSE) Log.d(TAG, "got decoder: " + decoder.getName());
             decoder.configure(format, outputSurface.getSurface(), null, 0);
             decoder.start();
@@ -535,9 +375,9 @@
             // Create a MediaCodec for the desired codec, then configure it as an encoder with
             // our desired properties.  Request a Surface to use for input.
             if (useNdk) {
-                encoder = new NdkMediaCodec(codec);
+                encoder = new NdkMediaCodec(mEncoderName);
             }else {
-                encoder = new SdkMediaCodec(MediaCodec.createByCodecName(codec));
+                encoder = new SdkMediaCodec(MediaCodec.createByCodecName(mEncoderName));
             }
             encoder.configure(format, MediaCodec.CONFIGURE_FLAG_ENCODE);
             if (inSurf != null) {
@@ -759,7 +599,7 @@
                         // For codecs that don't have codec config data (such as VP8),
                         // initialize the decoder before trying to decode the first packet.
                         assertTrue((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0 ||
-                                   mMimeType.equals(MIME_TYPE_VP8));
+                                   mMimeType.equals(MediaFormat.MIMETYPE_VIDEO_VP8));
                         MediaFormat format =
                                 MediaFormat.createVideoFormat(mMimeType, mWidth, mHeight);
                         if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0)
@@ -1389,4 +1229,59 @@
     private static long computePresentationTime(int frameIndex) {
         return 132 + frameIndex * 1000000 / FRAME_RATE;
     }
+
+    /**
+     * Tests streaming of video through the encoder and decoder.  Data is encoded from
+     * a series of byte[] buffers and decoded into ByteBuffers.  The output is checked for
+     * validity.
+     */
+    @Test
+    public void testEncodeDecodeVideoFromBufferToBuffer() throws Exception {
+        encodeDecodeVideoFromBuffer(false);
+    }
+
+    /**
+     * Tests streaming of video through the encoder and decoder.  Data is encoded from
+     * a series of byte[] buffers and decoded into Surfaces.  The output is checked for
+     * validity.
+     * <p>
+     * Because of the way SurfaceTexture.OnFrameAvailableListener works, we need to run this
+     * test on a thread that doesn't have a Looper configured.  If we don't, the test will
+     * pass, but we won't actually test the output because we'll never receive the "frame
+     * available" notifications".  The CTS test framework seems to be configuring a Looper on
+     * the test thread, so we have to hand control off to a new thread for the duration of
+     * the test.
+     */
+    @Test
+    public void testEncodeDecodeVideoFromBufferToSurface() throws Throwable {
+        BufferToSurfaceWrapper.runTest(this);
+    }
+
+    /**
+     * Tests streaming of AVC through the encoder and decoder.  Data is provided through
+     * a Surface and decoded onto a Surface.  The output is checked for validity.
+     */
+    @Test
+    public void testEncodeDecodeVideoFromSurfaceToSurface() throws Throwable {
+        SurfaceToSurfaceWrapper.runTest(this, false, false);
+    }
+
+    @Test
+    public void testEncodeDecodeVideoFromSurfaceToSurfaceNdk() throws Throwable {
+        SurfaceToSurfaceWrapper.runTest(this, false, USE_NDK);
+    }
+
+    /**
+     * Tests streaming of video through the encoder and decoder.  Data is provided through
+     * a PersistentSurface and decoded onto a Surface.  The output is checked for validity.
+     */
+    @Test
+    public void testEncodeDecodeVideoFromSurfaceToPersistentSurface() throws Throwable {
+        SurfaceToSurfaceWrapper.runTest(this, true, false);
+    }
+
+    @Test
+    public void testEncodeDecodeVideoFromSurfaceToPersistentSurfaceNdk() throws Throwable {
+        SurfaceToSurfaceWrapper.runTest(this, true, USE_NDK);
+    }
 }
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTest.java b/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTest.java
index 2ee1137..1dd7651 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTest.java
@@ -17,7 +17,6 @@
 package android.media.codec.cts;
 
 import android.media.MediaCodec;
-import android.media.MediaCodecInfo;
 import android.media.MediaCodecList;
 import android.media.MediaFormat;
 import android.media.cts.MediaCodecWrapper;
@@ -25,10 +24,23 @@
 import android.platform.test.annotations.AppModeFull;
 import android.util.Log;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.MediaUtils;
+
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
 import java.io.File;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
 
 /**
  * Verification test for video encoder and decoder.
@@ -40,6 +52,7 @@
  */
 @MediaHeavyPresubmitTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
+@RunWith(Parameterized.class)
 public class VideoCodecTest extends VideoCodecTestBase {
 
     private static final String ENCODED_IVF_BASE = "football";
@@ -83,6 +96,56 @@
     // Maximum allowed key frame interval variation from the target value.
     private static final int MAX_KEYFRAME_INTERVAL_VARIATION = 3;
 
+    private static final String CODEC_PREFIX_KEY = "codec-prefix";
+    private static final String mCodecPrefix;
+
+    @Parameterized.Parameter(0)
+    public String mCodecName;
+
+    @Parameterized.Parameter(1)
+    public String mCodecMimeType;
+
+    @Parameterized.Parameter(2)
+    public int mBitRateMode;
+
+    static {
+        android.os.Bundle args = InstrumentationRegistry.getArguments();
+        mCodecPrefix = args.getString(CODEC_PREFIX_KEY);
+    }
+
+    static private List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList) {
+        final List<Object[]> argsList = new ArrayList<>();
+        int argLength = exhaustiveArgsList.get(0).length;
+        for (Object[] arg : exhaustiveArgsList) {
+            String[] encodersForMime = MediaUtils.getEncoderNamesForMime((String) arg[0]);
+            for (String encoder : encodersForMime) {
+                if (mCodecPrefix != null && !encoder.startsWith(mCodecPrefix)) {
+                    continue;
+                }
+                Object[] testArgs = new Object[argLength + 1];
+                testArgs[0] = encoder;
+                System.arraycopy(arg, 0, testArgs, 1, argLength);
+                argsList.add(testArgs);
+            }
+        }
+        return argsList;
+    }
+
+    @Parameterized.Parameters(name = "{index}({0}:{1}:{2})")
+    public static Collection<Object[]> input() {
+        final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+                {VP8_MIME, VIDEO_ControlRateConstant},
+                {VP8_MIME, VIDEO_ControlRateVariable},
+                {VP9_MIME, VIDEO_ControlRateConstant},
+                {VP9_MIME, VIDEO_ControlRateVariable},
+                {AVC_MIME, VIDEO_ControlRateConstant},
+                {AVC_MIME, VIDEO_ControlRateVariable},
+                {HEVC_MIME, VIDEO_ControlRateConstant},
+                {HEVC_MIME, VIDEO_ControlRateVariable},
+        });
+        return prepareParamList(exhaustiveArgsList);
+    }
+
     /**
      * A basic test for Video encoder.
      *
@@ -91,7 +154,8 @@
      * Verifies the average bitrate is within allowed MAX_BITRATE_VARIATIONS[] of
      * the target value.
      */
-    private void internalTestBasic(String codecMimeType, int bitRateMode) throws Exception {
+    private void internalTestBasic(String codecName, String codecMimeType, int bitRateMode)
+            throws Exception {
         int encodeSeconds = 9;
         boolean skipped = true;
 
@@ -101,6 +165,7 @@
             EncoderOutputStreamParameters params = getDefaultEncodingParameters(
                     INPUT_YUV,
                     ENCODED_IVF_BASE,
+                    codecName,
                     codecMimeType,
                     encodeSeconds,
                     WIDTH,
@@ -110,7 +175,8 @@
                     targetBitrate,
                     true);
             ArrayList<ByteBuffer> codecConfigs = new ArrayList<>();
-            ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params, codecConfigs);
+            VideoEncodeOutput videoEncodeOutput = encode(params, codecConfigs);
+            ArrayList<MediaCodec.BufferInfo> bufInfo = videoEncodeOutput.bufferInfo;
             if (bufInfo == null) {
                 continue;
             }
@@ -137,8 +203,7 @@
                     allowedVariance * targetBitrate);
             }
 
-            decode(params.outputIvfFilename, null, codecMimeType, FPS,
-                    params.forceGoogleEncoder, codecConfigs);
+            decode(params.outputIvfFilename, null, codecMimeType, FPS, codecConfigs);
         }
 
         if (skipped) {
@@ -153,7 +218,8 @@
      * Checks the PSNR difference between the encoded and decoded output and reference yuv input
      * does not change much for two different ways of the encoder call.
      */
-    private void internalTestAsyncEncoding(String codecMimeType, int bitRateMode) throws Exception {
+    private void internalTestAsyncEncoding(String codecName, String codecMimeType, int bitRateMode)
+            throws Exception {
         int encodeSeconds = 9;
 
         // First test the encoder running in a looper thread with buffer callbacks enabled.
@@ -161,6 +227,7 @@
         EncoderOutputStreamParameters params = getDefaultEncodingParameters(
                 INPUT_YUV,
                 ENCODED_IVF_BASE,
+                codecName,
                 codecMimeType,
                 encodeSeconds,
                 WIDTH,
@@ -170,14 +237,14 @@
                 BITRATE,
                 syncEncoding);
         ArrayList<ByteBuffer> codecConfigs = new ArrayList<>();
-        ArrayList<MediaCodec.BufferInfo> bufInfos = encodeAsync(params, codecConfigs);
+        VideoEncodeOutput videoEncodeOutput = encodeAsync(params, codecConfigs);
+        ArrayList<MediaCodec.BufferInfo> bufInfos = videoEncodeOutput.bufferInfo;
         if (bufInfos == null) {
             Log.i(TAG, "SKIPPING testAsyncEncoding(): no suitable encoder found");
             return;
         }
         computeEncodingStatistics(bufInfos);
-        decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS,
-                params.forceGoogleEncoder, codecConfigs);
+        decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, codecConfigs);
         VideoDecodingStatistics statisticsAsync = computeDecodingStatistics(
                 params.inputYuvFilename, "football_qvga.yuv", OUTPUT_YUV,
                 params.frameWidth, params.frameHeight);
@@ -188,6 +255,7 @@
         params = getDefaultEncodingParameters(
                 INPUT_YUV,
                 ENCODED_IVF_BASE,
+                codecName,
                 codecMimeType,
                 encodeSeconds,
                 WIDTH,
@@ -197,14 +265,14 @@
                 BITRATE,
                 syncEncoding);
         codecConfigs.clear();
-        bufInfos = encode(params, codecConfigs);
+        videoEncodeOutput = encode(params, codecConfigs);
+        bufInfos = videoEncodeOutput.bufferInfo;
         if (bufInfos == null) {
             Log.i(TAG, "SKIPPING testAsyncEncoding(): no suitable encoder found");
             return;
         }
         computeEncodingStatistics(bufInfos);
-        decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS,
-                params.forceGoogleEncoder, codecConfigs);
+        decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, codecConfigs);
         VideoDecodingStatistics statisticsSync = computeDecodingStatistics(
                 params.inputYuvFilename, "football_qvga.yuv", OUTPUT_YUV,
                 params.frameWidth, params.frameHeight);
@@ -228,13 +296,14 @@
      * Encodes 9 seconds of raw stream and requests a sync frame every second (30 frames).
      * The test does not verify the output stream.
      */
-    private void internalTestSyncFrame(
-            String codecMimeType, int bitRateMode, boolean useNdk) throws Exception {
+    private void internalTestSyncFrame(String codecName, String codecMimeType, int bitRateMode,
+            boolean useNdk) throws Exception {
         int encodeSeconds = 9;
 
         EncoderOutputStreamParameters params = getDefaultEncodingParameters(
                 INPUT_YUV,
                 ENCODED_IVF_BASE,
+                codecName,
                 codecMimeType,
                 encodeSeconds,
                 WIDTH,
@@ -246,7 +315,8 @@
         params.syncFrameInterval = encodeSeconds * FPS;
         params.syncForceFrameInterval = FPS;
         params.useNdk = useNdk;
-        ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
+        VideoEncodeOutput videoEncodeOutput = encode(params);
+        ArrayList<MediaCodec.BufferInfo> bufInfo = videoEncodeOutput.bufferInfo;
         if (bufInfo == null) {
             Log.i(TAG, "SKIPPING testSyncFrame(): no suitable encoder found");
             return;
@@ -280,14 +350,15 @@
      * Run the the encoder for 12 seconds. Request changes to the
      * bitrate after 6 seconds and ensure the encoder responds.
      */
-    private void internalTestDynamicBitrateChange(
-            String codecMimeType, int bitRateMode, boolean useNdk) throws Exception {
+    private void internalTestDynamicBitrateChange(String codecName, String codecMimeType,
+            int bitRateMode, boolean useNdk) throws Exception {
         int encodeSeconds = 12;    // Encoding sequence duration in seconds.
         int[] bitrateTargetValues = { 400000, 800000 };  // List of bitrates to test.
 
         EncoderOutputStreamParameters params = getDefaultEncodingParameters(
                 INPUT_YUV,
                 ENCODED_IVF_BASE,
+                codecName,
                 codecMimeType,
                 encodeSeconds,
                 WIDTH,
@@ -309,7 +380,8 @@
         }
 
         params.useNdk = useNdk;
-        ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
+        VideoEncodeOutput videoEncodeOutput = encode(params);
+        ArrayList<MediaCodec.BufferInfo> bufInfo = videoEncodeOutput.bufferInfo;
         if (bufInfo == null) {
             Log.i(TAG, "SKIPPING testDynamicBitrateChange(): no suitable encoder found");
             return;
@@ -350,7 +422,8 @@
       * and then run parallel encoding and decoding of the same streams.
       * Compares average bitrate and PSNR for sequential and parallel runs.
       */
-     private void internalTestParallelEncodingAndDecoding(String codecMimeType) throws Exception {
+     private void internalTestParallelEncodingAndDecoding(String codecName, String codecMimeType)
+             throws Exception {
          // check for encoder up front, as by the time we detect lack of
          // encoder support, we may have already started decoding.
          MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
@@ -368,6 +441,7 @@
          final EncoderOutputStreamParameters params = getDefaultEncodingParameters(
                  INPUT_YUV,
                  ENCODED_IVF_BASE,
+                 codecName,
                  codecMimeType,
                  encodeSeconds,
                  WIDTH,
@@ -384,9 +458,11 @@
                  try {
                      ArrayList<MediaCodec.BufferInfo> bufInfo;
                      if (codecConfigs.isEmpty()) {
-                         bufInfo = encode(params, codecConfigs);
+                         VideoEncodeOutput videoEncodeOutput = encode(params, codecConfigs);
+                         bufInfo = videoEncodeOutput.bufferInfo;
                      } else {
-                         bufInfo = encode(params);
+                         VideoEncodeOutput videoEncodeOutput = encode(params);
+                         bufInfo = videoEncodeOutput.bufferInfo;
                      }
                      VideoEncodingStatistics statistics = computeEncodingStatistics(bufInfo);
                      bitrate[0] = statistics.mAverageBitrate;
@@ -399,8 +475,7 @@
          Runnable runDecoder = new Runnable() {
              public void run() {
                  try {
-                     decode(inputIvfFilename, OUTPUT_YUV, codecMimeType, FPS,
-                            params.forceGoogleEncoder, codecConfigs);
+                     decode(inputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, codecConfigs);
                      VideoDecodingStatistics statistics = computeDecodingStatistics(
                             params.inputYuvFilename, "football_qvga.yuv", OUTPUT_YUV,
                             params.frameWidth, params.frameHeight);
@@ -459,7 +534,7 @@
      * Video streams with higher bitrates should have higher PSNRs.
      * Also compares average and minimum PSNR of codec with PSNR values of reference Google codec.
      */
-    private void internalTestEncoderQuality(String codecMimeType, int bitRateMode)
+    private void internalTestEncoderQuality(String codecName, String codecMimeType, int bitRateMode)
             throws Exception {
         int encodeSeconds = 9;      // Encoding sequence duration in seconds for each bitrate.
         double[] psnrPlatformCodecAverage = new double[TEST_BITRATES_SET.length];
@@ -473,6 +548,7 @@
             EncoderOutputStreamParameters params = getDefaultEncodingParameters(
                     INPUT_YUV,
                     ENCODED_IVF_BASE,
+                    codecName,
                     codecMimeType,
                     encodeSeconds,
                     WIDTH,
@@ -490,8 +566,7 @@
             completed[i] = true;
             skipped = false;
 
-            decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS,
-                    params.forceGoogleEncoder, codecConfigs);
+            decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, codecConfigs);
             VideoDecodingStatistics statistics = computeDecodingStatistics(
                     params.inputYuvFilename, "football_qvga.yuv", OUTPUT_YUV,
                     params.frameWidth, params.frameHeight);
@@ -554,203 +629,46 @@
         }
     }
 
-    public void testBasicVP8CBR() throws Exception {
-        internalTestBasic(VP8_MIME, VIDEO_ControlRateConstant);
-    }
-    public void testBasicVP8VBR() throws Exception {
-        internalTestBasic(VP8_MIME, VIDEO_ControlRateVariable);
+    @Test
+    public void testBasic() throws Exception {
+        internalTestBasic(mCodecName, mCodecMimeType, mBitRateMode);
     }
 
-    public void testBasicVP9CBR() throws Exception {
-        internalTestBasic(VP9_MIME, VIDEO_ControlRateConstant);
-    }
-    public void testBasicVP9VBR() throws Exception {
-        internalTestBasic(VP9_MIME, VIDEO_ControlRateVariable);
+    @Test
+    public void testAsyncEncode() throws Exception {
+        internalTestAsyncEncoding(mCodecName, mCodecMimeType, mBitRateMode);
     }
 
-    public void testBasicAVCCBR() throws Exception {
-        internalTestBasic(AVC_MIME, VIDEO_ControlRateConstant);
-    }
-    public void testBasicAVCVBR() throws Exception {
-        internalTestBasic(AVC_MIME, VIDEO_ControlRateVariable);
-    }
-    public void testBasicHEVCCBR() throws Exception {
-        internalTestBasic(HEVC_MIME, VIDEO_ControlRateConstant);
-    }
-    public void testBasicHEVCVBR() throws Exception {
-        internalTestBasic(HEVC_MIME, VIDEO_ControlRateVariable);
-    }
-    public void testAsyncEncodingVP8CBR() throws Exception {
-        internalTestAsyncEncoding(VP8_MIME, VIDEO_ControlRateConstant);
-    }
-    public void testAsyncEncodingVP8VBR() throws Exception {
-        internalTestAsyncEncoding(VP8_MIME, VIDEO_ControlRateVariable);
+    @Test
+    public void testSyncFrame() throws Exception {
+        internalTestSyncFrame(mCodecName, mCodecMimeType, mBitRateMode, false);
     }
 
-    public void testAsyncEncodingVP9CBR() throws Exception {
-        internalTestAsyncEncoding(VP9_MIME, VIDEO_ControlRateConstant);
-    }
-    public void testAsyncEncodingVP9VBR() throws Exception {
-        internalTestAsyncEncoding(VP9_MIME, VIDEO_ControlRateVariable);
+    @Test
+    public void testSyncFrameNdk() throws Exception {
+        internalTestSyncFrame(mCodecName, mCodecMimeType, mBitRateMode, true);
     }
 
-    public void testAsyncEncodingAVCCBR() throws Exception {
-        internalTestAsyncEncoding(AVC_MIME, VIDEO_ControlRateConstant);
-    }
-    public void testAsyncEncodingAVCVBR() throws Exception {
-        internalTestAsyncEncoding(AVC_MIME, VIDEO_ControlRateVariable);
-    }
-    public void testAsyncEncodingHEVCCBR() throws Exception {
-        internalTestAsyncEncoding(HEVC_MIME, VIDEO_ControlRateConstant);
-    }
-    public void testAsyncEncodingHEVCVBR() throws Exception {
-        internalTestAsyncEncoding(HEVC_MIME, VIDEO_ControlRateVariable);
+    @Test
+    public void testDynamicBitrateChange() throws Exception {
+        internalTestDynamicBitrateChange(mCodecName, mCodecMimeType, mBitRateMode, false);
     }
 
-    public void testSyncFrameVP8CBR() throws Exception {
-        internalTestSyncFrame(VP8_MIME, VIDEO_ControlRateConstant, false);
-    }
-    public void testSyncFrameVP8VBR() throws Exception {
-        internalTestSyncFrame(VP8_MIME, VIDEO_ControlRateVariable, false);
+    @Test
+    public void testDynamicBitrateChangeNdk() throws Exception {
+        internalTestDynamicBitrateChange(mCodecName, mCodecMimeType, mBitRateMode, true);
     }
 
-    public void testSyncFrameVP8NdkCBR() throws Exception {
-        internalTestSyncFrame(VP8_MIME, VIDEO_ControlRateConstant, true);
-    }
-    public void testSyncFrameVP8NdkVBR() throws Exception {
-        internalTestSyncFrame(VP8_MIME, VIDEO_ControlRateVariable, true);
+    @Test
+    public void testEncoderQuality() throws Exception {
+        internalTestEncoderQuality(mCodecName, mCodecMimeType, mBitRateMode);
     }
 
-    public void testSyncFrameVP9CBR() throws Exception {
-        internalTestSyncFrame(VP9_MIME, VIDEO_ControlRateConstant, false);
-    }
-    public void testSyncFrameVP9VBR() throws Exception {
-        internalTestSyncFrame(VP9_MIME, VIDEO_ControlRateVariable, false);
-    }
-
-    public void testSyncFrameVP9NdkCBR() throws Exception {
-        internalTestSyncFrame(VP9_MIME, VIDEO_ControlRateConstant, true);
-    }
-    public void testSyncFrameVP9NdkVBR() throws Exception {
-        internalTestSyncFrame(VP9_MIME, VIDEO_ControlRateVariable, true);
-    }
-
-    public void testSyncFrameAVCCBR() throws Exception {
-        internalTestSyncFrame(AVC_MIME, VIDEO_ControlRateConstant, false);
-    }
-    public void testSyncFrameAVCVBR() throws Exception {
-        internalTestSyncFrame(AVC_MIME, VIDEO_ControlRateVariable, false);
-    }
-
-    public void testSyncFrameAVCNdkCBR() throws Exception {
-        internalTestSyncFrame(AVC_MIME, VIDEO_ControlRateConstant, true);
-    }
-    public void testSyncFrameAVCNdkVBR() throws Exception {
-        internalTestSyncFrame(AVC_MIME, VIDEO_ControlRateVariable, true);
-    }
-
-    public void testSyncFrameHEVCCBR() throws Exception {
-        internalTestSyncFrame(HEVC_MIME, VIDEO_ControlRateConstant, false);
-    }
-    public void testSyncFrameHEVCVBR() throws Exception {
-        internalTestSyncFrame(HEVC_MIME, VIDEO_ControlRateVariable, false);
-    }
-
-    public void testSyncFrameHEVCNdkCBR() throws Exception {
-        internalTestSyncFrame(HEVC_MIME, VIDEO_ControlRateConstant, true);
-    }
-    public void testSyncFrameHEVCNdkVBR() throws Exception {
-        internalTestSyncFrame(HEVC_MIME, VIDEO_ControlRateVariable, true);
-    }
-
-    public void testDynamicBitrateChangeVP8CBR() throws Exception {
-        internalTestDynamicBitrateChange(VP8_MIME, VIDEO_ControlRateConstant, false);
-    }
-    public void testDynamicBitrateChangeVP8VBR() throws Exception {
-        internalTestDynamicBitrateChange(VP8_MIME, VIDEO_ControlRateVariable, false);
-    }
-    public void testDynamicBitrateChangeVP8NdkCBR() throws Exception {
-        internalTestDynamicBitrateChange(VP8_MIME, VIDEO_ControlRateConstant, true);
-    }
-    public void testDynamicBitrateChangeVP8NdkVBR() throws Exception {
-        internalTestDynamicBitrateChange(VP8_MIME, VIDEO_ControlRateVariable, true);
-    }
-    public void testDynamicBitrateChangeVP9CBR() throws Exception {
-        internalTestDynamicBitrateChange(VP9_MIME, VIDEO_ControlRateConstant, false);
-    }
-    public void testDynamicBitrateChangeVP9VBR() throws Exception {
-        internalTestDynamicBitrateChange(VP9_MIME, VIDEO_ControlRateVariable, false);
-    }
-    public void testDynamicBitrateChangeVP9NdkCBR() throws Exception {
-        internalTestDynamicBitrateChange(VP9_MIME, VIDEO_ControlRateConstant, true);
-    }
-    public void testDynamicBitrateChangeVP9NdkVBR() throws Exception {
-        internalTestDynamicBitrateChange(VP9_MIME, VIDEO_ControlRateVariable, true);
-    }
-    public void testDynamicBitrateChangeAVCCBR() throws Exception {
-        internalTestDynamicBitrateChange(AVC_MIME, VIDEO_ControlRateConstant, false);
-    }
-    public void testDynamicBitrateChangeAVCVBR() throws Exception {
-        internalTestDynamicBitrateChange(AVC_MIME, VIDEO_ControlRateVariable, false);
-    }
-    public void testDynamicBitrateChangeAVCNdkCBR() throws Exception {
-        internalTestDynamicBitrateChange(AVC_MIME, VIDEO_ControlRateConstant, true);
-    }
-    public void testDynamicBitrateChangeAVCNdkVBR() throws Exception {
-        internalTestDynamicBitrateChange(AVC_MIME, VIDEO_ControlRateVariable, true);
-    }
-    public void testDynamicBitrateChangeHEVCCBR() throws Exception {
-        internalTestDynamicBitrateChange(HEVC_MIME, VIDEO_ControlRateConstant, false);
-    }
-    public void testDynamicBitrateChangeHEVCVBR() throws Exception {
-        internalTestDynamicBitrateChange(HEVC_MIME, VIDEO_ControlRateVariable, false);
-    }
-    public void testDynamicBitrateChangeHEVCNdkCBR() throws Exception {
-        internalTestDynamicBitrateChange(HEVC_MIME, VIDEO_ControlRateConstant, true);
-    }
-    public void testDynamicBitrateChangeHEVCNdkVBR() throws Exception {
-        internalTestDynamicBitrateChange(HEVC_MIME, VIDEO_ControlRateVariable, true);
-    }
-
-    public void testEncoderQualityVP8CBR() throws Exception {
-        internalTestEncoderQuality(VP8_MIME, VIDEO_ControlRateConstant);
-    }
-    public void testEncoderQualityVP8VBR() throws Exception {
-        internalTestEncoderQuality(VP8_MIME, VIDEO_ControlRateVariable);
-    }
-
-    public void testEncoderQualityVP9CBR() throws Exception {
-        internalTestEncoderQuality(VP9_MIME, VIDEO_ControlRateConstant);
-    }
-    public void testEncoderQualityVP9VBR() throws Exception {
-        internalTestEncoderQuality(VP9_MIME, VIDEO_ControlRateVariable);
-    }
-
-    public void testEncoderQualityAVCCBR() throws Exception {
-        internalTestEncoderQuality(AVC_MIME, VIDEO_ControlRateConstant);
-    }
-    public void testEncoderQualityAVCVBR() throws Exception {
-        internalTestEncoderQuality(AVC_MIME, VIDEO_ControlRateVariable);
-    }
-
-    public void testEncoderQualityHEVCCBR() throws Exception {
-        internalTestEncoderQuality(HEVC_MIME, VIDEO_ControlRateConstant);
-    }
-    public void testEncoderQualityHEVCVBR() throws Exception {
-        internalTestEncoderQuality(HEVC_MIME, VIDEO_ControlRateVariable);
-    }
-
-    public void testParallelEncodingAndDecodingVP8() throws Exception {
-        internalTestParallelEncodingAndDecoding(VP8_MIME);
-    }
-    public void testParallelEncodingAndDecodingVP9() throws Exception {
-        internalTestParallelEncodingAndDecoding(VP9_MIME);
-    }
-    public void testParallelEncodingAndDecodingAVC() throws Exception {
-        internalTestParallelEncodingAndDecoding(AVC_MIME);
-    }
-    public void testParallelEncodingAndDecodingHEVC() throws Exception {
-        internalTestParallelEncodingAndDecoding(HEVC_MIME);
+    @Test
+    public void testParallelEncodingAndDecoding() throws Exception {
+        Assume.assumeTrue("Parallel Encode Decode test is run only for VBR mode",
+                mBitRateMode == VIDEO_ControlRateVariable);
+        internalTestParallelEncodingAndDecoding(mCodecName, mCodecMimeType);
     }
 }
 
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTestBase.java b/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTestBase.java
index 02754ab..cbe3966 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTestBase.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTestBase.java
@@ -16,13 +16,12 @@
 
 package android.media.codec.cts;
 
-import android.content.Context;
 import android.content.res.Resources;
 import android.media.MediaCodec;
 import android.media.MediaCodec.CodecException;
+import android.media.MediaCodecInfo;
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaCodecList;
-import android.media.MediaCodecInfo;
 import android.media.MediaFormat;
 import android.media.cts.MediaCodecWrapper;
 import android.media.cts.NdkMediaCodec;
@@ -30,12 +29,13 @@
 import android.media.cts.SdkMediaCodec;
 import android.os.Bundle;
 import android.os.Environment;
-import android.os.Looper;
 import android.os.Handler;
+import android.os.Looper;
 import android.platform.test.annotations.AppModeFull;
-import android.test.AndroidTestCase;
 import android.util.Log;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
 import com.android.compatibility.common.util.MediaUtils;
 
 import java.io.File;
@@ -48,6 +48,9 @@
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
 /**
  * Verification test for video encoder and decoder.
  *
@@ -57,7 +60,7 @@
  * calculate PSNR values for various bitrates.
  */
 @AppModeFull(reason = "Instant apps cannot access the SD card")
-public class VideoCodecTestBase extends AndroidTestCase {
+public class VideoCodecTestBase {
 
     protected static final String TAG = "VideoCodecTestBase";
     protected static final String VP8_MIME = MediaFormat.MIMETYPE_VIDEO_VP8;
@@ -91,14 +94,6 @@
     // were calculated and were written to yuv file.
     ArrayList<Integer> mScaledImages = new ArrayList<Integer>();
 
-    private Resources mResources;
-
-    @Override
-    public void setContext(Context context) {
-        super.setContext(context);
-        mResources = mContext.getResources();
-    }
-
     /**
      *  Video codec properties generated by getVideoCodecProperties() function.
      */
@@ -116,19 +111,11 @@
      *
      * Iterates through the list of available codecs and tries to find
      * Video codec, which can support either YUV420 planar or NV12 color formats.
-     * If forceGoogleCodec parameter set to true the function always returns
-     * Google Video codec.
-     * If forceGoogleCodec parameter set to false the functions looks for platform
-     * specific Video codec first. If no platform specific codec exist, falls back to
-     * Google Video codec.
      *
      * @param isEncoder     Flag if encoder is requested.
-     * @param forceGoogleCodec  Forces to use Google codec.
      */
-    private CodecProperties getVideoCodecProperties(
-            boolean isEncoder,
-            MediaFormat format,
-            boolean forceGoogleCodec) throws Exception {
+    private CodecProperties getVideoCodecProperties(boolean isEncoder, MediaFormat format)
+            throws Exception {
         CodecProperties codecProperties = null;
         String mime = format.getString(MediaFormat.KEY_MIME);
 
@@ -140,11 +127,6 @@
                 continue;
             }
             Log.v(TAG, codecInfo.getName());
-            // TODO: remove dependence of Google from the test
-            // Check if this is Google codec - we should ignore it.
-            if (codecInfo.isVendor() && forceGoogleCodec) {
-                continue;
-            }
 
             for (String type : codecInfo.getSupportedTypes()) {
                 if (!type.equalsIgnoreCase(mime)) {
@@ -179,12 +161,43 @@
             }
         }
         if (codecProperties == null) {
-            Log.i(TAG, "no suitable " + (forceGoogleCodec ? "google " : "")
-                    + (isEncoder ? "encoder " : "decoder ") + "found for " + format);
+            Log.i(TAG, "no suitable " + (isEncoder ? "encoder " : "decoder ") + "found for " +
+                    format);
         }
         return codecProperties;
     }
 
+    private CodecProperties getEncoderProperties(String codecName, MediaFormat format)
+            throws Exception {
+        assumeTrue("Media format " + format + " is not supported by " + codecName,
+                MediaUtils.supports(codecName, format));
+        CodecProperties codecProperties = null;
+        MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+        for (MediaCodecInfo codecInfo : mcl.getCodecInfos()) {
+            if (!codecInfo.isEncoder() || !codecName.equals(codecInfo.getName())) {
+                continue;
+            }
+            Log.v(TAG, codecInfo.getName());
+            String mime = format.getString(MediaFormat.KEY_MIME);
+            Log.d(TAG, "Name : " + codecInfo.getName() + " mime: " + mime);
+            CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(mime);
+            for (int supportedColorFormat : mSupportedColorList) {
+                for (int codecColorFormat : capabilities.colorFormats) {
+                    if (codecColorFormat == supportedColorFormat) {
+                        codecProperties = new CodecProperties(codecInfo.getName(),
+                                codecColorFormat);
+                        Log.v(TAG, "Found target codec " + codecProperties.codecName +
+                                ". Color: 0x" + Integer.toHexString(codecColorFormat));
+                        return codecProperties;
+                    }
+                }
+            }
+        }
+        assumeTrue("Codec " + codecName + " doesn't support color YUV 420 color formats",
+                codecProperties != null);
+        return codecProperties;
+    }
+
     /**
      * Parameters for encoded video stream.
      */
@@ -202,8 +215,8 @@
         public String outputIvfFilename;
         // Mime Type of the Encoded content.
         public String codecMimeType;
-        // Force to use Google Video encoder.
-        boolean forceGoogleEncoder;
+        // Component Name.
+        public String codecName;
         // Number of frames to encode.
         int frameCount;
         // Frame rate of input file in frames per second.
@@ -234,6 +247,33 @@
         boolean runInLooperThread;
         // Flag if use NdkMediaCodec
         boolean useNdk;
+        // Encoding Statistics Level
+        // 0: None, 1: Average block QP and picture type of a frame
+        public int encodingStatisticsLevel;
+    }
+
+    /**
+     * Encoding Statistics for a whole sequence
+     */
+    protected class EncodingStatisticsInfo {
+        public float averageSeqQp = 0; // Average qp of a whole sequence,
+                                         // i.e. average of 'per-frame average block QP'
+        public int encodedFrames = 0; // # of encoded frames,
+                                       // i.e. # of average_block_qp is reported
+    }
+
+    /**
+     * Encoding Statistics for a whole sequence
+     */
+    protected class VideoEncodeOutput{
+        public ArrayList<MediaCodec.BufferInfo> bufferInfo;
+        public EncodingStatisticsInfo encStat;
+
+        VideoEncodeOutput(ArrayList<MediaCodec.BufferInfo> bufferInfo,
+            EncodingStatisticsInfo encStat) {
+            bufferInfo = bufferInfo;
+            encStat = encStat;
+        }
     }
 
     private String getCodecSuffix(String codecMimeType) {
@@ -259,6 +299,7 @@
     protected ArrayList<EncoderOutputStreamParameters> getDefaultEncodingParameterList(
             String inputYuvName,
             String outputIvfBaseName,
+            String codecName,
             String codecMimeType,
             int encodeSeconds,
             int[] resolutionScales,
@@ -286,7 +327,7 @@
             String codecSuffix = getCodecSuffix(codecMimeType);
             params.outputIvfFilename = SDCARD_DIR + File.separator +
                     outputIvfBaseName + resolutionScales[i] + "_" + codecSuffix + ".ivf";
-            params.forceGoogleEncoder = false;
+            params.codecName = codecName;
             params.frameCount = encodeSeconds * frameRate;
             params.frameRate = frameRate;
             params.frameWidth = Math.min(frameWidth * resolutionScales[i], 1280);
@@ -312,6 +353,7 @@
     protected EncoderOutputStreamParameters getDefaultEncodingParameters(
             String inputYuvName,
             String outputIvfBaseName,
+            String codecName,
             String codecMimeType,
             int encodeSeconds,
             int frameWidth,
@@ -325,6 +367,7 @@
         return getDefaultEncodingParameterList(
                 inputYuvName,
                 outputIvfBaseName,
+                codecName,
                 codecMimeType,
                 encodeSeconds,
                 scaleValues,
@@ -537,7 +580,6 @@
      * @param inputIvfFilename  The name of the IVF file containing encoded bitsream.
      * @param outputYuvFilename The name of the output YUV file (optional).
      * @param frameRate         Frame rate of input file in frames per second
-     * @param forceGoogleDecoder    Force to use Google Video decoder.
      * @param codecConfigs      Codec config buffers to be added to the format
      */
     protected ArrayList<MediaCodec.BufferInfo> decode(
@@ -545,7 +587,6 @@
             String outputYuvFilename,
             String codecMimeType,
             int frameRate,
-            boolean forceGoogleDecoder,
             ArrayList<ByteBuffer> codecConfigs) throws Exception {
         ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
 
@@ -567,8 +608,7 @@
         // Create decoder.
         MediaFormat format = MediaFormat.createVideoFormat(
                 codecMimeType, ivf.getWidth(), ivf.getHeight());
-        CodecProperties properties = getVideoCodecProperties(
-                false /* encoder */, format, forceGoogleDecoder);
+        CodecProperties properties = getVideoCodecProperties(false /* encoder */, format);
         if (properties == null) {
             ivf.close();
             return null;
@@ -782,19 +822,22 @@
 
         private InputStream mYuvStream;
         private int mInputFrameIndex;
+        private final EncodingStatisticsInfo mEncStatInfo;
 
         MediaEncoderAsyncHelper(
                 EncoderOutputStreamParameters streamParams,
                 CodecProperties properties,
                 ArrayList<MediaCodec.BufferInfo> bufferInfos,
                 IvfWriter ivf,
-                ArrayList<ByteBuffer> codecConfigs)
+                ArrayList<ByteBuffer> codecConfigs,
+                EncodingStatisticsInfo encStatInfo)
                 throws Exception {
             mStreamParams = streamParams;
             mProperties = properties;
             mBufferInfos = bufferInfos;
             mIvf = ivf;
             mCodecConfigs = codecConfigs;
+            mEncStatInfo = encStatInfo;
 
             int srcFrameSize = streamParams.frameWidth * streamParams.frameHeight * 3 / 2;
             mSrcFrame = new byte[srcFrameSize];
@@ -871,6 +914,11 @@
             }
             return false;
         }
+
+        public void saveAvgQp(int avg_qp) {
+            mEncStatInfo.averageSeqQp += (float) avg_qp;
+            ++mEncStatInfo.encodedFrames;  // Note: Duplicated info to  mOutputFrameIndex
+        }
     }
 
     /**
@@ -999,6 +1047,13 @@
                 out.flags = info.flags;
                 out.outputGenerated = true;
 
+                MediaFormat format = codec.getOutputFormat(index);
+                if (format.containsKey(MediaFormat.KEY_VIDEO_QP_AVERAGE)) {
+                    int avgQp = format.getInteger(MediaFormat.KEY_VIDEO_QP_AVERAGE);
+                    // Copy per-frame avgQp to sequence level buffer
+                    mHelper.saveAvgQp(avgQp);
+                }
+
                 if (mHelper.saveOutputFrame(out)) {
                     // output EOS
                     signalCompletion();
@@ -1334,7 +1389,7 @@
     /**
      * @see #encode(EncoderOutputStreamParameters, ArrayList<ByteBuffer>)
      */
-    protected ArrayList<MediaCodec.BufferInfo> encode(
+    protected VideoEncodeOutput encode(
             EncoderOutputStreamParameters streamParams) throws Exception {
         return encode(streamParams, new ArrayList<ByteBuffer>());
     }
@@ -1354,13 +1409,16 @@
      *
      * @param streamParams  Structure with encoder parameters
      * @param codecConfigs  List to be filled with codec config buffers
-     * @return              Returns array of encoded frames information for each frame.
+     * @return              Returns VideoEncodeOutput, which consists of
+     *                      array of encoded frames information for each frame and Encoding
+     *                      Statistics Information.
      */
-    protected ArrayList<MediaCodec.BufferInfo> encode(
+    protected VideoEncodeOutput encode(
             EncoderOutputStreamParameters streamParams,
             ArrayList<ByteBuffer> codecConfigs) throws Exception {
 
         ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
+        EncodingStatisticsInfo encStatInfo = new EncodingStatisticsInfo();
         Log.d(TAG, "Source resolution: "+streamParams.frameWidth + " x " +
                 streamParams.frameHeight);
         int bitrate = streamParams.bitrateSet[0];
@@ -1370,11 +1428,7 @@
                 streamParams.codecMimeType, streamParams.frameWidth,
                 streamParams.frameHeight);
         format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
-        CodecProperties properties = getVideoCodecProperties(
-                true, format, streamParams.forceGoogleEncoder);
-        if (properties == null) {
-            return null;
-        }
+        CodecProperties properties = getEncoderProperties(streamParams.codecName, format);
 
         // Open input/output
         InputStream yuvStream = OpenFileOrResource(
@@ -1395,6 +1449,11 @@
         int syncFrameInterval = (streamParams.syncFrameInterval + streamParams.frameRate/2) /
                 streamParams.frameRate;
         format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
+        if (streamParams.encodingStatisticsLevel !=
+                MediaFormat.VIDEO_ENCODING_STATISTICS_LEVEL_NONE) {
+            format.setInteger(MediaFormat.KEY_VIDEO_ENCODING_STATISTICS_LEVEL,
+                    streamParams.encodingStatisticsLevel);
+        }
 
         // Create encoder
         Log.d(TAG, "Creating encoder " + properties.codecName +
@@ -1520,7 +1579,7 @@
         ivf.close();
         yuvStream.close();
 
-        return bufferInfos;
+        return new VideoEncodeOutput(bufferInfos, encStatInfo);
     }
 
     /**
@@ -1537,9 +1596,11 @@
      *
      * @param streamParams  Structure with encoder parameters
      * @param codecConfigs  List to be filled with codec config buffers
-     * @return              Returns array of encoded frames information for each frame.
+     * @return              Returns VideoEncodeOutput, which consists of
+     *                      array of encoded frames information for each frame and Encoding
+     *                      Statistics Information.
      */
-    protected ArrayList<MediaCodec.BufferInfo> encodeAsync(
+    protected VideoEncodeOutput encodeAsync(
             EncoderOutputStreamParameters streamParams,
             ArrayList<ByteBuffer> codecConfigs) throws Exception {
         if (!streamParams.runInLooperThread) {
@@ -1547,6 +1608,7 @@
         }
 
         ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
+        EncodingStatisticsInfo encStatInfo = new EncodingStatisticsInfo();
         Log.d(TAG, "Source resolution: "+streamParams.frameWidth + " x " +
                 streamParams.frameHeight);
         int bitrate = streamParams.bitrateSet[0];
@@ -1556,11 +1618,7 @@
                 streamParams.codecMimeType, streamParams.frameWidth,
                 streamParams.frameHeight);
         format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
-        CodecProperties properties = getVideoCodecProperties(
-                true, format, streamParams.forceGoogleEncoder);
-        if (properties == null) {
-            return null;
-        }
+        CodecProperties properties = getEncoderProperties(streamParams.codecName, format);
 
         // Open input/output
         IvfWriter ivf = new IvfWriter(
@@ -1579,7 +1637,11 @@
         int syncFrameInterval = (streamParams.syncFrameInterval + streamParams.frameRate/2) /
                 streamParams.frameRate;
         format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
-
+        if (streamParams.encodingStatisticsLevel !=
+                MediaFormat.VIDEO_ENCODING_STATISTICS_LEVEL_NONE) {
+            format.setInteger(MediaFormat.KEY_VIDEO_ENCODING_STATISTICS_LEVEL,
+                    MediaFormat.VIDEO_ENCODING_STATISTICS_LEVEL_1);
+        }
         // Create encoder
         Log.d(TAG, "Creating encoder " + properties.codecName +
                 ". Color format: 0x" + Integer.toHexString(properties.colorFormat)+ " : " +
@@ -1593,7 +1655,7 @@
 
         MediaEncoderAsync codec = new MediaEncoderAsync();
         MediaEncoderAsyncHelper helper = new MediaEncoderAsyncHelper(
-                streamParams, properties, bufferInfos, ivf, codecConfigs);
+                streamParams, properties, bufferInfos, ivf, codecConfigs, encStatInfo);
 
         codec.setAsyncHelper(helper);
         codec.createCodec(0, properties.codecName, format,
@@ -1603,7 +1665,7 @@
         codec.deleteCodec();
         ivf.close();
 
-        return bufferInfos;
+        return new VideoEncodeOutput(bufferInfos, encStatInfo);
     }
 
     /**
@@ -1664,11 +1726,7 @@
                     params.codecMimeType, params.frameWidth,
                     params.frameHeight);
             format[i].setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
-            CodecProperties properties = getVideoCodecProperties(
-                    true, format[i], params.forceGoogleEncoder);
-            if (properties == null) {
-                continue;
-            }
+            CodecProperties properties = getEncoderProperties(params.codecName, format[i]);
 
             // Check if scaled image was created
             int scale = params.frameWidth / srcFrameWidth;
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/VideoEncodingStatisticsTest.java b/tests/tests/media/codec/src/android/media/codec/cts/VideoEncodingStatisticsTest.java
new file mode 100644
index 0000000..10a18dd
--- /dev/null
+++ b/tests/tests/media/codec/src/android/media/codec/cts/VideoEncodingStatisticsTest.java
@@ -0,0 +1,211 @@
+/*
+ * 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.media.codec.cts;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.media.cts.MediaCodecWrapper;
+import android.media.cts.MediaHeavyPresubmitTest;
+import android.platform.test.annotations.AppModeFull;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.MediaUtils;
+
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Verification test for video encoding statistics.
+ *
+ * Check whether a higher bitrate gives a lower average QP reported from encoder
+ *
+ */
+@MediaHeavyPresubmitTest
+@AppModeFull(reason = "TODO: evaluate and port to instant")
+@RunWith(Parameterized.class)
+public class VideoEncodingStatisticsTest extends VideoCodecTestBase {
+
+    private static final String ENCODED_IVF_BASE = "football";
+    private static final String INPUT_YUV = null;
+    private static final String OUTPUT_YUV = SDCARD_DIR + File.separator +
+            ENCODED_IVF_BASE + "_out.yuv";
+
+    // YUV stream properties.
+    private static final int WIDTH = 320;
+    private static final int HEIGHT = 240;
+    private static final int FPS = 30;
+    // Default encoding bitrate.
+    private static final int BITRATE = 400000;
+    // List of bitrates used in quality and basic bitrate tests.
+    private static final int[] TEST_BITRATES_SET = { 300000, 500000, 700000, 900000 };
+
+    private static final String CODEC_PREFIX_KEY = "codec-prefix";
+    private static final String mCodecPrefix;
+
+    @Parameterized.Parameter(0)
+    public String mCodecName;
+
+    @Parameterized.Parameter(1)
+    public String mCodecMimeType;
+
+    @Parameterized.Parameter(2)
+    public int mBitRateMode;
+
+    static {
+        android.os.Bundle args = InstrumentationRegistry.getArguments();
+        mCodecPrefix = args.getString(CODEC_PREFIX_KEY);
+    }
+
+    static private List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList) {
+        final List<Object[]> argsList = new ArrayList<>();
+        int argLength = exhaustiveArgsList.get(0).length;
+        for (Object[] arg : exhaustiveArgsList) {
+            String[] encodersForMime = MediaUtils.getEncoderNamesForMime((String) arg[0]);
+            for (String encoder : encodersForMime) {
+                if (mCodecPrefix != null && !encoder.startsWith(mCodecPrefix)) {
+                    continue;
+                }
+                Object[] testArgs = new Object[argLength + 1];
+                testArgs[0] = encoder;
+                System.arraycopy(arg, 0, testArgs, 1, argLength);
+                argsList.add(testArgs);
+            }
+        }
+        return argsList;
+    }
+
+    @Parameterized.Parameters(name = "{index}({0}:{1}:{2})")
+    public static Collection<Object[]> input() {
+        final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+                {AVC_MIME, VIDEO_ControlRateConstant},
+                {AVC_MIME, VIDEO_ControlRateVariable},
+                {HEVC_MIME, VIDEO_ControlRateConstant},
+                {HEVC_MIME, VIDEO_ControlRateVariable},
+        });
+        return prepareParamList(exhaustiveArgsList);
+    }
+
+    private static CodecCapabilities getCodecCapabilities(
+            String encoderName, String mime, boolean isEncoder) {
+        MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+        for (MediaCodecInfo codecInfo : mcl.getCodecInfos()) {
+            if (isEncoder != codecInfo.isEncoder()) {
+                continue;
+            }
+            if (encoderName.equals(codecInfo.getName())) {
+                return codecInfo.getCapabilitiesForType(mime);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Check whethera a higher bitrate gives a lower average QP
+     *
+     * Video streams with higher bitrate should have lower average qp.
+     */
+    private void testEncStatRateAvgQp(String codecName, String codecMimeType, int bitRateMode)
+            throws Exception {
+        int encodeSeconds = 9;      // Encoding sequence duration in seconds for each bitrate.
+        float[] avgSeqQp = new float[TEST_BITRATES_SET.length];
+        boolean[] completed = new boolean[TEST_BITRATES_SET.length];
+        boolean skipped = true;
+        ArrayList<MediaCodec.BufferInfo> bufInfos;
+
+        CodecCapabilities caps = getCodecCapabilities(codecName, codecMimeType, true);
+        Assume.assumeTrue(codecName + " does not support FEATURE_EncodingStatistics",
+           caps.isFeatureSupported(CodecCapabilities.FEATURE_EncodingStatistics));
+
+        for (int i = 0; i < TEST_BITRATES_SET.length; i++) {
+            EncoderOutputStreamParameters params = getDefaultEncodingParameters(
+                    INPUT_YUV,
+                    ENCODED_IVF_BASE,
+                    codecName,
+                    codecMimeType,
+                    encodeSeconds,
+                    WIDTH,
+                    HEIGHT,
+                    FPS,
+                    bitRateMode,
+                    TEST_BITRATES_SET[i],
+                    true);
+            // Enable encoding statistics at VIDEO_ENCODING_STATISTICS_LEVEL_1
+            params.encodingStatisticsLevel = MediaFormat.VIDEO_ENCODING_STATISTICS_LEVEL_1;
+            ArrayList<ByteBuffer> codecConfigs = new ArrayList<>();
+            VideoEncodeOutput videoEncodeOutput = encode(params, codecConfigs);
+            bufInfos = videoEncodeOutput.bufferInfo;
+            if (bufInfos == null) {
+                // parameters not supported, try other bitrates
+                completed[i] = false;
+                continue;
+            }
+            completed[i] = true;
+            skipped = false;
+            if (videoEncodeOutput.encStat.encodedFrames > 0) {
+                avgSeqQp[i] = (float) videoEncodeOutput.encStat.averageSeqQp
+                                      / videoEncodeOutput.encStat.encodedFrames;
+            }
+        }
+
+        if (skipped) {
+            Log.i(TAG, "SKIPPING testEncodingStatisticsAvgQp(): no bitrates supported");
+            return;
+        }
+
+        // First do a validity check - higher bitrates should results in lower QP.
+        for (int i = 1; i < TEST_BITRATES_SET.length; i++) {
+            if (!completed[i]) {
+                continue;
+            }
+            for (int j = 0; j < i; j++) {
+                if (!completed[j]) {
+                    continue;
+                }
+                double differenceBitrate = TEST_BITRATES_SET[i] - TEST_BITRATES_SET[j];
+                double differenceAvgQp = avgSeqQp[i] - avgSeqQp[j];
+                if (differenceBitrate * differenceAvgQp > 0) {
+                    throw new RuntimeException("Target bitrates: " +
+                            TEST_BITRATES_SET[j] + ", " + TEST_BITRATES_SET[i] +
+                            ". Average QP: "
+                            + avgSeqQp[j] + ", " + avgSeqQp[i]);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testEncodingStatisticsAvgQp() throws Exception {
+       testEncStatRateAvgQp(mCodecName, mCodecMimeType, mBitRateMode);
+   }
+}
+
diff --git a/tests/tests/media/common/Android.bp b/tests/tests/media/common/Android.bp
new file mode 100644
index 0000000..be689bc
--- /dev/null
+++ b/tests/tests/media/common/Android.bp
@@ -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 {
+    default_applicable_licenses: [
+        "Android-Apache-2.0",
+        "cts_tests_tests_media_common_license",
+    ],
+}
+
+// See: http://go/android-license-faq
+license {
+    name: "cts_tests_tests_media_common_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "legacy_unencumbered",
+    ],
+}
+
+java_library {
+    name: "ctsmediautil",
+    srcs: [
+        "src/android/media/cts/CodecImage.java",
+        "src/android/media/cts/YUVImage.java",
+        "src/android/media/cts/CodecUtils.java",
+        "src/android/media/cts/CodecState.java",
+        "src/android/media/cts/MediaCodecTunneledPlayer.java",
+        "src/android/media/cts/MediaTimeProvider.java",
+        "src/android/media/cts/NonBlockingAudioTrack.java",
+    ],
+    static_libs: [
+        "compatibility-device-util-axt",
+        "platform-test-annotations",
+    ],
+    platform_apis: true,
+    min_sdk_version: "29",
+    target_sdk_version: "31",
+}
+
+cc_test_library {
+    name: "libctscodecutils_jni",
+    srcs: [
+        "jni/codec-utils-jni.cpp",
+        "jni/md5_utils.cpp",
+    ],
+    shared_libs: [
+        "libnativehelper_compat_libc++",
+        "liblog",
+    ],
+    header_libs: ["liblog_headers"],
+    // this test suite will run on sdk 29 as part of MTS, make sure it's compatible
+    // (revisit if/when we add features to this library that require newer sdk.
+    sdk_version: "29",
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ],
+    stl: "libc++_static",
+    gtest: false,
+}
+
+cc_test_library {
+    name: "libctsmediacommon_jni",
+    srcs: [
+        "jni/NdkInputSurface-jni.cpp",
+        "jni/NdkMediaCodec-jni.cpp",
+    ],
+    shared_libs: [
+        "libandroid",
+        "libnativehelper_compat_libc++",
+        "liblog",
+        "libmediandk",
+        "libEGL",
+    ],
+    header_libs: ["liblog_headers"],
+    stl: "libc++_static",
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ],
+    gtest: false,
+    // this test suite will run on sdk 29 as part of MTS, make sure it's compatible
+    // (revisit if/when we add features to this library that require newer sdk.
+    sdk_version: "29",
+}
+
+android_library {
+    name: "cts-media-common",
+    srcs: [
+        "src/**/*.java",
+    ],
+    static_libs: [
+        "androidx.heifwriter_heifwriter",
+        "androidx.test.core",
+        "androidx.test.ext.junit",
+        "compatibility-device-util-axt",
+        "junit",
+        "platform-test-annotations",
+    ],
+    platform_apis: true,
+    libs: [
+        "org.apache.http.legacy",
+        "android.test.base",
+        "android.test.runner",
+    ],
+    min_sdk_version: "29",
+    target_sdk_version: "31",
+}
diff --git a/tests/tests/media/common/AndroidManifest.xml b/tests/tests/media/common/AndroidManifest.xml
new file mode 100644
index 0000000..651a22d
--- /dev/null
+++ b/tests/tests/media/common/AndroidManifest.xml
@@ -0,0 +1,62 @@
+<?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.media.cts"
+     android:targetSandboxVersion="2">
+
+    <uses-sdk android:minSdkVersion="29"
+         android:targetSdkVersion="31"/>
+
+    <application android:networkSecurityConfig="@xml/network_security_config"
+        android:largeHeap="true">
+        <uses-library android:name="android.test.runner"/>
+
+        <activity android:name="android.media.cts.MediaProjectionActivity"
+            android:label="MediaProjectionActivity"
+            android:screenOrientation="locked"/>
+        <activity android:name="android.media.cts.AudioManagerStub"
+            android:label="AudioManagerStub"/>
+        <activity android:name="android.media.cts.AudioManagerStubHelper"
+            android:label="AudioManagerStubHelper"/>
+
+        <activity android:name="android.media.cts.MediaStubActivity"
+            android:label="MediaStubActivity"
+            android:screenOrientation="nosensor"
+            android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+            </intent-filter>
+        </activity>
+        <activity android:name="android.media.cts.MediaStubActivity2"
+            android:label="MediaStubActivity2"
+            android:screenOrientation="nosensor"
+            android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+            </intent-filter>
+        </activity>
+
+        <service android:name="android.media.cts.LocalMediaProjectionService"
+            android:foregroundServiceType="mediaProjection"
+            android:enabled="true">
+        </service>
+     </application>
+</manifest>
diff --git a/tests/tests/media/res/layout/composition_layout.xml b/tests/tests/media/common/res/layout/composition_layout.xml
similarity index 100%
rename from tests/tests/media/res/layout/composition_layout.xml
rename to tests/tests/media/common/res/layout/composition_layout.xml
diff --git a/tests/tests/media/res/layout/mediacodecplayer.xml b/tests/tests/media/common/res/layout/mediacodecplayer.xml
similarity index 100%
rename from tests/tests/media/res/layout/mediacodecplayer.xml
rename to tests/tests/media/common/res/layout/mediacodecplayer.xml
diff --git a/tests/tests/media/res/layout/mediaplayer.xml b/tests/tests/media/common/res/layout/mediaplayer.xml
similarity index 100%
rename from tests/tests/media/res/layout/mediaplayer.xml
rename to tests/tests/media/common/res/layout/mediaplayer.xml
diff --git a/tests/tests/media/res/layout/test_runner_activity.xml b/tests/tests/media/common/res/layout/test_runner_activity.xml
similarity index 100%
rename from tests/tests/media/res/layout/test_runner_activity.xml
rename to tests/tests/media/common/res/layout/test_runner_activity.xml
diff --git a/tests/tests/media/res/raw/sine1khzs40dblong.mp3 b/tests/tests/media/common/res/raw/sine1khzs40dblong.mp3
similarity index 100%
copy from tests/tests/media/res/raw/sine1khzs40dblong.mp3
copy to tests/tests/media/common/res/raw/sine1khzs40dblong.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/testmp3.mp3 b/tests/tests/media/common/res/raw/testmp3.mp3
similarity index 100%
copy from tests/tests/media/res/raw/testmp3.mp3
copy to tests/tests/media/common/res/raw/testmp3.mp3
Binary files differ
diff --git a/tests/tests/media/res/xml/network_security_config.xml b/tests/tests/media/common/res/xml/network_security_config.xml
similarity index 100%
rename from tests/tests/media/res/xml/network_security_config.xml
rename to tests/tests/media/common/res/xml/network_security_config.xml
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 79aaada..d6c898b2 100644
--- a/tests/tests/media/common/src/android/media/cts/TestUtils.java
+++ b/tests/tests/media/common/src/android/media/cts/TestUtils.java
@@ -102,7 +102,7 @@
      * {@link #assumeMainlineModuleAtLeast(String, long)} instead.
      */
     @Deprecated
-    static boolean skipTestIfMainlineLessThan(String module, long minVersion) {
+    public static boolean skipTestIfMainlineLessThan(String module, long minVersion) {
         try {
             long actualVersion = getModuleVersion(module);
             if (actualVersion < minVersion) {
diff --git a/tests/tests/media/common/src/android/media/cts/Utils.java b/tests/tests/media/common/src/android/media/cts/Utils.java
index 1524e26..42a813f 100644
--- a/tests/tests/media/common/src/android/media/cts/Utils.java
+++ b/tests/tests/media/common/src/android/media/cts/Utils.java
@@ -132,7 +132,7 @@
                 nm.isNotificationPolicyAccessGranted());
     }
 
-    static boolean compareRemoteUserInfo(RemoteUserInfo a, RemoteUserInfo b) {
+    public static boolean compareRemoteUserInfo(RemoteUserInfo a, RemoteUserInfo b) {
         if (a == null && b == null) {
             return true;
         } else if (a == null || b == null) {
@@ -148,7 +148,7 @@
      * is created once. The playback will be stopped immediately after that.
      * <p>For a media session to receive media button events, an actual playback is needed.
      */
-    static void assertMediaPlaybackStarted(Context context) {
+    public static void assertMediaPlaybackStarted(Context context) {
         final AudioManager am = new AudioManager(context);
         final HandlerThread handlerThread = new HandlerThread(TAG);
         handlerThread.start();
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/AdaptivePlaybackTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/AdaptivePlaybackTest.java
index 01e29b9..1600e9a 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/AdaptivePlaybackTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/AdaptivePlaybackTest.java
@@ -39,27 +39,35 @@
 
 import android.opengl.GLES20;
 
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 import javax.microedition.khronos.opengles.GL10;
 
-import java.lang.System;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
 import java.util.Vector;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.zip.CRC32;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+
 @MediaHeavyPresubmitTest
 @AppModeFull
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
 public class AdaptivePlaybackTest extends MediaTestBase {
 
     private static final boolean sIsAtLeastS = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S);
@@ -82,7 +90,21 @@
         super.tearDown();
     }
 
-    public Iterable<Codec> H264(CodecFactory factory) {
+    private static final String CODEC_PREFIX_KEY = "codec-prefix";
+    private static final String mCodecPrefix;
+
+    @Parameterized.Parameter(0)
+    public String mCodecName;
+
+    @Parameterized.Parameter(1)
+    public CodecList mCodecs;
+
+    static {
+        android.os.Bundle args = InstrumentationRegistry.getArguments();
+        mCodecPrefix = args.getString(CODEC_PREFIX_KEY);
+    }
+
+    public static Iterable<Codec> H264(CodecFactory factory) {
         return factory.createCodecList(
                 MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4",
@@ -90,7 +112,7 @@
                 "bbb_s1_720x480_mp4_h264_mp3_2mbps_30fps_aac_lc_5ch_320kbps_48000hz.mp4");
     }
 
-    public Iterable<Codec> HEVC(CodecFactory factory) {
+    public static Iterable<Codec> HEVC(CodecFactory factory) {
         return factory.createCodecList(
                 MediaFormat.MIMETYPE_VIDEO_HEVC,
                 "bbb_s1_720x480_mp4_hevc_mp3_1600kbps_30fps_aac_he_6ch_240kbps_48000hz.mp4",
@@ -98,21 +120,21 @@
                 "bbb_s1_352x288_mp4_hevc_mp2_600kbps_30fps_aac_he_stereo_96kbps_48000hz.mp4");
     }
 
-    public Iterable<Codec> Mpeg2(CodecFactory factory) {
+    public static Iterable<Codec> Mpeg2(CodecFactory factory) {
         return factory.createCodecList(
                 MediaFormat.MIMETYPE_VIDEO_MPEG2,
                 "video_640x360_mp4_mpeg2_2000kbps_30fps_aac_stereo_128kbps_48000hz.mp4",
                 "video_1280x720_mp4_mpeg2_3000kbps_30fps_aac_stereo_128kbps_48000hz.mp4");
     }
 
-    public Iterable<Codec> H263(CodecFactory factory) {
+    public static Iterable<Codec> H263(CodecFactory factory) {
         return factory.createCodecList(
                 MediaFormat.MIMETYPE_VIDEO_H263,
                 "video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz.3gp",
                 "video_352x288_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz.3gp");
     }
 
-    public Iterable<Codec> Mpeg4(CodecFactory factory) {
+    public static Iterable<Codec> Mpeg4(CodecFactory factory) {
         return factory.createCodecList(
                 MediaFormat.MIMETYPE_VIDEO_MPEG4,
                 "video_1280x720_mp4_mpeg4_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4",
@@ -120,7 +142,7 @@
                 "video_176x144_mp4_mpeg4_300kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
     }
 
-    public Iterable<Codec> VP8(CodecFactory factory) {
+    public static Iterable<Codec> VP8(CodecFactory factory) {
         return factory.createCodecList(
                 MediaFormat.MIMETYPE_VIDEO_VP8,
                 "video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_48000hz.webm",
@@ -128,7 +150,7 @@
                 "bbb_s1_320x180_webm_vp8_800kbps_30fps_opus_5ch_320kbps_48000hz.webm");
     }
 
-    public Iterable<Codec> VP9(CodecFactory factory) {
+    public static Iterable<Codec> VP9(CodecFactory factory) {
         return factory.createCodecList(
                 MediaFormat.MIMETYPE_VIDEO_VP9,
                 "video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_48000hz.webm",
@@ -136,7 +158,7 @@
                 "bbb_s1_320x180_webm_vp9_0p11_600kbps_30fps_vorbis_mono_64kbps_48000hz.webm");
     }
 
-    public Iterable<Codec> AV1(CodecFactory factory) {
+    public static Iterable<Codec> AV1(CodecFactory factory) {
         return factory.createCodecList(
                 MediaFormat.MIMETYPE_VIDEO_AV1,
                 "video_480x360_webm_av1_400kbps_30fps_vorbis_stereo_128kbps_48000hz.webm",
@@ -144,18 +166,18 @@
                 "video_320x180_webm_av1_200kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
     }
 
-    CodecFactory ALL = new CodecFactory();
-    CodecFactory SW  = new SWCodecFactory();
-    CodecFactory HW  = new HWCodecFactory();
+    static CodecFactory ALL = new CodecFactory();
+    static CodecFactory SW  = new SWCodecFactory();
+    static CodecFactory HW  = new HWCodecFactory();
 
-    public Iterable<Codec> H264()  { return H264(ALL);  }
-    public Iterable<Codec> HEVC()  { return HEVC(ALL);  }
-    public Iterable<Codec> VP8()   { return VP8(ALL);   }
-    public Iterable<Codec> VP9()   { return VP9(ALL);   }
-    public Iterable<Codec> AV1()   { return AV1(ALL);   }
-    public Iterable<Codec> Mpeg2() { return Mpeg2(ALL); }
-    public Iterable<Codec> Mpeg4() { return Mpeg4(ALL); }
-    public Iterable<Codec> H263()  { return H263(ALL);  }
+    public static Iterable<Codec> H264()  { return H264(ALL);  }
+    public static Iterable<Codec> HEVC()  { return HEVC(ALL);  }
+    public static Iterable<Codec> VP8()   { return VP8(ALL);   }
+    public static Iterable<Codec> VP9()   { return VP9(ALL);   }
+    public static Iterable<Codec> AV1()   { return AV1(ALL);   }
+    public static Iterable<Codec> Mpeg2() { return Mpeg2(ALL); }
+    public static Iterable<Codec> Mpeg4() { return Mpeg4(ALL); }
+    public static Iterable<Codec> H263()  { return H263(ALL);  }
 
     public Iterable<Codec> AllCodecs() {
         return chain(H264(ALL), HEVC(ALL), VP8(ALL), VP9(ALL), AV1(ALL), Mpeg2(ALL), Mpeg4(ALL), H263(ALL));
@@ -170,23 +192,23 @@
     }
 
     /* tests for adaptive codecs */
-    Test adaptiveEarlyEos     = new EarlyEosTest().adaptive();
-    Test adaptiveEosFlushSeek = new EosFlushSeekTest().adaptive();
-    Test adaptiveSkipAhead    = new AdaptiveSkipTest(true /* forward */);
-    Test adaptiveSkipBack     = new AdaptiveSkipTest(false /* forward */);
+    MediaTest adaptiveEarlyEos     = new EarlyEosTest().adaptive();
+    MediaTest adaptiveEosFlushSeek = new EosFlushSeekTest().adaptive();
+    MediaTest adaptiveSkipAhead    = new AdaptiveSkipTest(true /* forward */);
+    MediaTest adaptiveSkipBack     = new AdaptiveSkipTest(false /* forward */);
 
     /* DRC tests for adaptive codecs */
-    Test adaptiveReconfigDrc      = new ReconfigDrcTest().adaptive();
-    Test adaptiveSmallReconfigDrc = new ReconfigDrcTest().adaptiveSmall();
-    Test adaptiveDrc      = new AdaptiveDrcTest(); /* adaptive */
-    Test adaptiveSmallDrc = new AdaptiveDrcTest().adaptiveSmall();
+    MediaTest adaptiveReconfigDrc      = new ReconfigDrcTest().adaptive();
+    MediaTest adaptiveSmallReconfigDrc = new ReconfigDrcTest().adaptiveSmall();
+    MediaTest adaptiveDrc      = new AdaptiveDrcTest(); /* adaptive */
+    MediaTest adaptiveSmallDrc = new AdaptiveDrcTest().adaptiveSmall();
 
     /* tests for regular codecs */
-    Test earlyEos          = new EarlyEosTest();
-    Test eosFlushSeek      = new EosFlushSeekTest();
-    Test flushConfigureDrc = new ReconfigDrcTest();
+    MediaTest earlyEos          = new EarlyEosTest();
+    MediaTest eosFlushSeek      = new EosFlushSeekTest();
+    MediaTest flushConfigureDrc = new ReconfigDrcTest();
 
-    Test[] allTests = {
+    MediaTest[] allTests = {
         adaptiveEarlyEos,
         adaptiveEosFlushSeek,
         adaptiveSkipAhead,
@@ -201,7 +223,7 @@
     };
 
     /* helpers to run sets of tests */
-    public void runEOS() { ex(AllCodecs(), new Test[] {
+    public void runEOS() { ex(AllCodecs(), new MediaTest[] {
         adaptiveEarlyEos,
         adaptiveEosFlushSeek,
         adaptiveReconfigDrc,
@@ -249,209 +271,108 @@
     public void bytebuffer() { ex(H264(SW), new EarlyEosTest().byteBuffer()); }
     public void onlyTexture() { ex(H264(HW), new EarlyEosTest().texture()); }
 
-    /* Individual tests. */
-    @org.junit.Test
-    public void testH264_adaptiveEarlyEos()  { ex(H264(),  adaptiveEarlyEos); }
-    @org.junit.Test
-    public void testHEVC_adaptiveEarlyEos()  { ex(HEVC(),  adaptiveEarlyEos); }
-    @org.junit.Test
-    public void testVP8_adaptiveEarlyEos()   { ex(VP8(),   adaptiveEarlyEos); }
-    @org.junit.Test
-    public void testVP9_adaptiveEarlyEos()   { ex(VP9(),   adaptiveEarlyEos); }
-    @org.junit.Test
-    public void testAV1_adaptiveEarlyEos()   { ex(AV1(),   adaptiveEarlyEos); }
-    @org.junit.Test
-    public void testMpeg2_adaptiveEarlyEos() { ex(Mpeg2(), adaptiveEarlyEos); }
-    @org.junit.Test
-    public void testMpeg4_adaptiveEarlyEos() { ex(Mpeg4(), adaptiveEarlyEos); }
-    @org.junit.Test
-    public void testH263_adaptiveEarlyEos()  { ex(H263(),  adaptiveEarlyEos); }
-
-    @org.junit.Test
-    public void testH264_adaptiveEosFlushSeek()  { ex(H264(),  adaptiveEosFlushSeek); }
-    @org.junit.Test
-    public void testHEVC_adaptiveEosFlushSeek()  { ex(HEVC(),  adaptiveEosFlushSeek); }
-    @org.junit.Test
-    public void testVP8_adaptiveEosFlushSeek()   { ex(VP8(),   adaptiveEosFlushSeek); }
-    @org.junit.Test
-    public void testVP9_adaptiveEosFlushSeek()   { ex(VP9(),   adaptiveEosFlushSeek); }
-    @org.junit.Test
-    public void testAV1_adaptiveEosFlushSeek()   { ex(AV1(),   adaptiveEosFlushSeek); }
-    @org.junit.Test
-    public void testMpeg2_adaptiveEosFlushSeek() { ex(Mpeg2(), adaptiveEosFlushSeek); }
-    @org.junit.Test
-    public void testMpeg4_adaptiveEosFlushSeek() { ex(Mpeg4(), adaptiveEosFlushSeek); }
-    @org.junit.Test
-    public void testH263_adaptiveEosFlushSeek()  { ex(H263(),  adaptiveEosFlushSeek); }
-
-    @org.junit.Test
-    public void testH264_adaptiveSkipAhead()  { ex(H264(),  adaptiveSkipAhead); }
-    @org.junit.Test
-    public void testHEVC_adaptiveSkipAhead()  { ex(HEVC(),  adaptiveSkipAhead); }
-    @org.junit.Test
-    public void testVP8_adaptiveSkipAhead()   { ex(VP8(),   adaptiveSkipAhead); }
-    @org.junit.Test
-    public void testVP9_adaptiveSkipAhead()   { ex(VP9(),   adaptiveSkipAhead); }
-    @org.junit.Test
-    public void testAV1_adaptiveSkipAhead()   { ex(AV1(),   adaptiveSkipAhead); }
-    @org.junit.Test
-    public void testMpeg2_adaptiveSkipAhead() { ex(Mpeg2(), adaptiveSkipAhead); }
-    @org.junit.Test
-    public void testMpeg4_adaptiveSkipAhead() { ex(Mpeg4(), adaptiveSkipAhead); }
-    @org.junit.Test
-    public void testH263_adaptiveSkipAhead()  { ex(H263(),  adaptiveSkipAhead); }
-
-    @org.junit.Test
-    public void testH264_adaptiveSkipBack()  { ex(H264(),  adaptiveSkipBack); }
-    @org.junit.Test
-    public void testHEVC_adaptiveSkipBack()  { ex(HEVC(),  adaptiveSkipBack); }
-    @org.junit.Test
-    public void testVP8_adaptiveSkipBack()   { ex(VP8(),   adaptiveSkipBack); }
-    @org.junit.Test
-    public void testVP9_adaptiveSkipBack()   { ex(VP9(),   adaptiveSkipBack); }
-    @org.junit.Test
-    public void testAV1_adaptiveSkipBack()   { ex(AV1(),   adaptiveSkipBack); }
-    @org.junit.Test
-    public void testMpeg2_adaptiveSkipBack() { ex(Mpeg2(), adaptiveSkipBack); }
-    @org.junit.Test
-    public void testMpeg4_adaptiveSkipBack() { ex(Mpeg4(), adaptiveSkipBack); }
-    @org.junit.Test
-    public void testH263_adaptiveSkipBack()  { ex(H263(),  adaptiveSkipBack); }
-
-    @org.junit.Test
-    public void testH264_adaptiveReconfigDrc()  { ex(H264(),  adaptiveReconfigDrc); }
-    @org.junit.Test
-    public void testHEVC_adaptiveReconfigDrc()  { ex(HEVC(),  adaptiveReconfigDrc); }
-    @org.junit.Test
-    public void testVP8_adaptiveReconfigDrc()   { ex(VP8(),   adaptiveReconfigDrc); }
-    @org.junit.Test
-    public void testVP9_adaptiveReconfigDrc()   { ex(VP9(),   adaptiveReconfigDrc); }
-    @org.junit.Test
-    public void testAV1_adaptiveReconfigDrc()   { ex(AV1(),   adaptiveReconfigDrc); }
-    @org.junit.Test
-    public void testMpeg2_adaptiveReconfigDrc() { ex(Mpeg2(), adaptiveReconfigDrc); }
-    @org.junit.Test
-    public void testMpeg4_adaptiveReconfigDrc() { ex(Mpeg4(), adaptiveReconfigDrc); }
-    @org.junit.Test
-    public void testH263_adaptiveReconfigDrc()  { ex(H263(),  adaptiveReconfigDrc); }
-
-    @org.junit.Test
-    public void testH264_adaptiveSmallReconfigDrc()  { ex(H264(),  adaptiveSmallReconfigDrc); }
-    @org.junit.Test
-    public void testHEVC_adaptiveSmallReconfigDrc()  { ex(HEVC(),  adaptiveSmallReconfigDrc); }
-    @org.junit.Test
-    public void testVP8_adaptiveSmallReconfigDrc()   { ex(VP8(),   adaptiveSmallReconfigDrc); }
-    @org.junit.Test
-    public void testVP9_adaptiveSmallReconfigDrc()   { ex(VP9(),   adaptiveSmallReconfigDrc); }
-    @org.junit.Test
-    public void testAV1_adaptiveSmallReconfigDrc()   { ex(AV1(),   adaptiveSmallReconfigDrc); }
-    @org.junit.Test
-    public void testMpeg2_adaptiveSmallReconfigDrc() { ex(Mpeg2(), adaptiveSmallReconfigDrc); }
-    @org.junit.Test
-    public void testMpeg4_adaptiveSmallReconfigDrc() { ex(Mpeg4(), adaptiveSmallReconfigDrc); }
-    @org.junit.Test
-    public void testH263_adaptiveSmallReconfigDrc()  { ex(H263(),  adaptiveSmallReconfigDrc); }
-
-    @org.junit.Test
-    public void testH264_adaptiveDrc() { ex(H264(), adaptiveDrc); }
-    @org.junit.Test
-    public void testHEVC_adaptiveDrc() { ex(HEVC(), adaptiveDrc); }
-    @org.junit.Test
-    public void testVP8_adaptiveDrc()  { ex(VP8(),  adaptiveDrc); }
-    @org.junit.Test
-    public void testVP9_adaptiveDrc()  { ex(VP9(),  adaptiveDrc); }
-    @org.junit.Test
-    public void testAV1_adaptiveDrc()  { ex(AV1(),  adaptiveDrc); }
-    @org.junit.Test
-    public void testMpeg2_adaptiveDrc() { ex(Mpeg2(), adaptiveDrc); }
-    @org.junit.Test
-    public void testMpeg4_adaptiveDrc() { ex(Mpeg4(), adaptiveDrc); }
-    @org.junit.Test
-    public void testH263_adaptiveDrc() { ex(H263(), adaptiveDrc); }
-
-    @org.junit.Test
-    public void testH264_adaptiveDrcEarlyEos() { ex(H264(), new AdaptiveDrcEarlyEosTest()); }
-    @org.junit.Test
-    public void testHEVC_adaptiveDrcEarlyEos() { ex(HEVC(), new AdaptiveDrcEarlyEosTest()); }
-    @org.junit.Test
-    public void testVP8_adaptiveDrcEarlyEos()  { ex(VP8(),  new AdaptiveDrcEarlyEosTest()); }
-    @org.junit.Test
-    public void testVP9_adaptiveDrcEarlyEos()  { ex(VP9(),  new AdaptiveDrcEarlyEosTest()); }
-    @org.junit.Test
-    public void testAV1_adaptiveDrcEarlyEos()  { ex(AV1(),  new AdaptiveDrcEarlyEosTest()); }
-    @org.junit.Test
-    public void testMpeg2_adaptiveDrcEarlyEos(){ ex(Mpeg2(), new AdaptiveDrcEarlyEosTest()); }
-
-    @org.junit.Test
-    public void testH264_adaptiveSmallDrc()  { ex(H264(),  adaptiveSmallDrc); }
-    @org.junit.Test
-    public void testHEVC_adaptiveSmallDrc()  { ex(HEVC(),  adaptiveSmallDrc); }
-    @org.junit.Test
-    public void testVP8_adaptiveSmallDrc()   { ex(VP8(),   adaptiveSmallDrc); }
-    @org.junit.Test
-    public void testVP9_adaptiveSmallDrc()   { ex(VP9(),   adaptiveSmallDrc); }
-    @org.junit.Test
-    public void testAV1_adaptiveSmallDrc()   { ex(AV1(),   adaptiveSmallDrc); }
-    @org.junit.Test
-    public void testMpeg2_adaptiveSmallDrc() { ex(Mpeg2(), adaptiveSmallDrc); }
-
-    @org.junit.Test
-    public void testH264_earlyEos()  { ex(H264(),  earlyEos); }
-    @org.junit.Test
-    public void testHEVC_earlyEos()  { ex(HEVC(),  earlyEos); }
-    @org.junit.Test
-    public void testVP8_earlyEos()   { ex(VP8(),   earlyEos); }
-    @org.junit.Test
-    public void testVP9_earlyEos()   { ex(VP9(),   earlyEos); }
-    @org.junit.Test
-    public void testAV1_earlyEos()   { ex(AV1(),   earlyEos); }
-    @org.junit.Test
-    public void testMpeg2_earlyEos() { ex(Mpeg2(), earlyEos); }
-    @org.junit.Test
-    public void testMpeg4_earlyEos() { ex(Mpeg4(), earlyEos); }
-    @org.junit.Test
-    public void testH263_earlyEos()  { ex(H263(),  earlyEos); }
-
-    @org.junit.Test
-    public void testH264_eosFlushSeek()  { ex(H264(),  eosFlushSeek); }
-    @org.junit.Test
-    public void testHEVC_eosFlushSeek()  { ex(HEVC(),  eosFlushSeek); }
-    @org.junit.Test
-    public void testVP8_eosFlushSeek()   { ex(VP8(),   eosFlushSeek); }
-    @org.junit.Test
-    public void testVP9_eosFlushSeek()   { ex(VP9(),   eosFlushSeek); }
-    @org.junit.Test
-    public void testAV1_eosFlushSeek()   { ex(AV1(),   eosFlushSeek); }
-    @org.junit.Test
-    public void testMpeg2_eosFlushSeek() { ex(Mpeg2(), eosFlushSeek); }
-    @org.junit.Test
-    public void testMpeg4_eosFlushSeek() { ex(Mpeg4(), eosFlushSeek); }
-    @org.junit.Test
-    public void testH263_eosFlushSeek()  { ex(H263(),  eosFlushSeek); }
-
-    @org.junit.Test
-    public void testH264_flushConfigureDrc()  { ex(H264(),  flushConfigureDrc); }
-    @org.junit.Test
-    public void testHEVC_flushConfigureDrc()  { ex(HEVC(),  flushConfigureDrc); }
-    @org.junit.Test
-    public void testVP8_flushConfigureDrc()   { ex(VP8(),   flushConfigureDrc); }
-    @org.junit.Test
-    public void testVP9_flushConfigureDrc()   { ex(VP9(),   flushConfigureDrc); }
-    @org.junit.Test
-    public void testAV1_flushConfigureDrc()   { ex(AV1(),   flushConfigureDrc); }
-    @org.junit.Test
-    public void testMpeg2_flushConfigureDrc() { ex(Mpeg2(), flushConfigureDrc); }
-    @org.junit.Test
-    public void testMpeg4_flushConfigureDrc() { ex(Mpeg4(), flushConfigureDrc); }
-    @org.junit.Test
-    public void testH263_flushConfigureDrc()  { ex(H263(),  flushConfigureDrc); }
-
-    /* only use unchecked exceptions to allow brief test methods */
-    private void ex(Iterable<Codec> codecList, Test test) {
-        ex(codecList, new Test[] { test } );
+    static private List<Object[]> prepareParamList(List<Object> exhaustiveArgsList) {
+        final List<Object[]> argsList = new ArrayList<>();
+        for (Object arg : exhaustiveArgsList) {
+            if (arg instanceof CodecList) {
+                CodecList codecList = (CodecList)arg;
+                for (Codec codec : codecList) {
+                    if (mCodecPrefix != null && !codec.name.startsWith(mCodecPrefix)) {
+                        continue;
+                    }
+                    Object[] testArgs = new Object[2];
+                    testArgs[0] = codec.name;
+                    CodecList subList = new CodecList();
+                    subList.add(codec);
+                    testArgs[1] = subList;
+                    argsList.add(testArgs);
+                }
+            }
+        }
+        return argsList;
     }
 
-    private void ex(Iterable<Codec> codecList, Test[] testList) {
+    @Parameterized.Parameters(name = "{index}({0})")
+    public static Collection<Object[]> input() {
+        final List<Object> exhaustiveArgsList = Arrays.asList(new Object[]{
+                H264(), HEVC(), VP8(), VP9(), AV1(), Mpeg2(), Mpeg4(), H263()
+        });
+        return prepareParamList(exhaustiveArgsList);
+    }
+
+    /* individual tests */
+    @Test
+    public void test_adaptiveEarlyEos() {
+        ex(mCodecs, adaptiveEarlyEos);
+    }
+
+    @Test
+    public void test_adaptiveEosFlushSeek() {
+        ex(mCodecs, adaptiveEosFlushSeek);
+    }
+
+    @Test
+    public void test_adaptiveSkipAhead() {
+        ex(mCodecs, adaptiveSkipAhead);
+    }
+
+    @Test
+    public void test_adaptiveSkipBack() {
+        ex(mCodecs, adaptiveSkipBack);
+    }
+
+    @Test
+    public void test_adaptiveReconfigDrc() {
+        ex(mCodecs, adaptiveReconfigDrc);
+    }
+
+    @Test
+    public void test_adaptiveSmallReconfigDrc() {
+        ex(mCodecs, adaptiveSmallReconfigDrc);
+    }
+
+    @Test
+    public void test_adaptiveDrc() {
+        ex(mCodecs, adaptiveDrc);
+    }
+
+    @Test
+    public void test_AdaptiveDrcEarlyEosTest() {
+        String mime = mCodecs.get(0).mediaList[0].getMime();
+        assumeFalse(mime.equals(MediaFormat.MIMETYPE_VIDEO_H263) ||
+                mime.equals(MediaFormat.MIMETYPE_VIDEO_MPEG4));
+        ex(mCodecs, new AdaptiveDrcEarlyEosTest());
+    }
+
+    @Test
+    public void test_adaptiveSmallDrc() {
+        String mime = mCodecs.get(0).mediaList[0].getMime();
+        assumeFalse(mime.equals(MediaFormat.MIMETYPE_VIDEO_H263) ||
+                mime.equals(MediaFormat.MIMETYPE_VIDEO_MPEG4));
+        ex(mCodecs, adaptiveSmallDrc);
+    }
+
+    @Test
+    public void test_earlyEos() {
+        ex(mCodecs, earlyEos);
+    }
+
+    @Test
+    public void test_eosFlushSeek() {
+        ex(mCodecs, eosFlushSeek);
+    }
+
+    @Test
+    public void test_flushConfigureDrc() {
+        ex(mCodecs, flushConfigureDrc);
+    }
+
+    /* only use unchecked exceptions to allow brief test methods */
+    private void ex(Iterable<Codec> codecList, MediaTest test) {
+        ex(codecList, new MediaTest[] { test } );
+    }
+
+    private void ex(Iterable<Codec> codecList, MediaTest[] testList) {
         if (codecList == null) {
             Log.i(TAG, "CodecList was empty. Skipping test.");
             return;
@@ -459,7 +380,7 @@
 
         TestList tests = new TestList();
         for (Codec c : codecList) {
-            for (Test test : testList) {
+            for (MediaTest test : testList) {
                 if (test.isValid(c)) {
                     test.addTests(tests, c);
                 }
@@ -473,7 +394,7 @@
     }
 
     /* need an inner class to have access to the activity */
-    abstract class ActivityTest extends Test {
+    abstract class ActivityTest extends MediaTest {
         TestSurface mNullSurface = new ActivitySurface(null);
         protected TestSurface getSurface() {
             if (mUseSurface) {
@@ -1759,7 +1680,7 @@
     private int mWarnings;
 }
 
-abstract class Test {
+abstract class MediaTest {
     public static final int FORMAT_ADAPTIVE_LARGEST = 1;
     public static final int FORMAT_ADAPTIVE_FIRST = 2;
     public static final int FORMAT_REGULAR = 3;
@@ -1768,29 +1689,29 @@
     protected boolean mUseSurface;
     protected boolean mUseSurfaceTexture;
 
-    public Test() {
+    public MediaTest() {
         mFormatType = FORMAT_REGULAR;
         mUseSurface = true;
         mUseSurfaceTexture = false;
     }
 
-    public Test adaptive() {
+    public MediaTest adaptive() {
         mFormatType = FORMAT_ADAPTIVE_LARGEST;
         return this;
     }
 
-    public Test adaptiveSmall() {
+    public MediaTest adaptiveSmall() {
         mFormatType = FORMAT_ADAPTIVE_FIRST;
         return this;
     }
 
-    public Test byteBuffer() {
+    public MediaTest byteBuffer() {
         mUseSurface = false;
         mUseSurfaceTexture = false;
         return this;
     }
 
-    public Test texture() {
+    public MediaTest texture() {
         mUseSurface = false;
         mUseSurfaceTexture = true;
         return this;
@@ -1852,17 +1773,17 @@
 abstract class Step {
     private static final String TAG = "AdaptiveStep";
 
-    public Step(String title, Test instance, Codec codec, Media media) {
+    public Step(String title, MediaTest instance, Codec codec, Media media) {
         mTest = instance;
         mCodec = codec;
         mMedia = media;
         mDescription = title + " on " + stepSurface().getSurface() + " using " +
             mCodec.name + " and " + stepFormat();
     }
-    public Step(String title, Test instance, Codec codec, int mediaIx) {
+    public Step(String title, MediaTest instance, Codec codec, int mediaIx) {
         this(title, instance, codec, codec.mediaList[mediaIx]);
     }
-    public Step(String title, Test instance, Codec codec) {
+    public Step(String title, MediaTest instance, Codec codec) {
         this(title, instance, codec, 0);
     }
     public Step(String description) {
@@ -1873,7 +1794,7 @@
     public abstract void run() throws Throwable;
 
     private String mDescription;
-    private Test mTest;
+    private MediaTest mTest;
     private Codec mCodec;
     private Media mMedia;
     private int mWarnings;
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/ImageReaderDecoderTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/ImageReaderDecoderTest.java
index f9355f5..61acac7 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/ImageReaderDecoderTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/ImageReaderDecoderTest.java
@@ -78,7 +78,8 @@
  * test. For decoder test, hw and sw decoders are tested,
  * </p>
  */
-@Presubmit
+// TODO(b/210947256) Enable presubmit once this test works on Pixel 4
+//@Presubmit
 @SmallTest
 @RequiresDevice
 @AppModeFull(reason = "Instant apps cannot access the SD card")
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/VideoDecoderPerfTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/VideoDecoderPerfTest.java
index c182ab0..3464193 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/VideoDecoderPerfTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/VideoDecoderPerfTest.java
@@ -30,9 +30,9 @@
 import android.media.cts.Preconditions;
 import android.os.Bundle;
 import android.platform.test.annotations.AppModeFull;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
-import android.text.TextUtils;
 import android.view.Surface;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -47,15 +47,19 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 import org.junit.Test;
 
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.LinkedList;
+import java.util.List;
 
 @MediaHeavyPresubmitTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
 public class VideoDecoderPerfTest extends MediaTestBase {
     private static final String TAG = "VideoDecoderPerfTest";
     private static final String REPORT_LOG_NAME = "CtsMediaDecoderTestCases";
@@ -78,6 +82,14 @@
     private static final boolean OTHER = false;
 
     private static final int MAX_SIZE_SAMPLES_IN_MEMORY_BYTES = 12 << 20;  // 12MB
+
+    private static final String CODEC_PREFIX_KEY = "codec-prefix";
+    private static final String mCodecPrefix;
+
+    private final String mDecoderName;
+    private final String mMediaType;
+    private final String[] mResources;
+
     // each sample contains the buffer and the PTS offset from the frame index
     LinkedList<Pair<ByteBuffer, Double>> mSamplesInMemory = new LinkedList<Pair<ByteBuffer, Double>>();
     private MediaFormat mDecInputFormat;
@@ -87,6 +99,74 @@
     private boolean mSkipRateChecking = false;
     static final String mInpPrefix = WorkDir.getMediaDirString();
 
+    static private List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList) {
+        final List<Object[]> argsList = new ArrayList<>();
+        int argLength = exhaustiveArgsList.get(0).length;
+        for (Object[] arg : exhaustiveArgsList) {
+            String[] decoders = MediaUtils.getDecoderNamesForMime((String) arg[0]);
+            for (String decoder : decoders) {
+                if (mCodecPrefix != null && !decoder.startsWith(mCodecPrefix)) {
+                    continue;
+                }
+                Object[] testArgs = new Object[argLength + 1];
+                // Add codec name as first argument and then copy all other arguments passed
+                testArgs[0] = decoder;
+                System.arraycopy(arg, 0, testArgs, 1, argLength);
+                argsList.add(testArgs);
+            }
+        }
+        return argsList;
+    }
+
+    static {
+        android.os.Bundle args = InstrumentationRegistry.getArguments();
+        mCodecPrefix = args.getString(CODEC_PREFIX_KEY);
+    }
+
+    @Parameterized.Parameters(name = "{index}({0}:{3})")
+    public static Collection<Object[]> input() {
+        final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+                // MediaType, resources, graphics display resolution
+                {AVC, sAvcMedia0320x0240, "qvga"},
+                {AVC, sAvcMedia0720x0480, "sd"},
+                {AVC, sAvcMedia1280x0720, "hd"},
+                {AVC, sAvcMedia1920x1080, "fullhd"},
+
+                {H263, sH263Media0176x0144, "qcif"},
+                {H263, sH263Media0352x0288, "cif"},
+
+                {HEVC, sHevcMedia0352x0288, "cif"},
+                {HEVC, sHevcMedia0640x0360, "vga"},
+                {HEVC, sHevcMedia0720x0480, "sd"},
+                {HEVC, sHevcMedia1280x0720, "hd"},
+                {HEVC, sHevcMedia1920x1080, "fullhd"},
+                {HEVC, sHevcMedia3840x2160, "uhd"},
+
+                {MPEG4, sMpeg4Media0176x0144, "qcif"},
+                {MPEG4, sMpeg4Media0480x0360, "360p"},
+                {MPEG4, sMpeg4Media1280x0720, "hd"},
+
+                {VP8, sVp8Media0320x0180, "qvga"},
+                {VP8, sVp8Media0640x0360, "vga"},
+                {VP8, sVp8Media1280x0720, "hd"},
+                {VP8, sVp8Media1920x1080, "fullhd"},
+
+                {VP9, sVp9Media0320x0180, "qvga"},
+                {VP9, sVp9Media0640x0360, "vga"},
+                {VP9, sVp9Media1280x0720, "hd"},
+                {VP9, sVp9Media1920x1080, "fullhd"},
+                {VP9, sVp9Media3840x2160, "uhd"},
+        });
+        return prepareParamList(exhaustiveArgsList);
+    }
+
+    public VideoDecoderPerfTest(String decodername, String mediaType, String[] resources,
+            @SuppressWarnings("unused") String gfxcode) {
+        mDecoderName = decodername;
+        mMediaType = mediaType;
+        mResources = resources;
+    }
+
     @Before
     @Override
     public void setUp() throws Throwable {
@@ -308,7 +388,7 @@
 
         MediaUtils.Stats stats = new MediaUtils.Stats(frameTimeUsDiff);
         fps = MediaPerfUtils.addPerformanceStatsToLog(log, stats, message);
-        log.submit(getInstrumentation());
+        log.submit(InstrumentationRegistry.getInstrumentation());
         return fps;
     }
 
@@ -321,26 +401,8 @@
         return formats;
     }
 
-    private void count(final String[] resources, int numGoog, int numOther) throws Exception {
+    private void perf(final String decoderName, final String[] resources) throws Exception {
         MediaFormat[] formats = getVideoTrackFormats(resources);
-        MediaUtils.verifyNumCodecs(numGoog,  false /* isEncoder */, true /* isGoog */,  formats);
-        MediaUtils.verifyNumCodecs(numOther, false /* isEncoder */, false /* isGoog */, formats);
-    }
-
-    private void perf(final String[] resources, boolean isGoog, int ix)  throws Exception {
-        MediaFormat[] formats = getVideoTrackFormats(resources);
-        String[] decoders = MediaUtils.getDecoderNames(isGoog, formats);
-        String kind = isGoog ? "Google" : "non-Google";
-        if (decoders.length == 0) {
-            MediaUtils.skipTest("No " + kind + " decoders for " + Arrays.toString(formats));
-            return;
-        } else if (ix >= decoders.length) {
-            Log.i(TAG, "No more " + kind + " decoders for " + Arrays.toString(formats));
-            return;
-        }
-
-        String decoderName = decoders[ix];
-
         // Decode/measure the first supported video resource
         for (int i = 0; i < resources.length; ++i) {
             if (MediaUtils.supports(decoderName, formats[i])) {
@@ -350,51 +412,16 @@
         }
     }
 
-    // Poor man's Parametrized test as this test must still run on CTSv1 runner.
-
-    // The count tests are to ensure this Cts test covers all decoders. Add further
-    // tests and change the count if there can be more decoders.
-
     // AVC tests
 
     private static final String[] sAvcMedia0320x0240 = {
         "bbb_s1_320x240_mp4_h264_mp2_800kbps_30fps_aac_lc_5ch_240kbps_44100hz.mp4",
     };
 
-    @Test
-    public void testAvcCount0320x0240() throws Exception { count(sAvcMedia0320x0240, 2, 4); }
-    @Test
-    public void testAvcGoog0Perf0320x0240() throws Exception { perf(sAvcMedia0320x0240, GOOG, 0); }
-    @Test
-    public void testAvcGoog1Perf0320x0240() throws Exception { perf(sAvcMedia0320x0240, GOOG, 1); }
-    @Test
-    public void testAvcOther0Perf0320x0240() throws Exception { perf(sAvcMedia0320x0240, OTHER, 0); }
-    @Test
-    public void testAvcOther1Perf0320x0240() throws Exception { perf(sAvcMedia0320x0240, OTHER, 1); }
-    @Test
-    public void testAvcOther2Perf0320x0240() throws Exception { perf(sAvcMedia0320x0240, OTHER, 2); }
-    @Test
-    public void testAvcOther3Perf0320x0240() throws Exception { perf(sAvcMedia0320x0240, OTHER, 3); }
-
     private static final String[] sAvcMedia0720x0480 = {
         "bbb_s1_720x480_mp4_h264_mp3_2mbps_30fps_aac_lc_5ch_320kbps_48000hz.mp4",
     };
 
-    @Test
-    public void testAvcCount0720x0480() throws Exception { count(sAvcMedia0720x0480, 2, 4); }
-    @Test
-    public void testAvcGoog0Perf0720x0480() throws Exception { perf(sAvcMedia0720x0480, GOOG, 0); }
-    @Test
-    public void testAvcGoog1Perf0720x0480() throws Exception { perf(sAvcMedia0720x0480, GOOG, 1); }
-    @Test
-    public void testAvcOther0Perf0720x0480() throws Exception { perf(sAvcMedia0720x0480, OTHER, 0); }
-    @Test
-    public void testAvcOther1Perf0720x0480() throws Exception { perf(sAvcMedia0720x0480, OTHER, 1); }
-    @Test
-    public void testAvcOther2Perf0720x0480() throws Exception { perf(sAvcMedia0720x0480, OTHER, 2); }
-    @Test
-    public void testAvcOther3Perf0720x0480() throws Exception { perf(sAvcMedia0720x0480, OTHER, 3); }
-
     // prefer highest effective bitrate, then high profile
     private static final String[] sAvcMedia1280x0720 = {
         "bbb_s4_1280x720_mp4_h264_mp31_8mbps_30fps_aac_he_mono_40kbps_44100hz.mp4",
@@ -402,21 +429,6 @@
         "bbb_s3_1280x720_mp4_h264_mp32_8mbps_60fps_aac_he_v2_6ch_144kbps_44100hz.mp4",
     };
 
-    @Test
-    public void testAvcCount1280x0720() throws Exception { count(sAvcMedia1280x0720, 2, 4); }
-    @Test
-    public void testAvcGoog0Perf1280x0720() throws Exception { perf(sAvcMedia1280x0720, GOOG, 0); }
-    @Test
-    public void testAvcGoog1Perf1280x0720() throws Exception { perf(sAvcMedia1280x0720, GOOG, 1); }
-    @Test
-    public void testAvcOther0Perf1280x0720() throws Exception { perf(sAvcMedia1280x0720, OTHER, 0); }
-    @Test
-    public void testAvcOther1Perf1280x0720() throws Exception { perf(sAvcMedia1280x0720, OTHER, 1); }
-    @Test
-    public void testAvcOther2Perf1280x0720() throws Exception { perf(sAvcMedia1280x0720, OTHER, 2); }
-    @Test
-    public void testAvcOther3Perf1280x0720() throws Exception { perf(sAvcMedia1280x0720, OTHER, 3); }
-
     // prefer highest effective bitrate, then high profile
     private static final String[] sAvcMedia1920x1080 = {
         "bbb_s4_1920x1080_wide_mp4_h264_hp4_20mbps_30fps_aac_lc_6ch_384kbps_44100hz.mp4",
@@ -425,53 +437,16 @@
         "bbb_s2_1920x1080_mp4_h264_mp42_20mbps_60fps_aac_he_v2_5ch_160kbps_48000hz.mp4",
     };
 
-    @Test
-    public void testAvcCount1920x1080() throws Exception { count(sAvcMedia1920x1080, 2, 4); }
-    @Test
-    public void testAvcGoog0Perf1920x1080() throws Exception { perf(sAvcMedia1920x1080, GOOG, 0); }
-    @Test
-    public void testAvcGoog1Perf1920x1080() throws Exception { perf(sAvcMedia1920x1080, GOOG, 1); }
-    @Test
-    public void testAvcOther0Perf1920x1080() throws Exception { perf(sAvcMedia1920x1080, OTHER, 0); }
-    @Test
-    public void testAvcOther1Perf1920x1080() throws Exception { perf(sAvcMedia1920x1080, OTHER, 1); }
-    @Test
-    public void testAvcOther2Perf1920x1080() throws Exception { perf(sAvcMedia1920x1080, OTHER, 2); }
-    @Test
-    public void testAvcOther3Perf1920x1080() throws Exception { perf(sAvcMedia1920x1080, OTHER, 3); }
-
     // H263 tests
 
     private static final String[] sH263Media0176x0144 = {
         "video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz.3gp",
     };
 
-    @Test
-    public void testH263Count0176x0144() throws Exception { count(sH263Media0176x0144, 2, 2); }
-    @Test
-    public void testH263Goog0Perf0176x0144() throws Exception { perf(sH263Media0176x0144, GOOG, 0); }
-    @Test
-    public void testH263Goog1Perf0176x0144() throws Exception { perf(sH263Media0176x0144, GOOG, 1); }
-    @Test
-    public void testH263Other0Perf0176x0144() throws Exception { perf(sH263Media0176x0144, OTHER, 0); }
-    @Test
-    public void testH263Other1Perf0176x0144() throws Exception { perf(sH263Media0176x0144, OTHER, 1); }
-
     private static final String[] sH263Media0352x0288 = {
         "video_352x288_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz.3gp",
     };
 
-    @Test
-    public void testH263Count0352x0288() throws Exception { count(sH263Media0352x0288, 2, 2); }
-    @Test
-    public void testH263Goog0Perf0352x0288() throws Exception { perf(sH263Media0352x0288, GOOG, 0); }
-    @Test
-    public void testH263Goog1Perf0352x0288() throws Exception { perf(sH263Media0352x0288, GOOG, 1); }
-    @Test
-    public void testH263Other0Perf0352x0288() throws Exception { perf(sH263Media0352x0288, OTHER, 0); }
-    @Test
-    public void testH263Other1Perf0352x0288() throws Exception { perf(sH263Media0352x0288, OTHER, 1); }
-
     // No media for H263 704x576
 
     // No media for H263 1408x1152
@@ -482,118 +457,28 @@
         "bbb_s1_352x288_mp4_hevc_mp2_600kbps_30fps_aac_he_stereo_96kbps_48000hz.mp4",
     };
 
-    @Test
-    public void testHevcCount0352x0288() throws Exception { count(sHevcMedia0352x0288, 2, 4); }
-    @Test
-    public void testHevcGoog0Perf0352x0288() throws Exception { perf(sHevcMedia0352x0288, GOOG, 0); }
-    @Test
-    public void testHevcGoog1Perf0352x0288() throws Exception { perf(sHevcMedia0352x0288, GOOG, 1); }
-    @Test
-    public void testHevcOther0Perf0352x0288() throws Exception { perf(sHevcMedia0352x0288, OTHER, 0); }
-    @Test
-    public void testHevcOther1Perf0352x0288() throws Exception { perf(sHevcMedia0352x0288, OTHER, 1); }
-    @Test
-    public void testHevcOther2Perf0352x0288() throws Exception { perf(sHevcMedia0352x0288, OTHER, 2); }
-    @Test
-    public void testHevcOther3Perf0352x0288() throws Exception { perf(sHevcMedia0352x0288, OTHER, 3); }
-
     private static final String[] sHevcMedia0640x0360 = {
         "bbb_s1_640x360_mp4_hevc_mp21_1600kbps_30fps_aac_he_6ch_288kbps_44100hz.mp4",
     };
 
-    @Test
-    public void testHevcCount0640x0360() throws Exception { count(sHevcMedia0640x0360, 2, 4); }
-    @Test
-    public void testHevcGoog0Perf0640x0360() throws Exception { perf(sHevcMedia0640x0360, GOOG, 0); }
-    @Test
-    public void testHevcGoog1Perf0640x0360() throws Exception { perf(sHevcMedia0640x0360, GOOG, 1); }
-    @Test
-    public void testHevcOther0Perf0640x0360() throws Exception { perf(sHevcMedia0640x0360, OTHER, 0); }
-    @Test
-    public void testHevcOther1Perf0640x0360() throws Exception { perf(sHevcMedia0640x0360, OTHER, 1); }
-    @Test
-    public void testHevcOther2Perf0640x0360() throws Exception { perf(sHevcMedia0640x0360, OTHER, 2); }
-    @Test
-    public void testHevcOther3Perf0640x0360() throws Exception { perf(sHevcMedia0640x0360, OTHER, 3); }
-
     private static final String[] sHevcMedia0720x0480 = {
         "bbb_s1_720x480_mp4_hevc_mp3_1600kbps_30fps_aac_he_6ch_240kbps_48000hz.mp4",
     };
 
-    @Test
-    public void testHevcCount0720x0480() throws Exception { count(sHevcMedia0720x0480, 2, 4); }
-    @Test
-    public void testHevcGoog0Perf0720x0480() throws Exception { perf(sHevcMedia0720x0480, GOOG, 0); }
-    @Test
-    public void testHevcGoog1Perf0720x0480() throws Exception { perf(sHevcMedia0720x0480, GOOG, 1); }
-    @Test
-    public void testHevcOther0Perf0720x0480() throws Exception { perf(sHevcMedia0720x0480, OTHER, 0); }
-    @Test
-    public void testHevcOther1Perf0720x0480() throws Exception { perf(sHevcMedia0720x0480, OTHER, 1); }
-    @Test
-    public void testHevcOther2Perf0720x0480() throws Exception { perf(sHevcMedia0720x0480, OTHER, 2); }
-    @Test
-    public void testHevcOther3Perf0720x0480() throws Exception { perf(sHevcMedia0720x0480, OTHER, 3); }
-
     private static final String[] sHevcMedia1280x0720 = {
         "bbb_s4_1280x720_mp4_hevc_mp31_4mbps_30fps_aac_he_stereo_80kbps_32000hz.mp4",
     };
 
-    @Test
-    public void testHevcCount1280x0720() throws Exception { count(sHevcMedia1280x0720, 2, 4); }
-    @Test
-    public void testHevcGoog0Perf1280x0720() throws Exception { perf(sHevcMedia1280x0720, GOOG, 0); }
-    @Test
-    public void testHevcGoog1Perf1280x0720() throws Exception { perf(sHevcMedia1280x0720, GOOG, 1); }
-    @Test
-    public void testHevcOther0Perf1280x0720() throws Exception { perf(sHevcMedia1280x0720, OTHER, 0); }
-    @Test
-    public void testHevcOther1Perf1280x0720() throws Exception { perf(sHevcMedia1280x0720, OTHER, 1); }
-    @Test
-    public void testHevcOther2Perf1280x0720() throws Exception { perf(sHevcMedia1280x0720, OTHER, 2); }
-    @Test
-    public void testHevcOther3Perf1280x0720() throws Exception { perf(sHevcMedia1280x0720, OTHER, 3); }
-
     private static final String[] sHevcMedia1920x1080 = {
         "bbb_s2_1920x1080_mp4_hevc_mp41_10mbps_60fps_aac_lc_6ch_384kbps_22050hz.mp4",
     };
 
-    @Test
-    public void testHevcCount1920x1080() throws Exception { count(sHevcMedia1920x1080, 2, 4); }
-    @Test
-    public void testHevcGoog0Perf1920x1080() throws Exception { perf(sHevcMedia1920x1080, GOOG, 0); }
-    @Test
-    public void testHevcGoog1Perf1920x1080() throws Exception { perf(sHevcMedia1920x1080, GOOG, 1); }
-    @Test
-    public void testHevcOther0Perf1920x1080() throws Exception { perf(sHevcMedia1920x1080, OTHER, 0); }
-    @Test
-    public void testHevcOther1Perf1920x1080() throws Exception { perf(sHevcMedia1920x1080, OTHER, 1); }
-    @Test
-    public void testHevcOther2Perf1920x1080() throws Exception { perf(sHevcMedia1920x1080, OTHER, 2); }
-    @Test
-    public void testHevcOther3Perf1920x1080() throws Exception { perf(sHevcMedia1920x1080, OTHER, 3); }
-
     // prefer highest effective bitrate
     private static final String[] sHevcMedia3840x2160 = {
         "bbb_s4_3840x2160_mp4_hevc_mp5_20mbps_30fps_aac_lc_6ch_384kbps_24000hz.mp4",
         "bbb_s2_3840x2160_mp4_hevc_mp51_20mbps_60fps_aac_lc_6ch_384kbps_32000hz.mp4",
     };
 
-    @Test
-    public void testHevcCount3840x2160() throws Exception { count(sHevcMedia3840x2160, 2, 4); }
-    @Test
-    public void testHevcGoog0Perf3840x2160() throws Exception { perf(sHevcMedia3840x2160, GOOG, 0); }
-    @Test
-    public void testHevcGoog1Perf3840x2160() throws Exception { perf(sHevcMedia3840x2160, GOOG, 1); }
-    @Test
-    public void testHevcOther0Perf3840x2160() throws Exception { perf(sHevcMedia3840x2160, OTHER, 0); }
-    @Test
-    public void testHevcOther1Perf3840x2160() throws Exception { perf(sHevcMedia3840x2160, OTHER, 1); }
-    @Test
-    public void testHevcOther2Perf3840x2160() throws Exception { perf(sHevcMedia3840x2160, OTHER, 2); }
-    @Test
-    public void testHevcOther3Perf3840x2160() throws Exception { perf(sHevcMedia3840x2160, OTHER, 3); }
-
     // MPEG2 tests
 
     // No media for MPEG2 176x144
@@ -612,205 +497,56 @@
         "video_176x144_mp4_mpeg4_300kbps_25fps_aac_stereo_128kbps_44100hz.mp4",
     };
 
-    @Test
-    public void testMpeg4Count0176x0144() throws Exception { count(sMpeg4Media0176x0144, 2, 4); }
-    @Test
-    public void testMpeg4Goog0Perf0176x0144() throws Exception { perf(sMpeg4Media0176x0144, GOOG, 0); }
-    @Test
-    public void testMpeg4Goog1Perf0176x0144() throws Exception { perf(sMpeg4Media0176x0144, GOOG, 1); }
-    @Test
-    public void testMpeg4Other0Perf0176x0144() throws Exception { perf(sMpeg4Media0176x0144, OTHER, 0); }
-    @Test
-    public void testMpeg4Other1Perf0176x0144() throws Exception { perf(sMpeg4Media0176x0144, OTHER, 1); }
-    @Test
-    public void testMpeg4Other2Perf0176x0144() throws Exception { perf(sMpeg4Media0176x0144, OTHER, 2); }
-    @Test
-    public void testMpeg4Other3Perf0176x0144() throws Exception { perf(sMpeg4Media0176x0144, OTHER, 3); }
-
     private static final String[] sMpeg4Media0480x0360 = {
         "video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz.mp4",
     };
 
-    @Test
-    public void testMpeg4Count0480x0360() throws Exception { count(sMpeg4Media0480x0360, 2, 4); }
-    @Test
-    public void testMpeg4Goog0Perf0480x0360() throws Exception { perf(sMpeg4Media0480x0360, GOOG, 0); }
-    @Test
-    public void testMpeg4Goog1Perf0480x0360() throws Exception { perf(sMpeg4Media0480x0360, GOOG, 1); }
-    @Test
-    public void testMpeg4Other0Perf0480x0360() throws Exception { perf(sMpeg4Media0480x0360, OTHER, 0); }
-    @Test
-    public void testMpeg4Other1Perf0480x0360() throws Exception { perf(sMpeg4Media0480x0360, OTHER, 1); }
-    @Test
-    public void testMpeg4Other2Perf0480x0360() throws Exception { perf(sMpeg4Media0480x0360, OTHER, 2); }
-    @Test
-    public void testMpeg4Other3Perf0480x0360() throws Exception { perf(sMpeg4Media0480x0360, OTHER, 3); }
-
-   // No media for MPEG4 640x480
+    // No media for MPEG4 640x480
 
     private static final String[] sMpeg4Media1280x0720 = {
         "video_1280x720_mp4_mpeg4_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4",
     };
 
-    @Test
-    public void testMpeg4Count1280x0720() throws Exception { count(sMpeg4Media1280x0720, 2, 4); }
-    @Test
-    public void testMpeg4Goog0Perf1280x0720() throws Exception { perf(sMpeg4Media1280x0720, GOOG, 0); }
-    @Test
-    public void testMpeg4Goog1Perf1280x0720() throws Exception { perf(sMpeg4Media1280x0720, GOOG, 1); }
-    @Test
-    public void testMpeg4Other0Perf1280x0720() throws Exception { perf(sMpeg4Media1280x0720, OTHER, 0); }
-    @Test
-    public void testMpeg4Other1Perf1280x0720() throws Exception { perf(sMpeg4Media1280x0720, OTHER, 1); }
-    @Test
-    public void testMpeg4Other2Perf1280x0720() throws Exception { perf(sMpeg4Media1280x0720, OTHER, 2); }
-    @Test
-    public void testMpeg4Other3Perf1280x0720() throws Exception { perf(sMpeg4Media1280x0720, OTHER, 3); }
-
     // VP8 tests
 
     private static final String[] sVp8Media0320x0180 = {
         "bbb_s1_320x180_webm_vp8_800kbps_30fps_opus_5ch_320kbps_48000hz.webm",
     };
 
-    @Test
-    public void testVp8Count0320x0180() throws Exception { count(sVp8Media0320x0180, 2, 2); }
-    @Test
-    public void testVp8Goog0Perf0320x0180() throws Exception { perf(sVp8Media0320x0180, GOOG, 0); }
-    @Test
-    public void testVp8Goog1Perf0320x0180() throws Exception { perf(sVp8Media0320x0180, GOOG, 1); }
-    @Test
-    public void testVp8Other0Perf0320x0180() throws Exception { perf(sVp8Media0320x0180, OTHER, 0); }
-    @Test
-    public void testVp8Other1Perf0320x0180() throws Exception { perf(sVp8Media0320x0180, OTHER, 1); }
-
     private static final String[] sVp8Media0640x0360 = {
         "bbb_s1_640x360_webm_vp8_2mbps_30fps_vorbis_5ch_320kbps_48000hz.webm",
     };
 
-    @Test
-    public void testVp8Count0640x0360() throws Exception { count(sVp8Media0640x0360, 2, 2); }
-    @Test
-    public void testVp8Goog0Perf0640x0360() throws Exception { perf(sVp8Media0640x0360, GOOG, 0); }
-    @Test
-    public void testVp8Goog1Perf0640x0360() throws Exception { perf(sVp8Media0640x0360, GOOG, 1); }
-    @Test
-    public void testVp8Other0Perf0640x0360() throws Exception { perf(sVp8Media0640x0360, OTHER, 0); }
-    @Test
-    public void testVp8Other1Perf0640x0360() throws Exception { perf(sVp8Media0640x0360, OTHER, 1); }
-
     // prefer highest effective bitrate
     private static final String[] sVp8Media1280x0720 = {
         "bbb_s4_1280x720_webm_vp8_8mbps_30fps_opus_mono_64kbps_48000hz.webm",
         "bbb_s3_1280x720_webm_vp8_8mbps_60fps_opus_6ch_384kbps_48000hz.webm",
     };
 
-    @Test
-    public void testVp8Count1280x0720() throws Exception { count(sVp8Media1280x0720, 2, 2); }
-    @Test
-    public void testVp8Goog0Perf1280x0720() throws Exception { perf(sVp8Media1280x0720, GOOG, 0); }
-    @Test
-    public void testVp8Goog1Perf1280x0720() throws Exception { perf(sVp8Media1280x0720, GOOG, 1); }
-    @Test
-    public void testVp8Other0Perf1280x0720() throws Exception { perf(sVp8Media1280x0720, OTHER, 0); }
-    @Test
-    public void testVp8Other1Perf1280x0720() throws Exception { perf(sVp8Media1280x0720, OTHER, 1); }
-
     // prefer highest effective bitrate
     private static final String[] sVp8Media1920x1080 = {
         "bbb_s4_1920x1080_wide_webm_vp8_20mbps_30fps_vorbis_6ch_384kbps_44100hz.webm",
         "bbb_s2_1920x1080_webm_vp8_20mbps_60fps_vorbis_6ch_384kbps_48000hz.webm",
     };
 
-    @Test
-    public void testVp8Count1920x1080() throws Exception { count(sVp8Media1920x1080, 2, 2); }
-    @Test
-    public void testVp8Goog0Perf1920x1080() throws Exception { perf(sVp8Media1920x1080, GOOG, 0); }
-    @Test
-    public void testVp8Goog1Perf1920x1080() throws Exception { perf(sVp8Media1920x1080, GOOG, 1); }
-    @Test
-    public void testVp8Other0Perf1920x1080() throws Exception { perf(sVp8Media1920x1080, OTHER, 0); }
-    @Test
-    public void testVp8Other1Perf1920x1080() throws Exception { perf(sVp8Media1920x1080, OTHER, 1); }
-
     // VP9 tests
 
     private static final String[] sVp9Media0320x0180 = {
         "bbb_s1_320x180_webm_vp9_0p11_600kbps_30fps_vorbis_mono_64kbps_48000hz.webm",
     };
 
-    @Test
-    public void testVp9Count0320x0180() throws Exception { count(sVp9Media0320x0180, 2, 4); }
-    @Test
-    public void testVp9Goog0Perf0320x0180() throws Exception { perf(sVp9Media0320x0180, GOOG, 0); }
-    @Test
-    public void testVp9Goog1Perf0320x0180() throws Exception { perf(sVp9Media0320x0180, GOOG, 1); }
-    @Test
-    public void testVp9Other0Perf0320x0180() throws Exception { perf(sVp9Media0320x0180, OTHER, 0); }
-    @Test
-    public void testVp9Other1Perf0320x0180() throws Exception { perf(sVp9Media0320x0180, OTHER, 1); }
-    @Test
-    public void testVp9Other2Perf0320x0180() throws Exception { perf(sVp9Media0320x0180, OTHER, 2); }
-    @Test
-    public void testVp9Other3Perf0320x0180() throws Exception { perf(sVp9Media0320x0180, OTHER, 3); }
-
     private static final String[] sVp9Media0640x0360 = {
         "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm",
     };
 
-    @Test
-    public void testVp9Count0640x0360() throws Exception { count(sVp9Media0640x0360, 2, 4); }
-    @Test
-    public void testVp9Goog0Perf0640x0360() throws Exception { perf(sVp9Media0640x0360, GOOG, 0); }
-    @Test
-    public void testVp9Goog1Perf0640x0360() throws Exception { perf(sVp9Media0640x0360, GOOG, 1); }
-    @Test
-    public void testVp9Other0Perf0640x0360() throws Exception { perf(sVp9Media0640x0360, OTHER, 0); }
-    @Test
-    public void testVp9Other1Perf0640x0360() throws Exception { perf(sVp9Media0640x0360, OTHER, 1); }
-    @Test
-    public void testVp9Other2Perf0640x0360() throws Exception { perf(sVp9Media0640x0360, OTHER, 2); }
-    @Test
-    public void testVp9Other3Perf0640x0360() throws Exception { perf(sVp9Media0640x0360, OTHER, 3); }
-
     private static final String[] sVp9Media1280x0720 = {
         "bbb_s4_1280x720_webm_vp9_0p31_4mbps_30fps_opus_stereo_128kbps_48000hz.webm",
     };
 
-    @Test
-    public void testVp9Count1280x0720() throws Exception { count(sVp9Media1280x0720, 2, 4); }
-    @Test
-    public void testVp9Goog0Perf1280x0720() throws Exception { perf(sVp9Media1280x0720, GOOG, 0); }
-    @Test
-    public void testVp9Goog1Perf1280x0720() throws Exception { perf(sVp9Media1280x0720, GOOG, 1); }
-    @Test
-    public void testVp9Other0Perf1280x0720() throws Exception { perf(sVp9Media1280x0720, OTHER, 0); }
-    @Test
-    public void testVp9Other1Perf1280x0720() throws Exception { perf(sVp9Media1280x0720, OTHER, 1); }
-    @Test
-    public void testVp9Other2Perf1280x0720() throws Exception { perf(sVp9Media1280x0720, OTHER, 2); }
-    @Test
-    public void testVp9Other3Perf1280x0720() throws Exception { perf(sVp9Media1280x0720, OTHER, 3); }
-
     private static final String[] sVp9Media1920x1080 = {
         "bbb_s2_1920x1080_webm_vp9_0p41_10mbps_60fps_vorbis_6ch_384kbps_22050hz.webm",
     };
 
-    @Test
-    public void testVp9Count1920x1080() throws Exception { count(sVp9Media1920x1080, 2, 4); }
-    @Test
-    public void testVp9Goog0Perf1920x1080() throws Exception { perf(sVp9Media1920x1080, GOOG, 0); }
-    @Test
-    public void testVp9Goog1Perf1920x1080() throws Exception { perf(sVp9Media1920x1080, GOOG, 1); }
-    @Test
-    public void testVp9Other0Perf1920x1080() throws Exception { perf(sVp9Media1920x1080, OTHER, 0); }
-    @Test
-    public void testVp9Other1Perf1920x1080() throws Exception { perf(sVp9Media1920x1080, OTHER, 1); }
-    @Test
-    public void testVp9Other2Perf1920x1080() throws Exception { perf(sVp9Media1920x1080, OTHER, 2); }
-    @Test
-    public void testVp9Other3Perf1920x1080() throws Exception { perf(sVp9Media1920x1080, OTHER, 3); }
-
     // prefer highest effective bitrate
     private static final String[] sVp9Media3840x2160 = {
         "bbb_s4_3840x2160_webm_vp9_0p5_20mbps_30fps_vorbis_6ch_384kbps_24000hz.webm",
@@ -818,17 +554,8 @@
     };
 
     @Test
-    public void testVp9Count3840x2160() throws Exception { count(sVp9Media3840x2160, 2, 4); }
-    @Test
-    public void testVp9Goog0Perf3840x2160() throws Exception { perf(sVp9Media3840x2160, GOOG, 0); }
-    @Test
-    public void testVp9Goog1Perf3840x2160() throws Exception { perf(sVp9Media3840x2160, GOOG, 1); }
-    @Test
-    public void testVp9Other0Perf3840x2160() throws Exception { perf(sVp9Media3840x2160, OTHER, 0); }
-    @Test
-    public void testVp9Other1Perf3840x2160() throws Exception { perf(sVp9Media3840x2160, OTHER, 1); }
-    @Test
-    public void testVp9Other2Perf3840x2160() throws Exception { perf(sVp9Media3840x2160, OTHER, 2); }
-    @Test
-    public void testVp9Other3Perf3840x2160() throws Exception { perf(sVp9Media3840x2160, OTHER, 3); }
+    public void testPerf() throws Exception {
+        perf(mDecoderName, mResources);
+    }
 }
+
diff --git a/tests/tests/media/drm/AndroidManifest.xml b/tests/tests/media/drm/AndroidManifest.xml
index 71c2d9d..e7aa4cd 100644
--- a/tests/tests/media/drm/AndroidManifest.xml
+++ b/tests/tests/media/drm/AndroidManifest.xml
@@ -24,6 +24,7 @@
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"/>
+    <uses-permission android:name="android.permission.INTERNET"/>
 
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
 
diff --git a/tests/tests/media/encoder/src/android/media/encoder/cts/EncoderTest.java b/tests/tests/media/encoder/src/android/media/encoder/cts/EncoderTest.java
index fc3a89f..c95ed69 100644
--- a/tests/tests/media/encoder/src/android/media/encoder/cts/EncoderTest.java
+++ b/tests/tests/media/encoder/src/android/media/encoder/cts/EncoderTest.java
@@ -16,7 +16,6 @@
 
 package android.media.encoder.cts;
 
-import android.content.Context;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
 import android.media.MediaFormat;
@@ -24,12 +23,11 @@
 import android.media.cts.Preconditions;
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.RequiresDevice;
-import android.test.AndroidTestCase;
 import android.util.Log;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 
-import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.MediaUtils;
 
 import java.io.File;
@@ -42,7 +40,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.LinkedList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
@@ -50,10 +48,20 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 @SmallTest
 @RequiresDevice
 @AppModeFull(reason = "Instant apps cannot access the SD card")
-public class EncoderTest extends AndroidTestCase {
+@RunWith(Parameterized.class)
+public class EncoderTest {
     private static final String TAG = "EncoderTest";
     private static final boolean VERBOSE = false;
 
@@ -76,17 +84,22 @@
     private static boolean sSaveResults = false;
     static final Map<String, String> mDefaultEncoders = new HashMap<>();
 
-    @Override
-    public void setContext(Context context) {
-        super.setContext(context);
-    }
+    private static final String CODEC_PREFIX_KEY = "codec-prefix";
+    private static String mCodecPrefix;
+
+    private final String mEncoderName;
+    private final String mMime;
+    private final int[] mProfiles;
+    private final int[] mBitrates;
+    private final int[] mSampleRates;
+    private final int[] mChannelCounts;
+    private ArrayList<MediaFormat> mFormats;
 
     static boolean isDefaultCodec(String codecName, String mime)
             throws IOException {
         if (mDefaultEncoders.containsKey(mime)) {
             return mDefaultEncoders.get(mime).equalsIgnoreCase(codecName);
         }
-
         MediaCodec codec = MediaCodec.createEncoderByType(mime);
         boolean isDefault = codec.getName().equalsIgnoreCase(codecName);
         mDefaultEncoders.put(mime, codec.getName());
@@ -94,121 +107,101 @@
         return isDefault;
     }
 
-    public void testAMRNBEncoders() {
-        LinkedList<MediaFormat> formats = new LinkedList<MediaFormat>();
-
-        final int kBitRates[] =
-            { 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200 };
-
-        for (int j = 0; j < kBitRates.length; ++j) {
-            MediaFormat format  = new MediaFormat();
-            format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AMR_NB);
-            format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 8000);
-            format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
-            format.setInteger(MediaFormat.KEY_BIT_RATE, kBitRates[j]);
-            formats.push(format);
-        }
-
-        testEncoderWithFormats(MediaFormat.MIMETYPE_AUDIO_AMR_NB, formats);
-    }
-
-    public void testAMRWBEncoders() {
-        LinkedList<MediaFormat> formats = new LinkedList<MediaFormat>();
-
-        final int kBitRates[] =
-            { 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850 };
-
-        for (int j = 0; j < kBitRates.length; ++j) {
-            MediaFormat format  = new MediaFormat();
-            format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AMR_WB);
-            format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 16000);
-            format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
-            format.setInteger(MediaFormat.KEY_BIT_RATE, kBitRates[j]);
-            formats.push(format);
-        }
-
-        testEncoderWithFormats(MediaFormat.MIMETYPE_AUDIO_AMR_WB, formats);
-    }
-
-    @CddTest(requirement="5.1.3")
-    public void testOpusEncoders() {
-        LinkedList<MediaFormat> formats = new LinkedList<MediaFormat>();
-
-        final int kBitRates[] =
-            { 8000, 12000, 16000, 24000, 48000 };
-
-        for (int j = 0; j < kBitRates.length; ++j) {
-            for (int nChannels = 1; nChannels <= 2; ++nChannels) {
-                MediaFormat format  = new MediaFormat();
-                format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_OPUS);
-                format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 16000);
-                format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, nChannels);
-                format.setInteger(MediaFormat.KEY_BIT_RATE, kBitRates[j]);
-                formats.push(format);
+    static private List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList) {
+        final List<Object[]> argsList = new ArrayList<>();
+        int argLength = exhaustiveArgsList.get(0).length;
+        for (Object[] arg : exhaustiveArgsList) {
+            String[] componentNames = MediaUtils.getEncoderNamesForMime((String)arg[0]);
+            for (String name : componentNames) {
+                if (mCodecPrefix != null && !name.startsWith(mCodecPrefix)) {
+                    continue;
+                }
+                Object[] testArgs = new Object[argLength + 1];
+                testArgs[0] = name;
+                System.arraycopy(arg, 0, testArgs, 1, argLength);
+                argsList.add(testArgs);
             }
         }
-
-        testEncoderWithFormats(MediaFormat.MIMETYPE_AUDIO_OPUS, formats);
+        return argsList;
     }
 
-    public void testAACEncoders() {
-        LinkedList<MediaFormat> formats = new LinkedList<MediaFormat>();
+    static {
+        android.os.Bundle args = InstrumentationRegistry.getArguments();
+        mCodecPrefix = args.getString(CODEC_PREFIX_KEY);
+    }
 
-        final int kAACProfiles[] = {
-            2 /* OMX_AUDIO_AACObjectLC */,
-            5 /* OMX_AUDIO_AACObjectHE */,
-            39 /* OMX_AUDIO_AACObjectELD */
-        };
+    @Parameterized.Parameters(name = "{index}({0}_{1})")
+    public static Collection<Object[]> input() {
+        final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+                // Audio - CodecMime, arrays of profiles, bit-rates, sample rates, channel counts
+                {MediaFormat.MIMETYPE_AUDIO_AAC, new int[]{2, 5, 39}, new int[]{64000, 128000},
+                        new int[]{8000, 11025, 22050, 44100, 48000}, new int[]{1, 2}},
+                {MediaFormat.MIMETYPE_AUDIO_OPUS, new int[]{-1}, new int[]{8000, 12000, 16000,
+                        24000, 48000}, new int[]{16000}, new int[]{1, 2}},
+                {MediaFormat.MIMETYPE_AUDIO_AMR_NB, new int[]{-1}, new int[]{4750, 5150, 5900, 6700
+                        , 7400, 7950, 10200, 12200}, new int[]{8000}, new int[]{1}},
+                {MediaFormat.MIMETYPE_AUDIO_AMR_WB, new int[]{-1}, new int[]{6600, 8850, 12650,
+                        14250, 15850, 18250, 19850, 23050, 23850}, new int[]{16000}, new int[]{1}},
+        });
+        return prepareParamList(exhaustiveArgsList);
+    }
 
-        final int kSampleRates[] = { 8000, 11025, 22050, 44100, 48000 };
-        final int kBitRates[] = { 64000, 128000 };
+    public EncoderTest(String encodername, String mime, int[] profiles, int[] bitrates,
+            int samplerates[], int channelcounts[]) {
+        mEncoderName = encodername;
+        mMime = mime;
+        mProfiles = profiles;
+        mBitrates = bitrates;
+        mSampleRates = samplerates;
+        mChannelCounts = channelcounts;
+    }
 
-        for (int k = 0; k < kAACProfiles.length; ++k) {
-            for (int i = 0; i < kSampleRates.length; ++i) {
-                if (kAACProfiles[k] == 5 && kSampleRates[i] < 22050) {
+    private void setUpFormats() {
+        mFormats = new ArrayList<MediaFormat>();
+        // TODO(b/218887182) Explore parameterizing based on the following loop params as well
+        for (int profile : mProfiles) {
+            for (int rate : mSampleRates) {
+                if (mMime.equals(MediaFormat.MIMETYPE_AUDIO_AAC) && profile == 5 && rate < 22050) {
                     // Is this right? HE does not support sample rates < 22050Hz?
                     continue;
                 }
-                for (int j = 0; j < kBitRates.length; ++j) {
-                    for (int ch = 1; ch <= 2; ++ch) {
-                        MediaFormat format  = new MediaFormat();
-                        format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AAC);
-
-                        format.setInteger(
-                                MediaFormat.KEY_AAC_PROFILE, kAACProfiles[k]);
-
-                        format.setInteger(
-                                MediaFormat.KEY_SAMPLE_RATE, kSampleRates[i]);
-
-                        format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, ch);
-                        format.setInteger(MediaFormat.KEY_BIT_RATE, kBitRates[j]);
-                        formats.push(format);
+                for (int bitrate : mBitrates) {
+                    for (int channels : mChannelCounts) {
+                        MediaFormat format = new MediaFormat();
+                        format.setString(MediaFormat.KEY_MIME, mMime);
+                        format.setInteger(MediaFormat.KEY_SAMPLE_RATE, rate);
+                        format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, channels);
+                        format.setInteger(MediaFormat.KEY_AAC_PROFILE, profile);
+                        format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
+                        mFormats.add(format);
                     }
                 }
             }
         }
-
-        testEncoderWithFormats(MediaFormat.MIMETYPE_AUDIO_AAC, formats);
     }
 
-    private void testEncoderWithFormatsParallel(String mime, List<MediaFormat> formats,
-            List<String> componentNames, int ThreadCount) {
+    @Test
+    public void testEncoders() {
+        setUpFormats();
+        testEncoderWithFormats();
+    }
+
+    private void testEncoderWithFormatsParallel(String mime, ArrayList<MediaFormat> formats,
+            String componentName, int ThreadCount) {
         int testsStarted = 0;
         int totalDurationSeconds = 0;
         ExecutorService pool = Executors.newFixedThreadPool(ThreadCount);
 
-        for (String componentName : componentNames) {
-            for (MediaFormat format : formats) {
-                assertEquals(mime, format.getString(MediaFormat.KEY_MIME));
-                pool.execute(new EncoderRun(componentName, format));
-                int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
-                int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
-                int bytesQueuedPerSecond = 2 * channelCount * sampleRate;
-                int durationSeconds =
-                        (kNumInputBytes + bytesQueuedPerSecond - 1) / bytesQueuedPerSecond;
-                totalDurationSeconds += durationSeconds * kNumEncoderTestsPerRun;
-                testsStarted++;
-            }
+        for (MediaFormat format : formats) {
+            assertEquals(mime, format.getString(MediaFormat.KEY_MIME));
+            pool.execute(new EncoderRun(componentName, format));
+            int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+            int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+            int bytesQueuedPerSecond = 2 * channelCount * sampleRate;
+            int durationSeconds =
+                    (kNumInputBytes + bytesQueuedPerSecond - 1) / bytesQueuedPerSecond;
+            totalDurationSeconds += durationSeconds * kNumEncoderTestsPerRun;
+            testsStarted++;
         }
         try {
             pool.shutdown();
@@ -221,40 +214,28 @@
         }
     }
 
-    private void testEncoderWithFormats(
-            String mime, List<MediaFormat> formatList) {
-        MediaFormat[] formats = formatList.toArray(new MediaFormat[formatList.size()]);
-        String[] componentNames = MediaUtils.getEncoderNames(formats);
-        if (componentNames.length == 0) {
-            MediaUtils.skipTest("no encoders found for " + Arrays.toString(formats));
-            return;
+    private void testEncoderWithFormats() {
+        for (MediaFormat fmt : mFormats) {
+            if (!MediaUtils.supports(mEncoderName, fmt)) {
+                MediaUtils.skipTest("no encoders found for " + fmt.toString());
+                return;
+            }
         }
-
         final int ThreadPoolCount = 3;
-        List<String>[] componentNamesGrouped = new List[ThreadPoolCount];
-        for (int i = 0; i < ThreadPoolCount; i++) {
-            componentNamesGrouped[i] = new ArrayList<>();
+        int instances = ThreadPoolCount;
+        MediaCodec codec = null;
+        try {
+            codec = MediaCodec.createByCodecName(mEncoderName);
+            MediaCodecInfo info = codec.getCodecInfo();
+            MediaCodecInfo.CodecCapabilities cap = info.getCapabilitiesForType(mMime);
+            instances = Math.min(cap.getMaxSupportedInstances(), instances);
+            assertTrue(instances >= 1);
+        } catch (Exception e) {
+            fail("codec '" + mEncoderName + "' failed construction.");
+        } finally {
+            codec.release();
         }
-        for (String componentName : componentNames) {
-            MediaCodec codec = null;
-            try {
-                codec = MediaCodec.createByCodecName(componentName);
-                MediaCodecInfo info = codec.getCodecInfo();
-                MediaCodecInfo.CodecCapabilities cap = info.getCapabilitiesForType(mime);
-                int instances = Math.min(cap.getMaxSupportedInstances(), ThreadPoolCount);
-                assertTrue(instances >= 1 && instances <= ThreadPoolCount);
-                componentNamesGrouped[instances - 1].add(componentName);
-            } catch (Exception e) {
-                fail("codec '" + componentName + "' failed construction.");
-            } finally {
-                codec.release();
-            }
-        }
-        for (int i = 0; i < ThreadPoolCount; i++) {
-            if (componentNamesGrouped[i].size() > 0) {
-                testEncoderWithFormatsParallel(mime, formatList, componentNamesGrouped[i], i + 1);
-            }
-        }
+        testEncoderWithFormatsParallel(mMime, mFormats, mEncoderName, instances);
     }
 
     // See bug 25843966
@@ -526,4 +507,3 @@
         }
     }
 }
-
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 707bde2..d7cfbaa 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
@@ -44,8 +44,6 @@
 import android.media.cts.Preconditions;
 import android.net.Uri;
 import android.platform.test.annotations.AppModeFull;
-import android.platform.test.annotations.Presubmit;
-import android.platform.test.annotations.RequiresDevice;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Range;
@@ -54,30 +52,43 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.MediaUtils;
 
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 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.concurrent.atomic.AtomicReference;
-import java.util.function.Consumer;
-import java.util.function.Function;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 @MediaHeavyPresubmitTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
 public class VideoEncoderTest extends MediaTestBase {
     private static final int MAX_SAMPLE_SIZE = 256 * 1024;
     private static final String TAG = "VideoEncoderTest";
@@ -89,6 +100,11 @@
     private static final String SOURCE_URL =
             mInpPrefix + "video_480x360_mp4_h264_871kbps_30fps.mp4";
 
+    private static final String CODEC_PREFIX_KEY = "codec-prefix";
+    private static final String mCodecPrefix;
+
+    private final Encoder mEncHandle;
+
     private final boolean DEBUG = false;
 
     @Before
@@ -103,6 +119,11 @@
         super.tearDown();
     }
 
+    static {
+        android.os.Bundle args = InstrumentationRegistry.getArguments();
+        mCodecPrefix = args.getString(CODEC_PREFIX_KEY);
+    }
+
     class VideoStorage {
         private LinkedList<Pair<ByteBuffer, BufferInfo>> mStream;
         private MediaFormat mFormat;
@@ -1226,1110 +1247,285 @@
             return success;
         }
     }
-
-    private Encoder[] googH265()  { return goog(MediaFormat.MIMETYPE_VIDEO_HEVC); }
-    private Encoder[] googH264()  { return goog(MediaFormat.MIMETYPE_VIDEO_AVC); }
-    private Encoder[] googH263()  { return goog(MediaFormat.MIMETYPE_VIDEO_H263); }
-    private Encoder[] googMpeg4() { return goog(MediaFormat.MIMETYPE_VIDEO_MPEG4); }
-    private Encoder[] googVP8()   { return goog(MediaFormat.MIMETYPE_VIDEO_VP8); }
-    private Encoder[] googVP9()   { return goog(MediaFormat.MIMETYPE_VIDEO_VP9); }
-
-    private Encoder[] otherH265()  { return other(MediaFormat.MIMETYPE_VIDEO_HEVC); }
-    private Encoder[] otherH264()  { return other(MediaFormat.MIMETYPE_VIDEO_AVC); }
-    private Encoder[] otherH263()  { return other(MediaFormat.MIMETYPE_VIDEO_H263); }
-    private Encoder[] otherMpeg4() { return other(MediaFormat.MIMETYPE_VIDEO_MPEG4); }
-    private Encoder[] otherVP8()   { return other(MediaFormat.MIMETYPE_VIDEO_VP8); }
-    private Encoder[] otherVP9()   { return other(MediaFormat.MIMETYPE_VIDEO_VP9); }
-
-    private Encoder[] goog(String mime) {
-        return encoders(mime, true /* goog */);
-    }
-
-    private Encoder[] other(String mime) {
-        return encoders(mime, false /* goog */);
-    }
-
-    private Encoder[] combineArray(Encoder[] a, Encoder[] b) {
-        Encoder[] all = new Encoder[a.length + b.length];
-        System.arraycopy(a, 0, all, 0, a.length);
-        System.arraycopy(b, 0, all, a.length, b.length);
-        return all;
-    }
-
-    private Encoder[] h264()  {
-        return combineArray(googH264(), otherH264());
-    }
-
-    private Encoder[] vp8()  {
-        return combineArray(googVP8(), otherVP8());
-    }
-
-    private Encoder[] encoders(String mime, boolean goog) {
+    private static CodecCapabilities getCodecCapabities(String encoderName, String mime,
+                                                        boolean isEncoder) {
         MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-        ArrayList<Encoder> result = new ArrayList<Encoder>();
-
-        for (MediaCodecInfo info : mcl.getCodecInfos()) {
-            if (!info.isEncoder() || !info.isVendor() != goog || info.isAlias()) {
+        for (MediaCodecInfo codecInfo : mcl.getCodecInfos()) {
+            if (isEncoder != codecInfo.isEncoder()) {
                 continue;
             }
-            CodecCapabilities caps = null;
-            try {
-                caps = info.getCapabilitiesForType(mime);
-            } catch (IllegalArgumentException e) { // mime is not supported
-                continue;
+            if (encoderName.equals(codecInfo.getName())) {
+                return codecInfo.getCapabilitiesForType(mime);
             }
-            assertNotNull(info.getName() + " capabilties for " + mime + " returned null", caps);
-            result.add(new Encoder(info.getName(), mime, caps));
         }
-        return result.toArray(new Encoder[result.size()]);
+        return null;
+    }
+    private Encoder getEncHandle(String encodername, String mime) {
+        CodecCapabilities caps = getCodecCapabities(encodername, mime, true);
+        assertNotNull(caps);
+        Encoder encoder = new Encoder(encodername, mime, caps);
+        return encoder;
+    }
+
+    static private List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList) {
+        final List<Object[]> argsList = new ArrayList<>();
+        int argLength = exhaustiveArgsList.get(0).length;
+        for (Object[] arg : exhaustiveArgsList) {
+            String[] encodersForMime = MediaUtils.getEncoderNamesForMime((String) arg[0]);
+            for (String encoder : encodersForMime) {
+                if (mCodecPrefix != null && !encoder.startsWith(mCodecPrefix)) {
+                    continue;
+                }
+                Object[] testArgs = new Object[argLength + 1];
+                testArgs[0] = encoder;
+                System.arraycopy(arg, 0, testArgs, 1, argLength);
+                argsList.add(testArgs);
+            }
+        }
+        return argsList;
+    }
+
+    @Parameterized.Parameters(name = "{index}({0}_{1})")
+    public static Collection<Object[]> input() {
+        final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+                {MediaFormat.MIMETYPE_VIDEO_AVC},
+                {MediaFormat.MIMETYPE_VIDEO_H263},
+                {MediaFormat.MIMETYPE_VIDEO_HEVC},
+                {MediaFormat.MIMETYPE_VIDEO_MPEG4},
+                {MediaFormat.MIMETYPE_VIDEO_VP8},
+                {MediaFormat.MIMETYPE_VIDEO_VP9},
+        });
+        return prepareParamList(exhaustiveArgsList);
+    }
+
+    public VideoEncoderTest(String encoderName, String mime) {
+        mEncHandle = getEncHandle(encoderName, mime);
     }
 
     @Test
-    public void testGoogH265FlexMinMin()   { minmin(googH265(),   true /* flex */); }
-    @Test
-    public void testGoogH265SurfMinMin()   { minmin(googH265(),   false /* flex */); }
-    @Test
-    public void testGoogH264FlexMinMin()   { minmin(googH264(),   true /* flex */); }
-    @Test
-    public void testGoogH264SurfMinMin()   { minmin(googH264(),   false /* flex */); }
-    @Test
-    public void testGoogH263FlexMinMin()   { minmin(googH263(),   true /* flex */); }
-    @Test
-    public void testGoogH263SurfMinMin()   { minmin(googH263(),   false /* flex */); }
-    @Test
-    public void testGoogMpeg4FlexMinMin()  { minmin(googMpeg4(),  true /* flex */); }
-    @Test
-    public void testGoogMpeg4SurfMinMin()  { minmin(googMpeg4(),  false /* flex */); }
-    @Test
-    public void testGoogVP8FlexMinMin()    { minmin(googVP8(),    true /* flex */); }
-    @Test
-    public void testGoogVP8SurfMinMin()    { minmin(googVP8(),    false /* flex */); }
-    @Test
-    public void testGoogVP9FlexMinMin()    { minmin(googVP9(),    true /* flex */); }
-    @Test
-    public void testGoogVP9SurfMinMin()    { minmin(googVP9(),    false /* flex */); }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265FlexMinMin()  { minmin(otherH265(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265SurfMinMin()  { minmin(otherH265(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264FlexMinMin()  { minmin(otherH264(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264SurfMinMin()  { minmin(otherH264(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263FlexMinMin()  { minmin(otherH263(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263SurfMinMin()  { minmin(otherH263(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4FlexMinMin() { minmin(otherMpeg4(), true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4SurfMinMin() { minmin(otherMpeg4(), false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8FlexMinMin()   { minmin(otherVP8(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8SurfMinMin()   { minmin(otherVP8(),   false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9FlexMinMin()   { minmin(otherVP9(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9SurfMinMin()   { minmin(otherVP9(),   false /* flex */); }
-
-    @Test
-    public void testGoogH265FlexMinMax()   { minmax(googH265(),   true /* flex */); }
-    @Test public void testGoogH265SurfMinMax()   { minmax(googH265(),   false /* flex */); }
-    @Test
-    public void testGoogH264FlexMinMax()   { minmax(googH264(),   true /* flex */); }
-    @Test
-    public void testGoogH264SurfMinMax()   { minmax(googH264(),   false /* flex */); }
-    @Test
-    public void testGoogH263FlexMinMax()   { minmax(googH263(),   true /* flex */); }
-    @Test
-    public void testGoogH263SurfMinMax()   { minmax(googH263(),   false /* flex */); }
-    @Test
-    public void testGoogMpeg4FlexMinMax()  { minmax(googMpeg4(),  true /* flex */); }
-    @Test
-    public void testGoogMpeg4SurfMinMax()  { minmax(googMpeg4(),  false /* flex */); }
-    @Test
-    public void testGoogVP8FlexMinMax()    { minmax(googVP8(),    true /* flex */); }
-    @Test
-    public void testGoogVP8SurfMinMax()    { minmax(googVP8(),    false /* flex */); }
-    @Test
-    public void testGoogVP9FlexMinMax()    { minmax(googVP9(),    true /* flex */); }
-    @Test
-    public void testGoogVP9SurfMinMax()    { minmax(googVP9(),    false /* flex */); }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265FlexMinMax()  { minmax(otherH265(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265SurfMinMax()  { minmax(otherH265(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264FlexMinMax()  { minmax(otherH264(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264SurfMinMax()  { minmax(otherH264(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263FlexMinMax()  { minmax(otherH263(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263SurfMinMax()  { minmax(otherH263(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4FlexMinMax() { minmax(otherMpeg4(), true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4SurfMinMax() { minmax(otherMpeg4(), false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8FlexMinMax()   { minmax(otherVP8(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8SurfMinMax()   { minmax(otherVP8(),   false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9FlexMinMax()   { minmax(otherVP9(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9SurfMinMax()   { minmax(otherVP9(),   false /* flex */); }
-
-    @Test
-    public void testGoogH265FlexMaxMin()   { maxmin(googH265(),   true /* flex */); }
-    @Test
-    public void testGoogH265SurfMaxMin()   { maxmin(googH265(),   false /* flex */); }
-    @Test
-    public void testGoogH264FlexMaxMin()   { maxmin(googH264(),   true /* flex */); }
-    @Test
-    public void testGoogH264SurfMaxMin()   { maxmin(googH264(),   false /* flex */); }
-    @Test
-    public void testGoogH263FlexMaxMin()   { maxmin(googH263(),   true /* flex */); }
-    @Test
-    public void testGoogH263SurfMaxMin()   { maxmin(googH263(),   false /* flex */); }
-    @Test
-    public void testGoogMpeg4FlexMaxMin()  { maxmin(googMpeg4(),  true /* flex */); }
-    @Test
-    public void testGoogMpeg4SurfMaxMin()  { maxmin(googMpeg4(),  false /* flex */); }
-    @Test
-    public void testGoogVP8FlexMaxMin()    { maxmin(googVP8(),    true /* flex */); }
-    @Test
-    public void testGoogVP8SurfMaxMin()    { maxmin(googVP8(),    false /* flex */); }
-    @Test
-    public void testGoogVP9FlexMaxMin()    { maxmin(googVP9(),    true /* flex */); }
-    @Test
-    public void testGoogVP9SurfMaxMin()    { maxmin(googVP9(),    false /* flex */); }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265FlexMaxMin()  { maxmin(otherH265(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265SurfMaxMin()  { maxmin(otherH265(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264FlexMaxMin()  { maxmin(otherH264(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264SurfMaxMin()  { maxmin(otherH264(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test public void testOtherH263FlexMaxMin()  { maxmin(otherH263(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263SurfMaxMin()  { maxmin(otherH263(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4FlexMaxMin() { maxmin(otherMpeg4(), true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4SurfMaxMin() { maxmin(otherMpeg4(), false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8FlexMaxMin()   { maxmin(otherVP8(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8SurfMaxMin()   { maxmin(otherVP8(),   false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9FlexMaxMin()   { maxmin(otherVP9(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9SurfMaxMin()   { maxmin(otherVP9(),   false /* flex */); }
-
-    @Test
-    public void testGoogH265FlexMaxMax()   { maxmax(googH265(),   true /* flex */); }
-    @Test
-    public void testGoogH265SurfMaxMax()   { maxmax(googH265(),   false /* flex */); }
-    @Test
-    public void testGoogH264FlexMaxMax()   { maxmax(googH264(),   true /* flex */); }
-    @Test
-    public void testGoogH264SurfMaxMax()   { maxmax(googH264(),   false /* flex */); }
-    @Test
-    public void testGoogH263FlexMaxMax()   { maxmax(googH263(),   true /* flex */); }
-    @Test
-    public void testGoogH263SurfMaxMax()   { maxmax(googH263(),   false /* flex */); }
-    @Test
-    public void testGoogMpeg4FlexMaxMax()  { maxmax(googMpeg4(),  true /* flex */); }
-    @Test public void testGoogMpeg4SurfMaxMax()  { maxmax(googMpeg4(),  false /* flex */); }
-    @Test
-    public void testGoogVP8FlexMaxMax()    { maxmax(googVP8(),    true /* flex */); }
-    @Test
-    public void testGoogVP8SurfMaxMax()    { maxmax(googVP8(),    false /* flex */); }
-    @Test
-    public void testGoogVP9FlexMaxMax()    { maxmax(googVP9(),    true /* flex */); }
-    @Test
-    public void testGoogVP9SurfMaxMax()    { maxmax(googVP9(),    false /* flex */); }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265FlexMaxMax()  { maxmax(otherH265(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265SurfMaxMax()  { maxmax(otherH265(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264FlexMaxMax()  { maxmax(otherH264(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264SurfMaxMax()  { maxmax(otherH264(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263FlexMaxMax()  { maxmax(otherH263(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263SurfMaxMax()  { maxmax(otherH263(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4FlexMaxMax() { maxmax(otherMpeg4(), true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4SurfMaxMax() { maxmax(otherMpeg4(), false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8FlexMaxMax()   { maxmax(otherVP8(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8SurfMaxMax()   { maxmax(otherVP8(),   false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9FlexMaxMax()   { maxmax(otherVP9(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9SurfMaxMax()   { maxmax(otherVP9(),   false /* flex */); }
-
-    @Test public void testGoogH265FlexNearMinMin()   { nearminmin(googH265(),   true /* flex */); }
-    @Test
-    public void testGoogH265SurfNearMinMin()   { nearminmin(googH265(),   false /* flex */); }
-    @Test
-    public void testGoogH264FlexNearMinMin()   { nearminmin(googH264(),   true /* flex */); }
-    @Test
-    public void testGoogH264SurfNearMinMin()   { nearminmin(googH264(),   false /* flex */); }
-    @Test
-    public void testGoogH263FlexNearMinMin()   { nearminmin(googH263(),   true /* flex */); }
-    @Test
-    public void testGoogH263SurfNearMinMin()   { nearminmin(googH263(),   false /* flex */); }
-    @Test
-    public void testGoogMpeg4FlexNearMinMin()  { nearminmin(googMpeg4(),  true /* flex */); }
-    @Test
-    public void testGoogMpeg4SurfNearMinMin()  { nearminmin(googMpeg4(),  false /* flex */); }
-    @Test
-    public void testGoogVP8FlexNearMinMin()    { nearminmin(googVP8(),    true /* flex */); }
-    @Test
-    public void testGoogVP8SurfNearMinMin()    { nearminmin(googVP8(),    false /* flex */); }
-    @Test
-    public void testGoogVP9FlexNearMinMin()    { nearminmin(googVP9(),    true /* flex */); }
-    @Test
-    public void testGoogVP9SurfNearMinMin()    { nearminmin(googVP9(),    false /* flex */); }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265FlexNearMinMin()  { nearminmin(otherH265(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265SurfNearMinMin()  { nearminmin(otherH265(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264FlexNearMinMin()  { nearminmin(otherH264(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264SurfNearMinMin()  { nearminmin(otherH264(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263FlexNearMinMin()  { nearminmin(otherH263(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263SurfNearMinMin()  { nearminmin(otherH263(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4FlexNearMinMin() { nearminmin(otherMpeg4(), true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4SurfNearMinMin() { nearminmin(otherMpeg4(), false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8FlexNearMinMin()   { nearminmin(otherVP8(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8SurfNearMinMin()   { nearminmin(otherVP8(),   false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9FlexNearMinMin()   { nearminmin(otherVP9(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9SurfNearMinMin()   { nearminmin(otherVP9(),   false /* flex */); }
-
-    @Test
-    public void testGoogH265FlexNearMinMax()   { nearminmax(googH265(),   true /* flex */); }
-    @Test
-    public void testGoogH265SurfNearMinMax()   { nearminmax(googH265(),   false /* flex */); }
-    @Test
-    public void testGoogH264FlexNearMinMax()   { nearminmax(googH264(),   true /* flex */); }
-    @Test
-    public void testGoogH264SurfNearMinMax()   { nearminmax(googH264(),   false /* flex */); }
-    @Test
-    public void testGoogH263FlexNearMinMax()   { nearminmax(googH263(),   true /* flex */); }
-    @Test
-    public void testGoogH263SurfNearMinMax()   { nearminmax(googH263(),   false /* flex */); }
-    @Test
-    public void testGoogMpeg4FlexNearMinMax()  { nearminmax(googMpeg4(),  true /* flex */); }
-    @Test
-    public void testGoogMpeg4SurfNearMinMax()  { nearminmax(googMpeg4(),  false /* flex */); }
-    @Test public void testGoogVP8FlexNearMinMax()    { nearminmax(googVP8(),    true /* flex */); }
-    @Test
-    public void testGoogVP8SurfNearMinMax()    { nearminmax(googVP8(),    false /* flex */); }
-    @Test
-    public void testGoogVP9FlexNearMinMax()    { nearminmax(googVP9(),    true /* flex */); }
-    @Test
-    public void testGoogVP9SurfNearMinMax()    { nearminmax(googVP9(),    false /* flex */); }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265FlexNearMinMax()  { nearminmax(otherH265(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265SurfNearMinMax()  { nearminmax(otherH265(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264FlexNearMinMax()  { nearminmax(otherH264(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264SurfNearMinMax()  { nearminmax(otherH264(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263FlexNearMinMax()  { nearminmax(otherH263(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263SurfNearMinMax()  { nearminmax(otherH263(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4FlexNearMinMax() { nearminmax(otherMpeg4(), true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4SurfNearMinMax() { nearminmax(otherMpeg4(), false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8FlexNearMinMax()   { nearminmax(otherVP8(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8SurfNearMinMax()   { nearminmax(otherVP8(),   false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9FlexNearMinMax()   { nearminmax(otherVP9(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test public void testOtherVP9SurfNearMinMax()   { nearminmax(otherVP9(),   false /* flex */); }
-
-    @Test
-    public void testGoogH265FlexNearMaxMin()   { nearmaxmin(googH265(),   true /* flex */); }
-    @Test
-    public void testGoogH265SurfNearMaxMin()   { nearmaxmin(googH265(),   false /* flex */); }
-    @Test
-    public void testGoogH264FlexNearMaxMin()   { nearmaxmin(googH264(),   true /* flex */); }
-    @Test
-    public void testGoogH264SurfNearMaxMin()   { nearmaxmin(googH264(),   false /* flex */); }
-    @Test
-    public void testGoogH263FlexNearMaxMin()   { nearmaxmin(googH263(),   true /* flex */); }
-    @Test
-    public void testGoogH263SurfNearMaxMin()   { nearmaxmin(googH263(),   false /* flex */); }
-    @Test
-    public void testGoogMpeg4FlexNearMaxMin()  { nearmaxmin(googMpeg4(),  true /* flex */); }
-    @Test
-    public void testGoogMpeg4SurfNearMaxMin()  { nearmaxmin(googMpeg4(),  false /* flex */); }
-    @Test
-    public void testGoogVP8FlexNearMaxMin()    { nearmaxmin(googVP8(),    true /* flex */); }
-    @Test
-    public void testGoogVP8SurfNearMaxMin()    { nearmaxmin(googVP8(),    false /* flex */); }
-    @Test
-    public void testGoogVP9FlexNearMaxMin()    { nearmaxmin(googVP9(),    true /* flex */); }
-    @Test
-    public void testGoogVP9SurfNearMaxMin()    { nearmaxmin(googVP9(),    false /* flex */); }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265FlexNearMaxMin()  { nearmaxmin(otherH265(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265SurfNearMaxMin()  { nearmaxmin(otherH265(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264FlexNearMaxMin()  { nearmaxmin(otherH264(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264SurfNearMaxMin()  { nearmaxmin(otherH264(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263FlexNearMaxMin()  { nearmaxmin(otherH263(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263SurfNearMaxMin()  { nearmaxmin(otherH263(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4FlexNearMaxMin() { nearmaxmin(otherMpeg4(), true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4SurfNearMaxMin() { nearmaxmin(otherMpeg4(), false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8FlexNearMaxMin()   { nearmaxmin(otherVP8(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8SurfNearMaxMin()   { nearmaxmin(otherVP8(),   false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9FlexNearMaxMin()   { nearmaxmin(otherVP9(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9SurfNearMaxMin()   { nearmaxmin(otherVP9(),   false /* flex */); }
-
-    @Test
-    public void testGoogH265FlexNearMaxMax()   { nearmaxmax(googH265(),   true /* flex */); }
-    @Test
-    public void testGoogH265SurfNearMaxMax()   { nearmaxmax(googH265(),   false /* flex */); }
-    @Test
-    public void testGoogH264FlexNearMaxMax()   { nearmaxmax(googH264(),   true /* flex */); }
-    @Test
-    public void testGoogH264SurfNearMaxMax()   { nearmaxmax(googH264(),   false /* flex */); }
-    @Test
-    public void testGoogH263FlexNearMaxMax()   { nearmaxmax(googH263(),   true /* flex */); }
-    @Test
-    public void testGoogH263SurfNearMaxMax()   { nearmaxmax(googH263(),   false /* flex */); }
-    @Test
-    public void testGoogMpeg4FlexNearMaxMax()  { nearmaxmax(googMpeg4(),  true /* flex */); }
-    @Test
-    public void testGoogMpeg4SurfNearMaxMax()  { nearmaxmax(googMpeg4(),  false /* flex */); }
-    @Test
-    public void testGoogVP8FlexNearMaxMax()    { nearmaxmax(googVP8(),    true /* flex */); }
-    @Test
-    public void testGoogVP8SurfNearMaxMax()    { nearmaxmax(googVP8(),    false /* flex */); }
-    @Test public void testGoogVP9FlexNearMaxMax()    { nearmaxmax(googVP9(),    true /* flex */); }
-    @Test
-    public void testGoogVP9SurfNearMaxMax()    { nearmaxmax(googVP9(),    false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265FlexNearMaxMax()  { nearmaxmax(otherH265(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265SurfNearMaxMax()  { nearmaxmax(otherH265(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264FlexNearMaxMax()  { nearmaxmax(otherH264(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264SurfNearMaxMax()  { nearmaxmax(otherH264(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263FlexNearMaxMax()  { nearmaxmax(otherH263(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263SurfNearMaxMax()  { nearmaxmax(otherH263(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4FlexNearMaxMax() { nearmaxmax(otherMpeg4(), true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4SurfNearMaxMax() { nearmaxmax(otherMpeg4(), false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8FlexNearMaxMax()   { nearmaxmax(otherVP8(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8SurfNearMaxMax()   { nearmaxmax(otherVP8(),   false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9FlexNearMaxMax()   { nearmaxmax(otherVP9(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9SurfNearMaxMax()   { nearmaxmax(otherVP9(),   false /* flex */); }
-
-    @Test
-    public void testGoogH265FlexArbitraryW()   { arbitraryw(googH265(),   true /* flex */); }
-    @Test
-    public void testGoogH265SurfArbitraryW()   { arbitraryw(googH265(),   false /* flex */); }
-    @Test
-    public void testGoogH264FlexArbitraryW()   { arbitraryw(googH264(),   true /* flex */); }
-    @Test
-    public void testGoogH264SurfArbitraryW()   { arbitraryw(googH264(),   false /* flex */); }
-    @Test
-    public void testGoogH263FlexArbitraryW()   { arbitraryw(googH263(),   true /* flex */); }
-    @Test
-    public void testGoogH263SurfArbitraryW()   { arbitraryw(googH263(),   false /* flex */); }
-    @Test
-    public void testGoogMpeg4FlexArbitraryW()  { arbitraryw(googMpeg4(),  true /* flex */); }
-    @Test
-    public void testGoogMpeg4SurfArbitraryW()  { arbitraryw(googMpeg4(),  false /* flex */); }
-    @Test
-    public void testGoogVP8FlexArbitraryW()    { arbitraryw(googVP8(),    true /* flex */); }
-    @Test
-    public void testGoogVP8SurfArbitraryW()    { arbitraryw(googVP8(),    false /* flex */); }
-    @Test
-    public void testGoogVP9FlexArbitraryW()    { arbitraryw(googVP9(),    true /* flex */); }
-    @Test
-    public void testGoogVP9SurfArbitraryW()    { arbitraryw(googVP9(),    false /* flex */); }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265FlexArbitraryW()  { arbitraryw(otherH265(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265SurfArbitraryW()  { arbitraryw(otherH265(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264FlexArbitraryW()  { arbitraryw(otherH264(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264SurfArbitraryW()  { arbitraryw(otherH264(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263FlexArbitraryW()  { arbitraryw(otherH263(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263SurfArbitraryW()  { arbitraryw(otherH263(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4FlexArbitraryW() { arbitraryw(otherMpeg4(), true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4SurfArbitraryW() { arbitraryw(otherMpeg4(), false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8FlexArbitraryW()   { arbitraryw(otherVP8(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8SurfArbitraryW()   { arbitraryw(otherVP8(),   false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9FlexArbitraryW()   { arbitraryw(otherVP9(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9SurfArbitraryW()   { arbitraryw(otherVP9(),   false /* flex */); }
-
-    @Test
-    public void testGoogH265FlexArbitraryH()   { arbitraryh(googH265(),   true /* flex */); }
-    @Test
-    public void testGoogH265SurfArbitraryH()   { arbitraryh(googH265(),   false /* flex */); }
-    @Test
-    public void testGoogH264FlexArbitraryH()   { arbitraryh(googH264(),   true /* flex */); }
-    @Test
-    public void testGoogH264SurfArbitraryH()   { arbitraryh(googH264(),   false /* flex */); }
-    @Test
-    public void testGoogH263FlexArbitraryH()   { arbitraryh(googH263(),   true /* flex */); }
-    @Test
-    public void testGoogH263SurfArbitraryH()   { arbitraryh(googH263(),   false /* flex */); }
-    @Test
-    public void testGoogMpeg4FlexArbitraryH()  { arbitraryh(googMpeg4(),  true /* flex */); }
-    @Test
-    public void testGoogMpeg4SurfArbitraryH()  { arbitraryh(googMpeg4(),  false /* flex */); }
-    @Test
-    public void testGoogVP8FlexArbitraryH()    { arbitraryh(googVP8(),    true /* flex */); }
-    @Test
-    public void testGoogVP8SurfArbitraryH()    { arbitraryh(googVP8(),    false /* flex */); }
-    @Test
-    public void testGoogVP9FlexArbitraryH()    { arbitraryh(googVP9(),    true /* flex */); }
-    @Test
-    public void testGoogVP9SurfArbitraryH()    { arbitraryh(googVP9(),    false /* flex */); }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265FlexArbitraryH()  { arbitraryh(otherH265(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265SurfArbitraryH()  { arbitraryh(otherH265(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264FlexArbitraryH()  { arbitraryh(otherH264(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264SurfArbitraryH()  { arbitraryh(otherH264(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263FlexArbitraryH()  { arbitraryh(otherH263(),  true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263SurfArbitraryH()  { arbitraryh(otherH263(),  false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4FlexArbitraryH() { arbitraryh(otherMpeg4(), true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4SurfArbitraryH() { arbitraryh(otherMpeg4(), false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8FlexArbitraryH()   { arbitraryh(otherVP8(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8SurfArbitraryH()   { arbitraryh(otherVP8(),   false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9FlexArbitraryH()   { arbitraryh(otherVP9(),   true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9SurfArbitraryH()   { arbitraryh(otherVP9(),   false /* flex */); }
-
-    @Test
-    public void testGoogH265FlexQCIF()   { specific(googH265(),   176, 144, true /* flex */); }
-    @Test
-    public void testGoogH265SurfQCIF()   { specific(googH265(),   176, 144, false /* flex */); }
-    @Presubmit
-    @SmallTest
-    @Test
-    public void testGoogH264FlexQCIF()   { specific(googH264(),   176, 144, true /* flex */); }
-    @Presubmit
-    @SmallTest
-    @Test
-    public void testGoogH264SurfQCIF()   { specific(googH264(),   176, 144, false /* flex */); }
-    @Test
-    public void testGoogH263FlexQCIF()   { specific(googH263(),   176, 144, true /* flex */); }
-    @Test
-    public void testGoogH263SurfQCIF()   { specific(googH263(),   176, 144, false /* flex */); }
-    @Test
-    public void testGoogMpeg4FlexQCIF()  { specific(googMpeg4(),  176, 144, true /* flex */); }
-    @Test
-    public void testGoogMpeg4SurfQCIF()  { specific(googMpeg4(),  176, 144, false /* flex */); }
-    @Test
-    public void testGoogVP8FlexQCIF()    { specific(googVP8(),    176, 144, true /* flex */); }
-    @Test
-    public void testGoogVP8SurfQCIF()    { specific(googVP8(),    176, 144, false /* flex */); }
-    @Test
-    public void testGoogVP9FlexQCIF()    { specific(googVP9(),    176, 144, true /* flex */); }
-    @Test
-    public void testGoogVP9SurfQCIF()    { specific(googVP9(),    176, 144, false /* flex */); }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265FlexQCIF()  { specific(otherH265(),  176, 144, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265SurfQCIF()  { specific(otherH265(),  176, 144, false /* flex */); }
-    @NonMediaMainlineTest
-    @RequiresDevice
-    @Presubmit
-    @SmallTest
-    @Test
-    public void testOtherH264FlexQCIF()  { specific(otherH264(),  176, 144, true /* flex */); }
-    @NonMediaMainlineTest
-    @RequiresDevice
-    @Presubmit
-    @SmallTest
-    @Test
-    public void testOtherH264SurfQCIF()  { specific(otherH264(),  176, 144, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263FlexQCIF()  { specific(otherH263(),  176, 144, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263SurfQCIF()  { specific(otherH263(),  176, 144, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4FlexQCIF() { specific(otherMpeg4(), 176, 144, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4SurfQCIF() { specific(otherMpeg4(), 176, 144, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8FlexQCIF()   { specific(otherVP8(),   176, 144, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8SurfQCIF()   { specific(otherVP8(),   176, 144, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9FlexQCIF()   { specific(otherVP9(),   176, 144, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9SurfQCIF()   { specific(otherVP9(),   176, 144, false /* flex */); }
-
-    @Test
-    public void testGoogH265Flex480p()   { specific(googH265(),   720, 480, true /* flex */); }
-    @Test
-    public void testGoogH265Surf480p()   { specific(googH265(),   720, 480, false /* flex */); }
-    @Test
-    public void testGoogH264Flex480p()   { specific(googH264(),   720, 480, true /* flex */); }
-    @Test
-    public void testGoogH264Surf480p()   { specific(googH264(),   720, 480, false /* flex */); }
-    @Test
-    public void testGoogH263Flex480p()   { specific(googH263(),   720, 480, true /* flex */); }
-    @Test
-    public void testGoogH263Surf480p()   { specific(googH263(),   720, 480, false /* flex */); }
-    @Test
-    public void testGoogMpeg4Flex480p()  { specific(googMpeg4(),  720, 480, true /* flex */); }
-    @Test
-    public void testGoogMpeg4Surf480p()  { specific(googMpeg4(),  720, 480, false /* flex */); }
-    @Test
-    public void testGoogVP8Flex480p()    { specific(googVP8(),    720, 480, true /* flex */); }
-    @Test
-    public void testGoogVP8Surf480p()    { specific(googVP8(),    720, 480, false /* flex */); }
-    @Test public void testGoogVP9Flex480p()    { specific(googVP9(),    720, 480, true /* flex */); }
-    @Test public void testGoogVP9Surf480p()    { specific(googVP9(),    720, 480, false /* flex */); }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265Flex480p()  { specific(otherH265(),  720, 480, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265Surf480p()  { specific(otherH265(),  720, 480, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264Flex480p()  { specific(otherH264(),  720, 480, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264Surf480p()  { specific(otherH264(),  720, 480, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263Flex480p()  { specific(otherH263(),  720, 480, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263Surf480p()  { specific(otherH263(),  720, 480, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4Flex480p() { specific(otherMpeg4(), 720, 480, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4Surf480p() { specific(otherMpeg4(), 720, 480, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8Flex480p()   { specific(otherVP8(),   720, 480, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8Surf480p()   { specific(otherVP8(),   720, 480, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9Flex480p()   { specific(otherVP9(),   720, 480, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9Surf480p()   { specific(otherVP9(),   720, 480, false /* flex */); }
-
-    // even though H.263 and MPEG-4 are not defined for 720p or 1080p
-    // test for it, in case device claims support for it.
-
-    @Test
-    public void testGoogH265Flex720p()   { specific(googH265(),   1280, 720, true /* flex */); }
-    @Test
-    public void testGoogH265Surf720p()   { specific(googH265(),   1280, 720, false /* flex */); }
-    @Test
-    public void testGoogH264Flex720p()   { specific(googH264(),   1280, 720, true /* flex */); }
-    @Test
-    public void testGoogH264Surf720p()   { specific(googH264(),   1280, 720, false /* flex */); }
-    @Test
-    public void testGoogH263Flex720p()   { specific(googH263(),   1280, 720, true /* flex */); }
-    @Test
-    public void testGoogH263Surf720p()   { specific(googH263(),   1280, 720, false /* flex */); }
-    @Test
-    public void testGoogMpeg4Flex720p()  { specific(googMpeg4(),  1280, 720, true /* flex */); }
-    @Test
-    public void testGoogMpeg4Surf720p()  { specific(googMpeg4(),  1280, 720, false /* flex */); }
-    @Test
-    public void testGoogVP8Flex720p()    { specific(googVP8(),    1280, 720, true /* flex */); }
-    @Test
-    public void testGoogVP8Surf720p()    { specific(googVP8(),    1280, 720, false /* flex */); }
-    @Test
-    public void testGoogVP9Flex720p()    { specific(googVP9(),    1280, 720, true /* flex */); }
-    @Test
-    public void testGoogVP9Surf720p()    { specific(googVP9(),    1280, 720, false /* flex */); }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265Flex720p()  { specific(otherH265(),  1280, 720, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265Surf720p()  { specific(otherH265(),  1280, 720, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264Flex720p()  { specific(otherH264(),  1280, 720, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264Surf720p()  { specific(otherH264(),  1280, 720, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263Flex720p()  { specific(otherH263(),  1280, 720, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263Surf720p()  { specific(otherH263(),  1280, 720, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4Flex720p() { specific(otherMpeg4(), 1280, 720, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4Surf720p() { specific(otherMpeg4(), 1280, 720, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8Flex720p()   { specific(otherVP8(),   1280, 720, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8Surf720p()   { specific(otherVP8(),   1280, 720, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9Flex720p()   { specific(otherVP9(),   1280, 720, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9Surf720p()   { specific(otherVP9(),   1280, 720, false /* flex */); }
-
-    @Test public void testGoogH265Flex1080p()   { specific(googH265(),   1920, 1080, true /* flex */); }
-    @Test
-    public void testGoogH265Surf1080p()   { specific(googH265(),   1920, 1080, false /* flex */); }
-    @Test
-    public void testGoogH264Flex1080p()   { specific(googH264(),   1920, 1080, true /* flex */); }
-    @Test
-    public void testGoogH264Surf1080p()   { specific(googH264(),   1920, 1080, false /* flex */); }
-    @Test
-    public void testGoogH263Flex1080p()   { specific(googH263(),   1920, 1080, true /* flex */); }
-    @Test
-    public void testGoogH263Surf1080p()   { specific(googH263(),   1920, 1080, false /* flex */); }
-    @Test
-    public void testGoogMpeg4Flex1080p()  { specific(googMpeg4(),  1920, 1080, true /* flex */); }
-    @Test
-    public void testGoogMpeg4Surf1080p()  { specific(googMpeg4(),  1920, 1080, false /* flex */); }
-    @Test
-    public void testGoogVP8Flex1080p()    { specific(googVP8(),    1920, 1080, true /* flex */); }
-    @Test
-    public void testGoogVP8Surf1080p()    { specific(googVP8(),    1920, 1080, false /* flex */); }
-    @Test
-    public void testGoogVP9Flex1080p()    { specific(googVP9(),    1920, 1080, true /* flex */); }
-    @Test
-    public void testGoogVP9Surf1080p()    { specific(googVP9(),    1920, 1080, false /* flex */); }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265Flex1080p()  { specific(otherH265(),  1920, 1080, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH265Surf1080p()  { specific(otherH265(),  1920, 1080, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264Flex1080p()  { specific(otherH264(),  1920, 1080, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH264Surf1080p()  { specific(otherH264(),  1920, 1080, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263Flex1080p()  { specific(otherH263(),  1920, 1080, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherH263Surf1080p()  { specific(otherH263(),  1920, 1080, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4Flex1080p() { specific(otherMpeg4(), 1920, 1080, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherMpeg4Surf1080p() { specific(otherMpeg4(), 1920, 1080, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8Flex1080p()   { specific(otherVP8(),   1920, 1080, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP8Surf1080p()   { specific(otherVP8(),   1920, 1080, false /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9Flex1080p()   { specific(otherVP9(),   1920, 1080, true /* flex */); }
-    @NonMediaMainlineTest
-    @Test
-    public void testOtherVP9Surf1080p()   { specific(otherVP9(),   1920, 1080, false /* flex */); }
-
-    @Test
-    public void testGoogH265Flex360pWithIntraRefresh() {
-        intraRefresh(googH265(), 480, 360);
+    public void testFlexMinMin() {
+        minmin(new Encoder[]{mEncHandle}, true);
     }
 
     @Test
-    public void testGoogH264Flex360pWithIntraRefresh() {
-        intraRefresh(googH264(), 480, 360);
+    public void testSurfMinMin() {
+        minmin(new Encoder[]{mEncHandle}, false);
     }
 
     @Test
-    public void testGoogH263Flex360pWithIntraRefresh() {
-        intraRefresh(googH263(), 480, 360);
+    public void testFlexMinMax() {
+        minmax(new Encoder[]{mEncHandle}, true);
     }
 
     @Test
-    public void testGoogMpeg4Flex360pWithIntraRefresh() {
-        intraRefresh(googMpeg4(), 480, 360);
+    public void testSurfMinMax() {
+        minmax(new Encoder[]{mEncHandle}, false);
     }
 
     @Test
-    public void testGoogVP8Flex360pWithIntraRefresh() {
-        intraRefresh(googVP8(), 480, 360);
+    public void testFlexMaxMin() {
+        maxmin(new Encoder[]{mEncHandle}, true);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testOtherH265Flex360pWithIntraRefresh() {
-        intraRefresh(otherH265(), 480, 360);
+    public void testSurfMaxMin() {
+        maxmin(new Encoder[]{mEncHandle}, false);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testOtherH264Flex360pWithIntraRefresh() {
-        intraRefresh(otherH264(), 480, 360);
+    public void testFlexMaxMax() {
+        maxmax(new Encoder[]{mEncHandle}, true);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testOtherH263FlexQCIFWithIntraRefresh() {
-        intraRefresh(otherH263(), 176, 120);
+    public void testSurfMaxMax() {
+        maxmax(new Encoder[]{mEncHandle}, false);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testOtherMpeg4Flex360pWithIntraRefresh() {
-        intraRefresh(otherMpeg4(), 480, 360);
+    public void testFlexNearMinMin() {
+        nearminmin(new Encoder[]{mEncHandle}, true);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testOtherVP8Flex360pWithIntraRefresh() {
-        intraRefresh(otherVP8(), 480, 360);
+    public void testSurfNearMinMin() {
+        nearminmin(new Encoder[]{mEncHandle}, false);
+    }
+
+    @Test
+    public void testFlexNearMinMax() {
+        nearminmax(new Encoder[]{mEncHandle}, true);
+    }
+
+    @Test
+    public void testSurfNearMinMax() {
+        nearminmax(new Encoder[]{mEncHandle}, false);
+    }
+
+    @Test
+    public void testFlexNearMaxMin() {
+        nearmaxmin(new Encoder[]{mEncHandle}, true);
+    }
+
+    @Test
+    public void testSurfNearMaxMin() {
+        nearmaxmin(new Encoder[]{mEncHandle}, false);
+    }
+
+    @Test
+    public void testFlexNearMaxMax() {
+        nearmaxmax(new Encoder[]{mEncHandle}, true);
+    }
+
+    @Test
+    public void testSurfNearMaxMax() {
+        nearmaxmax(new Encoder[]{mEncHandle}, false);
+    }
+
+    @Test
+    public void testFlexArbitraryW() {
+        arbitraryw(new Encoder[]{mEncHandle}, true);
+    }
+
+    @Test
+    public void testSurfArbitraryW() {
+        arbitraryw(new Encoder[]{mEncHandle}, false);
+    }
+
+    @Test
+    public void testFlexArbitraryH() {
+        arbitraryh(new Encoder[]{mEncHandle}, true);
+    }
+
+    @Test
+    public void testSurfArbitraryH() {
+        arbitraryh(new Encoder[]{mEncHandle}, false);
+    }
+
+    @Test
+    public void testFlexQCIF() {
+        specific(new Encoder[]{mEncHandle}, 176, 144, true);
+    }
+
+    @Test
+    public void testSurfQCIF() {
+        specific(new Encoder[]{mEncHandle}, 176, 144, false);
+    }
+
+    @Test
+    public void testFlex480p() {
+        specific(new Encoder[]{mEncHandle}, 720, 480, true);
+    }
+
+    @Test
+    public void testSurf480p() {
+        specific(new Encoder[]{mEncHandle}, 720, 480, false);
+    }
+
+    @Test
+    public void testFlex720p() {
+        specific(new Encoder[]{mEncHandle}, 1280, 720, true);
+    }
+
+    @Test
+    public void testSurf720p() {
+        specific(new Encoder[]{mEncHandle}, 1280, 720, false);
+    }
+
+    @Test
+    public void testFlex1080p() {
+        specific(new Encoder[]{mEncHandle}, 1920, 1080, true);
+    }
+
+    @Test
+    public void testSurf1080p() {
+        specific(new Encoder[]{mEncHandle}, 1920, 1080, false);
+    }
+
+    @Test
+    public void testFlex360pWithIntraRefresh() {
+        intraRefresh(new Encoder[]{mEncHandle}, 480, 360);
     }
 
     // Tests encoder profiles required by CDD.
-    // H264
-    @NonMediaMainlineTest
     @Test
-    public void testH264LowQualitySDSupport()   {
-        support(h264(), 320, 240, 20, 384 * 1000);
+    public void testLowQualitySDSupport() {
+        Assume.assumeTrue("Test is currently enabled only for avc and vp8 encoders",
+                mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_AVC) ||
+                mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8));
+        support(new Encoder[]{mEncHandle}, 720, 480, 20, 384 * 1000);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testH264HighQualitySDSupport()   {
-        support(h264(), 720, 480, 30, 2 * 1000000);
+    public void testHighQualitySDSupport() {
+        Assume.assumeTrue("Test is currently enabled only for avc and vp8 encoders",
+                mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_AVC) ||
+                        mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8));
+        support(new Encoder[]{mEncHandle}, 720, 480, 30, 2 * 1000000);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testH264FlexQVGA20fps384kbps()   {
-        detailed(h264(), 320, 240, 20, 384 * 1000, true /* flex */);
+    public void testFlexQVGA20fps384kbps() {
+        Assume.assumeTrue("Test is currently enabled only for avc and vp8 encoders",
+                mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_AVC) ||
+                        mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8));
+        detailed(new Encoder[]{mEncHandle}, 320, 240, 20, 384 * 1000, true);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testH264SurfQVGA20fps384kbps()   {
-        detailed(h264(), 320, 240, 20, 384 * 1000, false /* flex */);
+    public void testSurfQVGA20fps384kbps() {
+        Assume.assumeTrue("Test is currently enabled only for avc and vp8 encoders",
+                mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_AVC) ||
+                        mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8));
+        detailed(new Encoder[]{mEncHandle}, 320, 240, 20, 384 * 1000, false /* flex */);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testH264Flex480p30fps2Mbps()   {
-        detailed(h264(), 720, 480, 30, 2 * 1000000, true /* flex */);
+    public void testFlex480p30fps2Mbps() {
+        Assume.assumeTrue("Test is currently enabled only for avc and vp8 encoders",
+                mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_AVC) ||
+                        mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8));
+        detailed(new Encoder[]{mEncHandle}, 720, 480, 30, 2 * 1000000, true /* flex */);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testH264Surf480p30fps2Mbps()   {
-        detailed(h264(), 720, 480, 30, 2 * 1000000, false /* flex */);
+    public void testSurf480p30fps2Mbps() {
+        Assume.assumeTrue("Test is currently enabled only for avc and vp8 encoders",
+                mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_AVC) ||
+                        mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8));
+        detailed(new Encoder[]{mEncHandle}, 720, 480, 30, 2 * 1000000, false /* flex */);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testH264Flex720p30fps4Mbps()   {
-        detailed(h264(), 1280, 720, 30, 4 * 1000000, true /* flex */);
+    public void testFlex720p30fps4Mbps() {
+        Assume.assumeTrue("Test is currently enabled only for avc and vp8 encoders",
+                mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_AVC) ||
+                        mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8));
+        detailed(new Encoder[]{mEncHandle}, 1280, 720, 30, 4 * 1000000, true /* flex */);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testH264Surf720p30fps4Mbps()   {
-        detailed(h264(), 1280, 720, 30, 4 * 1000000, false /* flex */);
+    public void testSurf720p30fps4Mbps() {
+        Assume.assumeTrue("Test is currently enabled only for avc and vp8 encoders",
+                mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_AVC) ||
+                        mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8));
+        detailed(new Encoder[]{mEncHandle}, 1280, 720, 30, 4 * 1000000, false /* flex */);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testH264Flex1080p30fps10Mbps()   {
-        detailed(h264(), 1920, 1080, 30, 10 * 1000000, true /* flex */);
+    public void testFlex1080p30fps10Mbps() {
+        Assume.assumeTrue("Test is currently enabled only for avc and vp8 encoders",
+                mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_AVC) ||
+                        mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8));
+        detailed(new Encoder[]{mEncHandle}, 1920, 1080, 30, 10 * 1000000, true /* flex */);
     }
 
-    @NonMediaMainlineTest
     @Test
-    public void testH264Surf1080p30fps10Mbps()   {
-        detailed(h264(), 1920, 1080, 30, 10 * 1000000, false /* flex */);
-    }
-
-    // VP8
-    @NonMediaMainlineTest
-    @Test
-    public void testVP8LowQualitySDSupport()   {
-        support(vp8(), 320, 180, 30, 800 * 1000);
-    }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testVP8HighQualitySDSupport()   {
-        support(vp8(), 640, 360, 30, 2 * 1000000);
-    }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testVP8Flex180p30fps800kbps()   {
-        detailed(vp8(), 320, 180, 30, 800 * 1000, true /* flex */);
-    }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testVP8Surf180p30fps800kbps()   {
-        detailed(vp8(), 320, 180, 30, 800 * 1000, false /* flex */);
-    }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testVP8Flex360p30fps2Mbps()   {
-        detailed(vp8(), 640, 360, 30, 2 * 1000000, true /* flex */);
-    }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testVP8Surf360p30fps2Mbps()   {
-        detailed(vp8(), 640, 360, 30, 2 * 1000000, false /* flex */);
-    }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testVP8Flex720p30fps4Mbps()   {
-        detailed(vp8(), 1280, 720, 30, 4 * 1000000, true /* flex */);
-    }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testVP8Surf720p30fps4Mbps()   {
-        detailed(vp8(), 1280, 720, 30, 4 * 1000000, false /* flex */);
-    }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testVP8Flex1080p30fps10Mbps()   {
-        detailed(vp8(), 1920, 1080, 30, 10 * 1000000, true /* flex */);
-    }
-
-    @NonMediaMainlineTest
-    @Test
-    public void testVP8Surf1080p30fps10Mbps()   {
-        detailed(vp8(), 1920, 1080, 30, 10 * 1000000, false /* flex */);
+    public void testSurf1080p30fps10Mbps() {
+        Assume.assumeTrue("Test is currently enabled only for avc and vp8 encoders",
+                mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_AVC) ||
+                        mEncHandle.mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8));
+        detailed(new Encoder[]{mEncHandle}, 1920, 1080, 30, 10 * 1000000, false /* flex */);
     }
 
     private void minmin(Encoder[] encoders, boolean flexYUV) {
diff --git a/tests/tests/media/extractor/AndroidManifest.xml b/tests/tests/media/extractor/AndroidManifest.xml
index 6911d53..82f45b9 100644
--- a/tests/tests/media/extractor/AndroidManifest.xml
+++ b/tests/tests/media/extractor/AndroidManifest.xml
@@ -17,9 +17,9 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="android.media.extractor.cts"
      android:targetSandboxVersion="2">
-
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"/>
+    <uses-permission android:name="android.permission.INTERNET"/>
 
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
 
diff --git a/tests/tests/media/libimagereaderjni/Android.bp b/tests/tests/media/libimagereaderjni/Android.bp
deleted file mode 100644
index bb84594..0000000
--- a/tests/tests/media/libimagereaderjni/Android.bp
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Build the unit tests.
-
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_test_library {
-    name: "libctsimagereader_jni",
-    srcs: ["AImageReaderCts.cpp"],
-    shared_libs: [
-        "libandroid",
-        "libcamera2ndk",
-        "libmediandk",
-        "libnativewindow",
-        "liblog",
-    ],
-    cflags: [
-        "-Werror",
-        "-Wall",
-    ],
-    gtest: false,
-    // this test suite will run on sdk 29 as part of MTS, make sure it's compatible
-    // (revisit if/when we add features to this library that require newer sdk.
-    sdk_version: "29",
-    stl: "libc++_static",
-}
diff --git a/tests/tests/media/libimagereaderjni/OWNERS b/tests/tests/media/libimagereaderjni/OWNERS
deleted file mode 100644
index f48a95c..0000000
--- a/tests/tests/media/libimagereaderjni/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include platform/frameworks/av:/camera/OWNERS
diff --git a/tests/tests/media/libmediandkjni/Android.bp b/tests/tests/media/libmediandkjni/Android.bp
deleted file mode 100644
index 02dcc3c..0000000
--- a/tests/tests/media/libmediandkjni/Android.bp
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (C) 2012 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-//------------------------------------------------------------------------------
-// Builds libctscodecutils_jni.so
-//
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "cts_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    //   legacy_unencumbered
-    default_applicable_licenses: [
-        "Android-Apache-2.0",
-        "cts_tests_tests_media_libmediaandkjni_license",
-    ],
-}
-
-license_kind {
-    name: "libmediaandkjni_public_domain",
-    conditions: ["unencumbered"],
-}
-
-license {
-    name: "cts_tests_tests_media_libmediaandkjni_license",
-    license_kinds: ["libmediaandkjni_public_domain"],
-}
-
-//------------------------------------------------------------------------------
-// Builds libctsmediacodec_jni.so
-//
-cc_test_library {
-    name: "libctsmediacodec_jni",
-    srcs: [
-        "native-media-jni.cpp",
-    ],
-    shared_libs: [
-        "libandroid",
-        "libnativehelper_compat_libc++",
-        "liblog",
-        "libmediandk",
-        "libEGL",
-    ],
-    header_libs: ["liblog_headers"],
-    stl: "libc++_static",
-    cflags: [
-        "-Werror",
-        "-Wall",
-        "-DEGL_EGLEXT_PROTOTYPES",
-    ],
-    gtest: false,
-    // this test suite will run on sdk 29 as part of MTS, make sure it's compatible
-    // (revisit if/when we add features to this library that require newer sdk.
-    sdk_version: "29",
-}
-
diff --git a/tests/tests/media/misc/Android.bp b/tests/tests/media/misc/Android.bp
new file mode 100644
index 0000000..feaabe4
--- /dev/null
+++ b/tests/tests/media/misc/Android.bp
@@ -0,0 +1,113 @@
+// Copyright (C) 2008 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: [
+        "Android-Apache-2.0",
+        "cts_tests_tests_media_license", // CC-BY
+    ],
+}
+
+cc_test_library {
+    name: "libctsmediamisc_jni",
+    srcs: [
+        "jni/AImageReaderCts.cpp",
+        "jni/native-media-jni.cpp",
+    ],
+    shared_libs: [
+        "libandroid",
+        "libcamera2ndk",
+        "libnativehelper_compat_libc++",
+        "liblog",
+        "libmediandk",
+        "libEGL",
+    ],
+    header_libs: ["liblog_headers"],
+    stl: "libc++_static",
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ],
+    gtest: false,
+    // this test suite will run on sdk 29 as part of MTS, make sure it's compatible
+    // (revisit if/when we add features to this library that require newer sdk.
+    sdk_version: "29",
+}
+
+android_test {
+    name: "CtsMediaMiscTestCases",
+    defaults: ["cts_defaults"],
+    // include both the 32 and 64 bit versions
+    compile_multilib: "both",
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.ext.junit",
+        "compatibility-device-util-axt",
+        "ctsdeviceutillegacy-axt",
+        "ctsmediautil",
+        "ctstestrunner-axt",
+        "hamcrest-library",
+        "ctstestserver",
+        "cts-media-common",
+        "junit",
+        "junit-params",
+        "testng",
+        "truth-prebuilt",
+        "mockito-target-minus-junit4",
+        "androidx.heifwriter_heifwriter",
+        "CtsCameraUtils",
+    ],
+    jni_libs: [
+        "libctscodecutils_jni",
+        "libctsmediamisc_jni",
+        "libctsmediacommon_jni",
+        "libnativehelper_compat_libc++",
+    ],
+    asset_dirs: ["assets"],
+    resource_dirs: ["res"],
+    aaptflags: [
+        "--auto-add-overlay",
+
+        // Do not compress these files:
+        "-0 .vp9",
+        "-0 .ts",
+        "-0 .heic",
+        "-0 .trp",
+        "-0 .ota",
+        "-0 .mxmf",
+    ],
+    srcs: [
+        "src/**/*.java",
+        "aidl/**/*.aidl",
+    ],
+    // This test uses private APIs
+    platform_apis: true,
+    jni_uses_sdk_apis: true,
+    libs: [
+        "org.apache.http.legacy",
+        "android.test.base",
+        "android.test.runner",
+    ],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "general-tests",
+        "mts-media",
+    ],
+    host_required: ["cts-dynamic-config"],
+    min_sdk_version: "29",
+    target_sdk_version: "31",
+}
diff --git a/tests/tests/media/AndroidManifest.xml b/tests/tests/media/misc/AndroidManifest.xml
similarity index 63%
rename from tests/tests/media/AndroidManifest.xml
rename to tests/tests/media/misc/AndroidManifest.xml
index 86f744f..9b02586 100644
--- a/tests/tests/media/AndroidManifest.xml
+++ b/tests/tests/media/misc/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-     package="android.media.cts"
+     package="android.media.misc.cts"
      android:targetSandboxVersion="2">
 
     <uses-sdk android:minSdkVersion="29"
@@ -44,24 +44,14 @@
 
     <uses-permission android:name="android.permission.VIBRATE"/>
 
-    <permission android:name="android.media.cts"
-         android:protectionLevel="normal"/>
-
-    <application android:networkSecurityConfig="@xml/network_security_config"
+    <application
          android:requestLegacyExternalStorage="true"
          android:largeHeap="true">
         <uses-library android:name="android.test.runner"/>
         <uses-library android:name="org.apache.http.legacy"
              android:required="false"/>
 
-        <activity android:name="android.media.cts.MediaProjectionActivity"
-             android:label="MediaProjectionActivity"
-             android:screenOrientation="locked"/>
-        <activity android:name="android.media.cts.AudioManagerStub"
-             android:label="AudioManagerStub"/>
-        <activity android:name="android.media.cts.AudioManagerStubHelper"
-             android:label="AudioManagerStubHelper"/>
-        <activity android:name="android.media.cts.MediaSessionTestActivity"
+        <activity android:name="android.media.misc.cts.MediaSessionTestActivity"
              android:label="MediaSessionTestActivity"
              android:screenOrientation="nosensor"
              android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
@@ -71,29 +61,9 @@
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
             </intent-filter>
         </activity>
-        <activity android:name="android.media.cts.MediaStubActivity"
-             android:label="MediaStubActivity"
-             android:screenOrientation="nosensor"
-             android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
-             android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
-            </intent-filter>
-        </activity>
-        <activity android:name="android.media.cts.MediaStubActivity2"
-             android:label="MediaStubActivity2"
-             android:screenOrientation="nosensor"
-             android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
-             android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
-            </intent-filter>
-        </activity>
-        <activity android:name="android.media.cts.FaceDetectorStub"
+        <activity android:name="android.media.misc.cts.FaceDetectorStub"
              android:label="FaceDetectorStub"/>
-        <activity android:name="android.media.cts.ResourceManagerStubActivity"
+        <activity android:name="android.media.misc.cts.ResourceManagerStubActivity"
              android:label="ResourceManagerStubActivity"
              android:exported="true">
             <intent-filter>
@@ -101,50 +71,46 @@
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
             </intent-filter>
         </activity>
-        <activity android:name="android.media.cts.ResourceManagerTestActivity1"
+        <activity android:name="android.media.misc.cts.ResourceManagerTestActivity1"
              android:label="ResourceManagerTestActivity1"
              android:process=":mediaCodecTestProcess1">
         </activity>
-        <activity android:name="android.media.cts.ResourceManagerTestActivity2"
+        <activity android:name="android.media.misc.cts.ResourceManagerTestActivity2"
              android:label="ResourceManagerTestActivity2"
              android:process=":mediaCodecTestProcess2">
         </activity>
-        <activity android:name="android.media.cts.MockActivity"/>
-        <activity android:name="android.media.cts.MediaRouter2TestActivity"/>
-        <service android:name="android.media.cts.StubMediaBrowserService"
+        <activity android:name="android.media.misc.cts.MockActivity"/>
+        <activity android:name="android.media.misc.cts.MediaRouter2TestActivity"/>
+        <service android:name="android.media.misc.cts.StubMediaBrowserService"
              android:exported="true">
             <intent-filter>
                 <action android:name="android.media.browse.MediaBrowserService"/>
             </intent-filter>
         </service>
-        <service android:name="android.media.cts.StubMediaSession2Service"
-             android:permission="android.media.cts"
+        <service android:name="android.media.misc.cts.StubMediaSession2Service"
+             android:permission="android.media.misc.cts"
              android:exported="true">
             <intent-filter>
                 <action android:name="android.media.MediaSession2Service"/>
             </intent-filter>
         </service>
-        <service android:name="android.media.cts.LocalMediaProjectionService"
-             android:foregroundServiceType="mediaProjection"
-             android:enabled="true">
-        </service>
         <service android:name=".StubMediaRoute2ProviderService"
              android:exported="true">
             <intent-filter>
                 <action android:name="android.media.MediaRoute2ProviderService"/>
             </intent-filter>
         </service>
-        <service android:name="android.media.cts.MediaButtonReceiverService"
+        <service android:name="android.media.misc.cts.MediaButtonReceiverService"
              android:exported="true"/>
         <service android:name=".MediaBrowserServiceTestService"
              android:process=":mediaBrowserServiceTestService"/>
         <service android:name=".MediaSessionTestService"
              android:process=":mediaSessionTestService"/>
-        <receiver android:name="android.media.cts.MediaButtonBroadcastReceiver"/>
+        <receiver android:name="android.media.misc.cts.MediaButtonBroadcastReceiver"/>
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-         android:targetPackage="android.media.cts"
+         android:targetPackage="android.media.misc.cts"
          android:label="CTS tests of android.media">
         <meta-data android:name="listener"
              android:value="com.android.cts.runner.CtsTestRunListener"/>
diff --git a/tests/tests/media/AndroidTest.xml b/tests/tests/media/misc/AndroidTest.xml
similarity index 83%
rename from tests/tests/media/AndroidTest.xml
rename to tests/tests/media/misc/AndroidTest.xml
index 8d20655..58cea2c 100644
--- a/tests/tests/media/AndroidTest.xml
+++ b/tests/tests/media/misc/AndroidTest.xml
@@ -29,26 +29,26 @@
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
         <option name="target" value="host" />
-        <option name="config-filename" value="CtsMediaTestCases" />
-        <option name="dynamic-config-name" value="CtsMediaTestCases" />
+        <option name="config-filename" value="CtsMediaMiscTestCases" />
+        <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.MediaPreparer">
         <option name="push-all" value="true" />
-        <option name="media-folder-name" value="CtsMediaTestCases-1.4" />
-        <option name="dynamic-config-module" value="CtsMediaTestCases" />
+        <option name="media-folder-name" value="CtsMediaMiscTestCases-1.0" />
+        <option name="dynamic-config-module" value="CtsMediaMiscTestCases" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsMediaTestCases.apk" />
+        <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="CtsMediaTestCases" />
-        <option name="version" value="7.0"/>
+        <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.cts" />
+        <option name="package" value="android.media.misc.cts" />
         <!-- setup can be expensive so limit the number of shards -->
         <option name="ajur-max-shard" value="5" />
         <!-- test-timeout unit is ms, value = 30 min -->
diff --git a/tests/tests/media/misc/DynamicConfig.xml b/tests/tests/media/misc/DynamicConfig.xml
new file mode 100644
index 0000000..09e5fba
--- /dev/null
+++ b/tests/tests/media/misc/DynamicConfig.xml
@@ -0,0 +1,20 @@
+<!-- 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.
+-->
+
+<dynamicConfig>
+    <entry key="media_files_url">
+    <value>https://storage.googleapis.com/android_media/cts/tests/tests/media/misc/CtsMediaMiscTestCases-1.0.zip</value>
+    </entry>
+</dynamicConfig>
diff --git a/tests/tests/media/aidl/android/media/cts/IRemoteService.aidl b/tests/tests/media/misc/aidl/android/media/misc/cts/IRemoteService.aidl
similarity index 95%
rename from tests/tests/media/aidl/android/media/cts/IRemoteService.aidl
rename to tests/tests/media/misc/aidl/android/media/misc/cts/IRemoteService.aidl
index 5aacc30..7a9a957 100644
--- a/tests/tests/media/aidl/android/media/cts/IRemoteService.aidl
+++ b/tests/tests/media/misc/aidl/android/media/misc/cts/IRemoteService.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.os.Bundle;
 
diff --git a/tests/tests/media/assets/noiseandchirps.mp3 b/tests/tests/media/misc/assets/noiseandchirps.mp3
similarity index 100%
rename from tests/tests/media/assets/noiseandchirps.mp3
rename to tests/tests/media/misc/assets/noiseandchirps.mp3
Binary files differ
diff --git a/tests/tests/media/libimagereaderjni/AImageReaderCts.cpp b/tests/tests/media/misc/jni/AImageReaderCts.cpp
similarity index 98%
rename from tests/tests/media/libimagereaderjni/AImageReaderCts.cpp
rename to tests/tests/media/misc/jni/AImageReaderCts.cpp
index ea35540..44b8a8f 100644
--- a/tests/tests/media/libimagereaderjni/AImageReaderCts.cpp
+++ b/tests/tests/media/misc/jni/AImageReaderCts.cpp
@@ -506,7 +506,7 @@
 }  // namespace
 
 // Test that newWithUsage can create AImageReader correctly.
-extern "C" jboolean Java_android_media_cts_NativeImageReaderTest_\
+extern "C" jboolean Java_android_media_misc_cts_NativeImageReaderTest_\
 testSucceedsWithSupportedUsageFormatNative(JNIEnv* /*env*/, jclass /*clazz*/) {
     static constexpr int kTestImageCount = 8;
 
@@ -526,7 +526,7 @@
     return true;
 }
 
-extern "C" jboolean Java_android_media_cts_NativeImageReaderTest_\
+extern "C" jboolean Java_android_media_misc_cts_NativeImageReaderTest_\
 testTakePicturesNative(JNIEnv* /*env*/, jclass /*clazz*/) {
     for (auto& readerUsage :
          {AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN}) {
@@ -546,7 +546,7 @@
     return true;
 }
 
-extern "C" jobject Java_android_media_cts_NativeImageReaderTest_\
+extern "C" jobject Java_android_media_misc_cts_NativeImageReaderTest_\
 testCreateSurfaceNative(JNIEnv* env, jclass /*clazz*/) {
     static constexpr uint64_t kTestImageUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
     static constexpr int kTestImageCount = 8;
diff --git a/tests/tests/media/libmediandkjni/native-media-jni.cpp b/tests/tests/media/misc/jni/native-media-jni.cpp
similarity index 88%
rename from tests/tests/media/libmediandkjni/native-media-jni.cpp
rename to tests/tests/media/misc/jni/native-media-jni.cpp
index a38ca17b..8dc8e18 100644
--- a/tests/tests/media/libmediandkjni/native-media-jni.cpp
+++ b/tests/tests/media/misc/jni/native-media-jni.cpp
@@ -31,7 +31,7 @@
 #include "media/NdkMediaDataSource.h"
 #include "media/NdkMediaFormat.h"
 
-extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testFormatNative(JNIEnv * /*env*/,
+extern "C" jboolean Java_android_media_misc_cts_NativeDecoderTest_testFormatNative(JNIEnv * /*env*/,
         jclass /*clazz*/) {
     AMediaFormat* format = AMediaFormat_new();
     if (!format) {
@@ -85,7 +85,7 @@
 }
 
 
-extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testPsshNative(JNIEnv * /*env*/,
+extern "C" jboolean Java_android_media_misc_cts_NativeDecoderTest_testPsshNative(JNIEnv * /*env*/,
         jclass /*clazz*/, int fd, jlong offset, jlong size) {
 
     AMediaExtractor *ex = AMediaExtractor_new();
@@ -126,7 +126,7 @@
     return true;
 }
 
-extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testCryptoInfoNative(JNIEnv * /*env*/,
+extern "C" jboolean Java_android_media_misc_cts_NativeDecoderTest_testCryptoInfoNative(JNIEnv * /*env*/,
         jclass /*clazz*/) {
 
     size_t numsubsamples = 4;
@@ -171,13 +171,13 @@
     return true;
 }
 
-extern "C" jlong Java_android_media_cts_NativeDecoderTest_createAMediaExtractor(JNIEnv * /*env*/,
+extern "C" jlong Java_android_media_misc_cts_NativeDecoderTest_createAMediaExtractor(JNIEnv * /*env*/,
         jclass /*clazz*/) {
     AMediaExtractor *ex = AMediaExtractor_new();
     return reinterpret_cast<jlong>(ex);
 }
 
-extern "C" jlong Java_android_media_cts_NativeDecoderTest_createAMediaDataSource(JNIEnv * env,
+extern "C" jlong Java_android_media_misc_cts_NativeDecoderTest_createAMediaDataSource(JNIEnv * env,
         jclass /*clazz*/, jstring jurl) {
     const char *url = env->GetStringUTFChars(jurl, NULL);
     if (url == NULL) {
@@ -190,29 +190,29 @@
     return reinterpret_cast<jlong>(ds);
 }
 
-extern "C" jint Java_android_media_cts_NativeDecoderTest_setAMediaExtractorDataSource(JNIEnv * /*env*/,
+extern "C" jint Java_android_media_misc_cts_NativeDecoderTest_setAMediaExtractorDataSource(JNIEnv * /*env*/,
         jclass /*clazz*/, jlong jex, jlong jds) {
     AMediaExtractor *ex = reinterpret_cast<AMediaExtractor *>(jex);
     AMediaDataSource *ds = reinterpret_cast<AMediaDataSource *>(jds);
     return AMediaExtractor_setDataSourceCustom(ex, ds);
 }
 
-extern "C" void Java_android_media_cts_NativeDecoderTest_closeAMediaDataSource(
+extern "C" void Java_android_media_misc_cts_NativeDecoderTest_closeAMediaDataSource(
         JNIEnv * /*env*/, jclass /*clazz*/, jlong ds) {
     AMediaDataSource_close(reinterpret_cast<AMediaDataSource *>(ds));
 }
 
-extern "C" void Java_android_media_cts_NativeDecoderTest_deleteAMediaExtractor(
+extern "C" void Java_android_media_misc_cts_NativeDecoderTest_deleteAMediaExtractor(
         JNIEnv * /*env*/, jclass /*clazz*/, jlong ex) {
     AMediaExtractor_delete(reinterpret_cast<AMediaExtractor *>(ex));
 }
 
-extern "C" void Java_android_media_cts_NativeDecoderTest_deleteAMediaDataSource(
+extern "C" void Java_android_media_misc_cts_NativeDecoderTest_deleteAMediaDataSource(
         JNIEnv * /*env*/, jclass /*clazz*/, jlong ds) {
     AMediaDataSource_delete(reinterpret_cast<AMediaDataSource *>(ds));
 }
 
-extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testMediaFormatNative(
+extern "C" jboolean Java_android_media_misc_cts_NativeDecoderTest_testMediaFormatNative(
         JNIEnv * /*env*/, jclass /*clazz*/) {
 
     AMediaFormat *original = AMediaFormat_new();
diff --git a/tests/tests/media/res/drawable/faces.jpg b/tests/tests/media/misc/res/drawable/faces.jpg
similarity index 100%
rename from tests/tests/media/res/drawable/faces.jpg
rename to tests/tests/media/misc/res/drawable/faces.jpg
Binary files differ
diff --git a/tests/tests/media/res/drawable/single_face.jpg b/tests/tests/media/misc/res/drawable/single_face.jpg
similarity index 100%
rename from tests/tests/media/res/drawable/single_face.jpg
rename to tests/tests/media/misc/res/drawable/single_face.jpg
Binary files differ
diff --git a/tests/tests/media/res/raw/a_4.ogg b/tests/tests/media/misc/res/raw/a_4.ogg
similarity index 100%
rename from tests/tests/media/res/raw/a_4.ogg
rename to tests/tests/media/misc/res/raw/a_4.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/a_4_aac.mp4 b/tests/tests/media/misc/res/raw/a_4_aac.mp4
similarity index 100%
rename from tests/tests/media/res/raw/a_4_aac.mp4
rename to tests/tests/media/misc/res/raw/a_4_aac.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/a_4_haptic.ogg b/tests/tests/media/misc/res/raw/a_4_haptic.ogg
similarity index 100%
rename from tests/tests/media/res/raw/a_4_haptic.ogg
rename to tests/tests/media/misc/res/raw/a_4_haptic.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/b_5.ogg b/tests/tests/media/misc/res/raw/b_5.ogg
similarity index 100%
rename from tests/tests/media/res/raw/b_5.ogg
rename to tests/tests/media/misc/res/raw/b_5.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/b_5_aac.mp4 b/tests/tests/media/misc/res/raw/b_5_aac.mp4
similarity index 100%
rename from tests/tests/media/res/raw/b_5_aac.mp4
rename to tests/tests/media/misc/res/raw/b_5_aac.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/b_5_haptic.ogg b/tests/tests/media/misc/res/raw/b_5_haptic.ogg
similarity index 100%
rename from tests/tests/media/res/raw/b_5_haptic.ogg
rename to tests/tests/media/misc/res/raw/b_5_haptic.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/c_sharp_5.ogg b/tests/tests/media/misc/res/raw/c_sharp_5.ogg
similarity index 100%
rename from tests/tests/media/res/raw/c_sharp_5.ogg
rename to tests/tests/media/misc/res/raw/c_sharp_5.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/c_sharp_5_aac.mp4 b/tests/tests/media/misc/res/raw/c_sharp_5_aac.mp4
similarity index 100%
rename from tests/tests/media/res/raw/c_sharp_5_aac.mp4
rename to tests/tests/media/misc/res/raw/c_sharp_5_aac.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/c_sharp_5_haptic.ogg b/tests/tests/media/misc/res/raw/c_sharp_5_haptic.ogg
similarity index 100%
rename from tests/tests/media/res/raw/c_sharp_5_haptic.ogg
rename to tests/tests/media/misc/res/raw/c_sharp_5_haptic.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/e_5.ogg b/tests/tests/media/misc/res/raw/e_5.ogg
similarity index 100%
rename from tests/tests/media/res/raw/e_5.ogg
rename to tests/tests/media/misc/res/raw/e_5.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/e_5_aac.mp4 b/tests/tests/media/misc/res/raw/e_5_aac.mp4
similarity index 100%
rename from tests/tests/media/res/raw/e_5_aac.mp4
rename to tests/tests/media/misc/res/raw/e_5_aac.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/e_5_haptic.ogg b/tests/tests/media/misc/res/raw/e_5_haptic.ogg
similarity index 100%
rename from tests/tests/media/res/raw/e_5_haptic.ogg
rename to tests/tests/media/misc/res/raw/e_5_haptic.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/g_sharp_5.ogg b/tests/tests/media/misc/res/raw/g_sharp_5.ogg
similarity index 100%
rename from tests/tests/media/res/raw/g_sharp_5.ogg
rename to tests/tests/media/misc/res/raw/g_sharp_5.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/g_sharp_5_aac.mp4 b/tests/tests/media/misc/res/raw/g_sharp_5_aac.mp4
similarity index 100%
rename from tests/tests/media/res/raw/g_sharp_5_aac.mp4
rename to tests/tests/media/misc/res/raw/g_sharp_5_aac.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/g_sharp_5_haptic.ogg b/tests/tests/media/misc/res/raw/g_sharp_5_haptic.ogg
similarity index 100%
rename from tests/tests/media/res/raw/g_sharp_5_haptic.ogg
rename to tests/tests/media/misc/res/raw/g_sharp_5_haptic.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/heifwriter_input.heic b/tests/tests/media/misc/res/raw/heifwriter_input.heic
similarity index 100%
rename from tests/tests/media/res/raw/heifwriter_input.heic
rename to tests/tests/media/misc/res/raw/heifwriter_input.heic
Binary files differ
diff --git a/tests/tests/media/res/raw/midi_a.mid b/tests/tests/media/misc/res/raw/midi_a.mid
similarity index 100%
rename from tests/tests/media/res/raw/midi_a.mid
rename to tests/tests/media/misc/res/raw/midi_a.mid
Binary files differ
diff --git a/tests/tests/media/res/raw/midi_b.mid b/tests/tests/media/misc/res/raw/midi_b.mid
similarity index 100%
rename from tests/tests/media/res/raw/midi_b.mid
rename to tests/tests/media/misc/res/raw/midi_b.mid
Binary files differ
diff --git a/tests/tests/media/res/raw/midi_cs.mid b/tests/tests/media/misc/res/raw/midi_cs.mid
similarity index 100%
rename from tests/tests/media/res/raw/midi_cs.mid
rename to tests/tests/media/misc/res/raw/midi_cs.mid
Binary files differ
diff --git a/tests/tests/media/res/raw/midi_e.mid b/tests/tests/media/misc/res/raw/midi_e.mid
similarity index 100%
rename from tests/tests/media/res/raw/midi_e.mid
rename to tests/tests/media/misc/res/raw/midi_e.mid
Binary files differ
diff --git a/tests/tests/media/res/raw/midi_gs.mid b/tests/tests/media/misc/res/raw/midi_gs.mid
similarity index 100%
rename from tests/tests/media/res/raw/midi_gs.mid
rename to tests/tests/media/misc/res/raw/midi_gs.mid
Binary files differ
diff --git a/tests/tests/media/res/raw/sine1khzm40db.wav b/tests/tests/media/misc/res/raw/sine1khzm40db.wav
similarity index 100%
rename from tests/tests/media/res/raw/sine1khzm40db.wav
rename to tests/tests/media/misc/res/raw/sine1khzm40db.wav
Binary files differ
diff --git a/tests/tests/media/res/raw/sine1khzs40dblong.mp3 b/tests/tests/media/misc/res/raw/sine1khzs40dblong.mp3
similarity index 100%
rename from tests/tests/media/res/raw/sine1khzs40dblong.mp3
rename to tests/tests/media/misc/res/raw/sine1khzs40dblong.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/test1m1s.mp3 b/tests/tests/media/misc/res/raw/test1m1s.mp3
similarity index 100%
rename from tests/tests/media/res/raw/test1m1s.mp3
rename to tests/tests/media/misc/res/raw/test1m1s.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/testcanonicalize_localizable_mp3.mp3 b/tests/tests/media/misc/res/raw/testcanonicalize_localizable_mp3.mp3
similarity index 100%
rename from tests/tests/media/res/raw/testcanonicalize_localizable_mp3.mp3
rename to tests/tests/media/misc/res/raw/testcanonicalize_localizable_mp3.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/testcanonicalize_mp3.mp3 b/tests/tests/media/misc/res/raw/testcanonicalize_mp3.mp3
similarity index 100%
rename from tests/tests/media/res/raw/testcanonicalize_mp3.mp3
rename to tests/tests/media/misc/res/raw/testcanonicalize_mp3.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/testmp3.mp3 b/tests/tests/media/misc/res/raw/testmp3.mp3
similarity index 100%
rename from tests/tests/media/res/raw/testmp3.mp3
rename to tests/tests/media/misc/res/raw/testmp3.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/testopus.opus b/tests/tests/media/misc/res/raw/testopus.opus
similarity index 100%
rename from tests/tests/media/res/raw/testopus.opus
rename to tests/tests/media/misc/res/raw/testopus.opus
Binary files differ
diff --git a/tests/tests/media/res/raw/testwav_16bit_44100hz.wav b/tests/tests/media/misc/res/raw/testwav_16bit_44100hz.wav
similarity index 100%
rename from tests/tests/media/res/raw/testwav_16bit_44100hz.wav
rename to tests/tests/media/misc/res/raw/testwav_16bit_44100hz.wav
Binary files differ
diff --git a/tests/tests/media/res/values/exifinterface.xml b/tests/tests/media/misc/res/values/exifinterface.xml
similarity index 100%
rename from tests/tests/media/res/values/exifinterface.xml
rename to tests/tests/media/misc/res/values/exifinterface.xml
diff --git a/tests/tests/media/res/values/strings.xml b/tests/tests/media/misc/res/values/strings.xml
similarity index 100%
rename from tests/tests/media/res/values/strings.xml
rename to tests/tests/media/misc/res/values/strings.xml
diff --git a/tests/tests/media/src/android/media/cts/CamcorderProfileTest.java b/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/CamcorderProfileTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java
index 3eecb04..c00407d 100644
--- a/tests/tests/media/src/android/media/cts/CamcorderProfileTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.content.pm.PackageManager;
 import android.hardware.Camera;
@@ -26,6 +26,7 @@
 import android.media.MediaCodecInfo;
 import android.media.MediaFormat;
 import android.media.MediaRecorder;
+import android.media.cts.NonMediaMainlineTest;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
diff --git a/tests/tests/media/src/android/media/cts/CameraProfileTest.java b/tests/tests/media/misc/src/android/media/misc/cts/CameraProfileTest.java
similarity index 96%
rename from tests/tests/media/src/android/media/cts/CameraProfileTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/CameraProfileTest.java
index 9949c73..1de7a91 100644
--- a/tests/tests/media/src/android/media/cts/CameraProfileTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/CameraProfileTest.java
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 
 import android.hardware.Camera;
 import android.media.CameraProfile;
+import android.media.cts.NonMediaMainlineTest;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
diff --git a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java b/tests/tests/media/misc/src/android/media/misc/cts/ExifInterfaceTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/ExifInterfaceTest.java
index 75ba4b1..22c8bf1 100644
--- a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/ExifInterfaceTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static android.media.ExifInterface.TAG_SUBJECT_AREA;
 
@@ -22,6 +22,8 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.media.ExifInterface;
+import android.media.cts.NonMediaMainlineTest;
+import android.media.cts.Preconditions;
 import android.os.FileUtils;
 import android.os.StrictMode;
 import android.platform.test.annotations.AppModeFull;
diff --git a/tests/tests/media/src/android/media/cts/FaceDetectorStub.java b/tests/tests/media/misc/src/android/media/misc/cts/FaceDetectorStub.java
similarity index 95%
rename from tests/tests/media/src/android/media/cts/FaceDetectorStub.java
rename to tests/tests/media/misc/src/android/media/misc/cts/FaceDetectorStub.java
index 6635fda..ef33f01 100644
--- a/tests/tests/media/src/android/media/cts/FaceDetectorStub.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/FaceDetectorStub.java
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-package android.media.cts;
-
-import android.media.cts.R;
+package android.media.misc.cts;
 
 import android.app.Activity;
 import android.media.FaceDetector.Face;
+
 import android.os.Bundle;
 
 import java.util.List;
diff --git a/tests/tests/media/src/android/media/cts/FaceDetectorTest.java b/tests/tests/media/misc/src/android/media/misc/cts/FaceDetectorTest.java
similarity index 95%
rename from tests/tests/media/src/android/media/cts/FaceDetectorTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/FaceDetectorTest.java
index 94e4e37..f5f24d0 100644
--- a/tests/tests/media/src/android/media/cts/FaceDetectorTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/FaceDetectorTest.java
@@ -14,15 +14,13 @@
  * limitations under the License.
  */
 
-package android.media.cts;
-
-import android.media.cts.R;
-
+package android.media.misc.cts;
 
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.media.FaceDetector;
 import android.media.FaceDetector.Face;
+import android.media.cts.NonMediaMainlineTest;
 import android.test.InstrumentationTestCase;
 
 @NonMediaMainlineTest
diff --git a/tests/tests/media/src/android/media/cts/FaceDetector_FaceTest.java b/tests/tests/media/misc/src/android/media/misc/cts/FaceDetector_FaceTest.java
similarity index 96%
rename from tests/tests/media/src/android/media/cts/FaceDetector_FaceTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/FaceDetector_FaceTest.java
index 7b50040..e32860c 100644
--- a/tests/tests/media/src/android/media/cts/FaceDetector_FaceTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/FaceDetector_FaceTest.java
@@ -14,15 +14,13 @@
  * limitations under the License.
  */
 
-package android.media.cts;
-
-import android.media.cts.R;
-
+package android.media.misc.cts;
 
 import android.content.Intent;
 import android.graphics.PointF;
 import android.media.FaceDetector;
 import android.media.FaceDetector.Face;
+import android.media.cts.NonMediaMainlineTest;
 import android.test.InstrumentationTestCase;
 
 import java.util.List;
diff --git a/tests/tests/media/src/android/media/cts/FaceView.java b/tests/tests/media/misc/src/android/media/misc/cts/FaceView.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/FaceView.java
rename to tests/tests/media/misc/src/android/media/misc/cts/FaceView.java
index 6d3d84b..d928f69a 100644
--- a/tests/tests/media/src/android/media/cts/FaceView.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/FaceView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.content.Context;
 import android.graphics.Bitmap;
diff --git a/tests/tests/media/src/android/media/cts/HandlerExecutor.java b/tests/tests/media/misc/src/android/media/misc/cts/HandlerExecutor.java
similarity index 96%
rename from tests/tests/media/src/android/media/cts/HandlerExecutor.java
rename to tests/tests/media/misc/src/android/media/misc/cts/HandlerExecutor.java
index afeef51e..9b6cf44 100644
--- a/tests/tests/media/src/android/media/cts/HandlerExecutor.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/HandlerExecutor.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.annotation.NonNull;
 import android.os.Handler;
diff --git a/tests/tests/media/src/android/media/cts/HeifWriterTest.java b/tests/tests/media/misc/src/android/media/misc/cts/HeifWriterTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/HeifWriterTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/HeifWriterTest.java
index 40d6128..e855a76 100644
--- a/tests/tests/media/src/android/media/cts/HeifWriterTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/HeifWriterTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static androidx.heifwriter.HeifWriter.INPUT_MODE_BITMAP;
 import static androidx.heifwriter.HeifWriter.INPUT_MODE_BUFFER;
@@ -40,6 +40,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
+import android.media.cts.InputSurface;
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.annotations.RequiresDevice;
diff --git a/tests/tests/media/src/android/media/cts/MediaActivityTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaActivityTest.java
similarity index 96%
rename from tests/tests/media/src/android/media/cts/MediaActivityTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaActivityTest.java
index a03d429..50365dd 100644
--- a/tests/tests/media/src/android/media/cts/MediaActivityTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaActivityTest.java
@@ -14,25 +14,24 @@
  * limitations under the License
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static junit.framework.Assert.assertEquals;
 
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.testng.Assert.assertFalse;
+import static org.junit.Assert.fail;
 
 import android.Manifest;
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.hardware.hdmi.HdmiControlManager;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
+import android.media.cts.NonMediaMainlineTest;
 import android.media.session.MediaSession;
 import android.os.Handler;
 import android.os.Looper;
@@ -101,9 +100,8 @@
             Manifest.permission.HDMI_CEC);
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mContext = mInstrumentation.getContext();
-        mUseFixedVolume = mContext.getResources().getBoolean(
-                Resources.getSystem().getIdentifier("config_useFixedVolume", "bool", "android"));
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        mUseFixedVolume = mAudioManager.isVolumeFixed();
         mHdmiControlManager = mContext.getSystemService(HdmiControlManager.class);
         if (mHdmiControlManager != null) {
             mHdmiEnableStatus = mHdmiControlManager.getHdmiCecEnabled();
@@ -174,6 +172,7 @@
     @Test
     public void testVolumeKey_whileSessionAlive() throws Exception {
         if (mUseFixedVolume) {
+            Log.i(TAG, "testVolumeKey_whileSessionAlive skipped due to full volume device");
             return;
         }
 
@@ -202,6 +201,7 @@
     @Test
     public void testVolumeKey_afterSessionReleased() throws Exception {
         if (mUseFixedVolume) {
+            Log.i(TAG, "testVolumeKey_afterSessionReleased skipped due to full volume device");
             return;
         }
 
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaBrowserServiceTest.java
similarity index 94%
rename from tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaBrowserServiceTest.java
index 7203df4..f8c8418 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaBrowserServiceTest.java
@@ -13,22 +13,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.cts;
+package android.media.misc.cts;
 
 import static android.media.browse.MediaBrowser.MediaItem.FLAG_PLAYABLE;
-import static android.media.cts.MediaBrowserServiceTestService.KEY_PARENT_MEDIA_ID;
-import static android.media.cts.MediaBrowserServiceTestService.KEY_SERVICE_COMPONENT_NAME;
-import static android.media.cts.MediaBrowserServiceTestService.TEST_SERIES_OF_NOTIFY_CHILDREN_CHANGED;
-import static android.media.cts.MediaSessionTestService.KEY_EXPECTED_TOTAL_NUMBER_OF_ITEMS;
-import static android.media.cts.MediaSessionTestService.STEP_CHECK;
-import static android.media.cts.MediaSessionTestService.STEP_CLEAN_UP;
-import static android.media.cts.MediaSessionTestService.STEP_SET_UP;
+import static android.media.misc.cts.MediaBrowserServiceTestService.KEY_PARENT_MEDIA_ID;
+import static android.media.misc.cts.MediaBrowserServiceTestService.KEY_SERVICE_COMPONENT_NAME;
+import static android.media.misc.cts.MediaBrowserServiceTestService.TEST_SERIES_OF_NOTIFY_CHILDREN_CHANGED;
+import static android.media.misc.cts.MediaSessionTestService.KEY_EXPECTED_TOTAL_NUMBER_OF_ITEMS;
+import static android.media.misc.cts.MediaSessionTestService.STEP_CHECK;
+import static android.media.misc.cts.MediaSessionTestService.STEP_CLEAN_UP;
+import static android.media.misc.cts.MediaSessionTestService.STEP_SET_UP;
 import static android.media.cts.Utils.compareRemoteUserInfo;
 
 import android.content.ComponentName;
 import android.media.MediaDescription;
 import android.media.browse.MediaBrowser;
 import android.media.browse.MediaBrowser.MediaItem;
+import android.media.cts.NonMediaMainlineTest;
 import android.media.session.MediaSessionManager.RemoteUserInfo;
 import android.os.Bundle;
 import android.os.Process;
@@ -52,7 +53,7 @@
     private static final long TIME_OUT_MS = 3000L;
     private static final long WAIT_TIME_FOR_NO_RESPONSE_MS = 500L;
     private static final ComponentName TEST_BROWSER_SERVICE = new ComponentName(
-            "android.media.cts", "android.media.cts.StubMediaBrowserService");
+            "android.media.misc.cts", "android.media.misc.cts.StubMediaBrowserService");
 
     private final TestCountDownLatch mOnChildrenLoadedLatch = new TestCountDownLatch();
     private final TestCountDownLatch mOnChildrenLoadedWithOptionsLatch = new TestCountDownLatch();
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTestService.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaBrowserServiceTestService.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/MediaBrowserServiceTestService.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaBrowserServiceTestService.java
index 0db43d9..e1868823 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTestService.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaBrowserServiceTestService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertTrue;
 
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaBrowserTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaBrowserTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaBrowserTest.java
index 8f3d299..8ab1b2b 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaBrowserTest.java
@@ -13,11 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.content.ComponentName;
 import android.media.browse.MediaBrowser;
 import android.media.browse.MediaBrowser.MediaItem;
+import android.media.cts.NonMediaMainlineTest;
 import android.os.Bundle;
 import android.test.InstrumentationTestCase;
 
@@ -46,7 +47,7 @@
      */
     private static final long SLEEP_MS = 100L;
     private static final ComponentName TEST_BROWSER_SERVICE = new ComponentName(
-            "android.media.cts", "android.media.cts.StubMediaBrowserService");
+            "android.media.misc.cts", "android.media.misc.cts.StubMediaBrowserService");
     private static final ComponentName TEST_INVALID_BROWSER_SERVICE = new ComponentName(
             "invalid.package", "invalid.ServiceClassName");
     private final StubConnectionCallback mConnectionCallback = new StubConnectionCallback();
diff --git a/tests/tests/media/src/android/media/cts/MediaButtonBroadcastReceiver.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaButtonBroadcastReceiver.java
similarity index 97%
rename from tests/tests/media/src/android/media/cts/MediaButtonBroadcastReceiver.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaButtonBroadcastReceiver.java
index 1d320d8..e07394f 100644
--- a/tests/tests/media/src/android/media/cts/MediaButtonBroadcastReceiver.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaButtonBroadcastReceiver.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertEquals;
 
diff --git a/tests/tests/media/src/android/media/cts/MediaButtonReceiverService.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaButtonReceiverService.java
similarity index 97%
rename from tests/tests/media/src/android/media/cts/MediaButtonReceiverService.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaButtonReceiverService.java
index def8cee..2e37e95 100644
--- a/tests/tests/media/src/android/media/cts/MediaButtonReceiverService.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaButtonReceiverService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertEquals;
 
diff --git a/tests/tests/media/src/android/media/cts/MediaCasTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaCasTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaCasTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaCasTest.java
index a5ab09b..dc2a2e8 100644
--- a/tests/tests/media/src/android/media/cts/MediaCasTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaCasTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.media.MediaCas;
 import android.media.MediaCas.PluginDescriptor;
@@ -24,7 +24,6 @@
 import android.media.MediaCasStateException;
 import android.media.MediaCodec;
 import android.media.MediaDescrambler;
-import android.media.cts.R;
 import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaCodecListTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaCodecListTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaCodecListTest.java
index 19621ec..4b36407 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaCodecListTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_SecurePlayback;
 import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_TunneledPlayback;
diff --git a/tests/tests/media/src/android/media/cts/MediaCommunicationManagerTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaCommunicationManagerTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaCommunicationManagerTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaCommunicationManagerTest.java
index 9fde336..cc5c3c1 100644
--- a/tests/tests/media/src/android/media/cts/MediaCommunicationManagerTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaCommunicationManagerTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
diff --git a/tests/tests/media/src/android/media/cts/MediaController2Test.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaController2Test.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaController2Test.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaController2Test.java
index 36085d9..1025109 100644
--- a/tests/tests/media/src/android/media/cts/MediaController2Test.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaController2Test.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
diff --git a/tests/tests/media/src/android/media/cts/MediaControllerTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaControllerTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaControllerTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaControllerTest.java
index 0fc6a5f..a44cd2c 100644
--- a/tests/tests/media/src/android/media/cts/MediaControllerTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaControllerTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.cts;
+package android.media.misc.cts;
 
 import static android.media.cts.Utils.compareRemoteUserInfo;
 import static android.media.session.PlaybackState.STATE_PLAYING;
@@ -24,6 +24,7 @@
 import android.media.AudioManager;
 import android.media.Rating;
 import android.media.VolumeProvider;
+import android.media.cts.NonMediaMainlineTest;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager.RemoteUserInfo;
diff --git a/tests/tests/media/src/android/media/cts/MediaFormatTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaFormatTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaFormatTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaFormatTest.java
index ff7259a..86000f6 100644
--- a/tests/tests/media/src/android/media/cts/MediaFormatTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaFormatTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.annotation.NonNull;
 import android.media.MediaFormat;
diff --git a/tests/tests/media/src/android/media/cts/MediaItemTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaItemTest.java
similarity index 97%
rename from tests/tests/media/src/android/media/cts/MediaItemTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaItemTest.java
index 75235c9..747954b 100644
--- a/tests/tests/media/src/android/media/cts/MediaItemTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaItemTest.java
@@ -13,10 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.media.MediaDescription;
 import android.media.browse.MediaBrowser.MediaItem;
+import android.media.cts.NonMediaMainlineTest;
 import android.os.Parcel;
 import android.test.AndroidTestCase;
 import android.text.TextUtils;
diff --git a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaMetadataRetrieverTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaMetadataRetrieverTest.java
index 20d0f50..70bf2b4 100644
--- a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaMetadataRetrieverTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static android.media.MediaMetadataRetriever.OPTION_CLOSEST;
 import static android.media.MediaMetadataRetriever.OPTION_CLOSEST_SYNC;
@@ -32,6 +32,10 @@
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.media.MediaMetadataRetriever;
+import android.media.cts.CodecUtils;
+import android.media.cts.Preconditions;
+import android.media.cts.TestMediaDataSource;
+import android.media.cts.TestUtils;
 import android.os.ParcelFileDescriptor;
 import android.net.Uri;
 import android.os.Build;
diff --git a/tests/tests/media/src/android/media/cts/MediaMetadataTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaMetadataTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaMetadataTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaMetadataTest.java
index ed7e0a3..9c00be6 100644
--- a/tests/tests/media/src/android/media/cts/MediaMetadataTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaMetadataTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -24,6 +24,7 @@
 import android.media.MediaDescription;
 import android.media.MediaMetadata;
 import android.media.Rating;
+import android.media.cts.NonMediaMainlineTest;
 import android.os.Parcel;
 import android.text.TextUtils;
 
diff --git a/tests/tests/media/src/android/media/cts/MediaMetricsTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaMetricsTest.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/MediaMetricsTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaMetricsTest.java
index 7898b2d..5120922 100644
--- a/tests/tests/media/src/android/media/cts/MediaMetricsTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaMetricsTest.java
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertEquals;
 
 import android.media.MediaMetrics;
+import android.media.cts.NonMediaMainlineTest;
 import android.os.Bundle;
 import android.os.Process;
 import androidx.test.runner.AndroidJUnit4;
diff --git a/tests/tests/media/src/android/media/cts/MediaProjectionTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaProjectionTest.java
similarity index 96%
rename from tests/tests/media/src/android/media/cts/MediaProjectionTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaProjectionTest.java
index 1b7e3d41..351338c 100644
--- a/tests/tests/media/src/android/media/cts/MediaProjectionTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaProjectionTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.cts;
+package android.media.misc.cts;
 
 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
 
@@ -22,6 +22,8 @@
 
 import android.app.ActivityManager;
 import android.content.Context;
+import android.media.cts.NonMediaMainlineTest;
+import android.media.cts.MediaProjectionActivity;
 import android.media.projection.MediaProjection;
 import android.os.Handler;
 import android.os.Looper;
diff --git a/tests/tests/media/src/android/media/cts/MediaRoute2InfoTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaRoute2InfoTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaRoute2InfoTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaRoute2InfoTest.java
index bf75ec8..94d5883 100644
--- a/tests/tests/media/src/android/media/cts/MediaRoute2InfoTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaRoute2InfoTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -25,6 +25,7 @@
 import static org.testng.Assert.assertThrows;
 
 import android.media.MediaRoute2Info;
+import android.media.cts.NonMediaMainlineTest;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
diff --git a/tests/tests/media/src/android/media/cts/MediaRoute2ProviderServiceTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaRoute2ProviderServiceTest.java
similarity index 96%
rename from tests/tests/media/src/android/media/cts/MediaRoute2ProviderServiceTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaRoute2ProviderServiceTest.java
index 0a75047..531a2f2 100644
--- a/tests/tests/media/src/android/media/cts/MediaRoute2ProviderServiceTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaRoute2ProviderServiceTest.java
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
-import static android.media.cts.MediaRouter2Test.releaseControllers;
-import static android.media.cts.StubMediaRoute2ProviderService.FEATURE_SAMPLE;
-import static android.media.cts.StubMediaRoute2ProviderService.FEATURE_SPECIAL;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID1;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID2;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID4_TO_SELECT_AND_DESELECT;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
+import static android.media.misc.cts.MediaRouter2Test.releaseControllers;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.FEATURE_SAMPLE;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.FEATURE_SPECIAL;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID1;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID2;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID4_TO_SELECT_AND_DESELECT;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -40,7 +40,8 @@
 import android.media.MediaRouter2.TransferCallback;
 import android.media.RouteDiscoveryPreference;
 import android.media.RoutingSessionInfo;
-import android.media.cts.StubMediaRoute2ProviderService.Proxy;
+import android.media.cts.NonMediaMainlineTest;
+import android.media.misc.cts.StubMediaRoute2ProviderService.Proxy;
 import android.os.Bundle;
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.LargeTest;
diff --git a/tests/tests/media/src/android/media/cts/MediaRouter2Test.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2Test.java
similarity index 97%
rename from tests/tests/media/src/android/media/cts/MediaRouter2Test.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2Test.java
index b20a294..05cedf3 100644
--- a/tests/tests/media/src/android/media/cts/MediaRouter2Test.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2Test.java
@@ -14,19 +14,20 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static android.content.Context.AUDIO_SERVICE;
 import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
 import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
-import static android.media.cts.StubMediaRoute2ProviderService.FEATURES_SPECIAL;
-import static android.media.cts.StubMediaRoute2ProviderService.FEATURE_SAMPLE;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID1;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID2;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID3_SESSION_CREATION_FAILED;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID4_TO_SELECT_AND_DESELECT;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID_SPECIAL_FEATURE;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.FEATURES_ALL;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.FEATURES_SPECIAL;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.FEATURE_SAMPLE;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID1;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID2;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID3_SESSION_CREATION_FAILED;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID4_TO_SELECT_AND_DESELECT;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID_SPECIAL_FEATURE;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -49,6 +50,7 @@
 import android.media.MediaRouter2.RoutingController;
 import android.media.MediaRouter2.TransferCallback;
 import android.media.RouteDiscoveryPreference;
+import android.media.cts.NonMediaMainlineTest;
 import android.os.Bundle;
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.LargeTest;
diff --git a/tests/tests/media/src/android/media/cts/MediaRouter2TestActivity.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2TestActivity.java
similarity index 97%
rename from tests/tests/media/src/android/media/cts/MediaRouter2TestActivity.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2TestActivity.java
index e0ba399..76eb1c9 100644
--- a/tests/tests/media/src/android/media/cts/MediaRouter2TestActivity.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2TestActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.app.Activity;
 import android.content.Context;
diff --git a/tests/tests/media/src/android/media/cts/MediaRouterTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaRouterTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaRouterTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaRouterTest.java
index 5d9908f..aa66932 100644
--- a/tests/tests/media/src/android/media/cts/MediaRouterTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaRouterTest.java
@@ -13,9 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.cts;
-
-import android.media.cts.R;
+package android.media.misc.cts;
 
 import android.app.PendingIntent;
 import android.content.Context;
@@ -30,6 +28,7 @@
 import android.media.MediaRouter.RouteInfo;
 import android.media.MediaRouter.UserRouteInfo;
 import android.media.RemoteControlClient;
+import android.media.cts.NonMediaMainlineTest;
 import android.platform.test.annotations.AppModeFull;
 import android.test.InstrumentationTestCase;
 
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaScannerConnectionTest.java
similarity index 97%
rename from tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaScannerConnectionTest.java
index 574ef2e..f03ae97 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaScannerConnectionTest.java
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.content.ComponentName;
 import android.content.Context;
 import android.media.MediaScannerConnection;
 import android.media.MediaScannerConnection.MediaScannerConnectionClient;
+import android.media.cts.NonMediaMainlineTest;
 import android.net.Uri;
 import android.os.IBinder;
 import android.platform.test.annotations.AppModeFull;
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerNotificationTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaScannerNotificationTest.java
similarity index 97%
rename from tests/tests/media/src/android/media/cts/MediaScannerNotificationTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaScannerNotificationTest.java
index 77f3d58..96ec5e6 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerNotificationTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaScannerNotificationTest.java
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.media.cts.NonMediaMainlineTest;
 import android.os.Environment;
 import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaScannerTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaScannerTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaScannerTest.java
index f984381..1794eba 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaScannerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.app.UiAutomation;
 import android.content.ComponentName;
@@ -25,6 +25,8 @@
 import android.media.MediaMetadataRetriever;
 import android.media.MediaScannerConnection;
 import android.media.MediaScannerConnection.MediaScannerConnectionClient;
+import android.media.cts.NonMediaMainlineTest;
+import android.media.cts.Preconditions;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Environment;
diff --git a/tests/tests/media/src/android/media/cts/MediaSession2ServiceTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaSession2ServiceTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaSession2ServiceTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaSession2ServiceTest.java
index 579d0a2..d031b9e 100644
--- a/tests/tests/media/src/android/media/cts/MediaSession2ServiceTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaSession2ServiceTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -34,6 +34,7 @@
 import android.media.MediaSession2Service;
 import android.media.Session2CommandGroup;
 import android.media.Session2Token;
+import android.media.cts.TestUtils;
 import android.os.Bundle;
 import android.os.HandlerThread;
 import android.os.Process;
diff --git a/tests/tests/media/src/android/media/cts/MediaSession2Test.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaSession2Test.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaSession2Test.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaSession2Test.java
index 6ee8bd4..85cfa46 100644
--- a/tests/tests/media/src/android/media/cts/MediaSession2Test.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaSession2Test.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
@@ -35,6 +35,7 @@
 import android.media.Session2Command;
 import android.media.Session2CommandGroup;
 import android.media.Session2Token;
+import android.media.cts.TestUtils;
 import android.media.session.MediaSessionManager;
 import android.os.Bundle;
 import android.os.Handler;
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaSessionManagerTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaSessionManagerTest.java
index 3349206..05306f5 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaSessionManagerTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.Manifest;
 import android.content.ComponentName;
@@ -25,6 +25,8 @@
 import android.media.MediaSession2;
 import android.media.Session2CommandGroup;
 import android.media.Session2Token;
+import android.media.cts.NonMediaMainlineTest;
+import android.media.cts.Utils;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager;
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaSessionTest.java
similarity index 97%
rename from tests/tests/media/src/android/media/cts/MediaSessionTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaSessionTest.java
index 04f2662..6edadaa 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaSessionTest.java
@@ -13,17 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.cts;
+package android.media.misc.cts;
 
 import static android.media.AudioAttributes.USAGE_GAME;
-import static android.media.cts.MediaSessionTestService.KEY_EXPECTED_QUEUE_SIZE;
-import static android.media.cts.MediaSessionTestService.KEY_EXPECTED_TOTAL_NUMBER_OF_ITEMS;
-import static android.media.cts.MediaSessionTestService.KEY_SESSION_TOKEN;
-import static android.media.cts.MediaSessionTestService.STEP_CHECK;
-import static android.media.cts.MediaSessionTestService.STEP_CLEAN_UP;
-import static android.media.cts.MediaSessionTestService.STEP_SET_UP;
-import static android.media.cts.MediaSessionTestService.TEST_SERIES_OF_SET_QUEUE;
-import static android.media.cts.MediaSessionTestService.TEST_SET_QUEUE;
+import static android.media.misc.cts.MediaSessionTestService.KEY_EXPECTED_QUEUE_SIZE;
+import static android.media.misc.cts.MediaSessionTestService.KEY_EXPECTED_TOTAL_NUMBER_OF_ITEMS;
+import static android.media.misc.cts.MediaSessionTestService.KEY_SESSION_TOKEN;
+import static android.media.misc.cts.MediaSessionTestService.STEP_CHECK;
+import static android.media.misc.cts.MediaSessionTestService.STEP_CLEAN_UP;
+import static android.media.misc.cts.MediaSessionTestService.STEP_SET_UP;
+import static android.media.misc.cts.MediaSessionTestService.TEST_SERIES_OF_SET_QUEUE;
+import static android.media.misc.cts.MediaSessionTestService.TEST_SET_QUEUE;
 import static android.media.cts.Utils.compareRemoteUserInfo;
 
 import android.app.PendingIntent;
@@ -37,6 +37,8 @@
 import android.media.MediaSession2;
 import android.media.Rating;
 import android.media.VolumeProvider;
+import android.media.cts.NonMediaMainlineTest;
+import android.media.cts.Utils;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.MediaSession.QueueItem;
@@ -402,7 +404,7 @@
      */
     public void testSetMediaButtonReceiver_implicitIntent() throws Exception {
         // Note: No such broadcast receiver exists.
-        Intent intent = new Intent("android.media.cts.ACTION_MEDIA_TEST");
+        Intent intent = new Intent("android.media.misc.cts.ACTION_MEDIA_TEST");
         PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent,
                 PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionTestActivity.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaSessionTestActivity.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/MediaSessionTestActivity.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaSessionTestActivity.java
index 90f7247..5967418 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionTestActivity.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaSessionTestActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.fail;
 
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionTestService.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaSessionTestService.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaSessionTestService.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaSessionTestService.java
index 08476ba..88ae926 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionTestService.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaSessionTestService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertTrue;
 
diff --git a/tests/tests/media/src/android/media/cts/MediaSyncTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaSyncTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaSyncTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaSyncTest.java
index 0e2562a..94529bf 100644
--- a/tests/tests/media/src/android/media/cts/MediaSyncTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaSyncTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -27,6 +27,9 @@
 import android.media.MediaTimestamp;
 import android.media.PlaybackParams;
 import android.media.SyncParams;
+import android.media.cts.NonMediaMainlineTest;
+import android.media.cts.MediaStubActivity;
+import android.media.cts.Preconditions;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.platform.test.annotations.AppModeFull;
diff --git a/tests/tests/media/src/android/media/cts/MediaTimestampTest.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaTimestampTest.java
similarity index 93%
rename from tests/tests/media/src/android/media/cts/MediaTimestampTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MediaTimestampTest.java
index 78fd1375..82cad3b 100644
--- a/tests/tests/media/src/android/media/cts/MediaTimestampTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaTimestampTest.java
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.media.MediaTimestamp;
+import android.media.cts.NonMediaMainlineTest;
 import android.test.AndroidTestCase;
 
 /**
diff --git a/tests/tests/media/src/android/media/cts/MockActivity.java b/tests/tests/media/misc/src/android/media/misc/cts/MockActivity.java
similarity index 95%
rename from tests/tests/media/src/android/media/cts/MockActivity.java
rename to tests/tests/media/misc/src/android/media/misc/cts/MockActivity.java
index 028cfae..0b90cf0 100644
--- a/tests/tests/media/src/android/media/cts/MockActivity.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MockActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.app.Activity;
 
diff --git a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java b/tests/tests/media/misc/src/android/media/misc/cts/NativeDecoderTest.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/NativeDecoderTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/NativeDecoderTest.java
index c0330cb..c79e9bd 100644
--- a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/NativeDecoderTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -28,6 +28,8 @@
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.media.MediaPlayer;
+import android.media.cts.MediaTestBase;
+import android.media.cts.Preconditions;
 import android.media.cts.TestUtils.Monitor;
 import android.net.Uri;
 import android.os.Build;
@@ -88,7 +90,7 @@
     static {
         // Load jni on initialization.
         Log.i("@@@", "before loadlibrary");
-        System.loadLibrary("ctsmediacodec_jni");
+        System.loadLibrary("ctsmediamisc_jni");
         Log.i("@@@", "after loadlibrary");
     }
 
diff --git a/tests/tests/media/src/android/media/cts/NativeImageReaderTest.java b/tests/tests/media/misc/src/android/media/misc/cts/NativeImageReaderTest.java
similarity index 95%
rename from tests/tests/media/src/android/media/cts/NativeImageReaderTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/NativeImageReaderTest.java
index 5de309a..17be6e5 100644
--- a/tests/tests/media/src/android/media/cts/NativeImageReaderTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/NativeImageReaderTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
@@ -32,7 +32,7 @@
     /** Load jni on initialization */
     static {
         Log.i("NativeImageReaderTest", "before loadlibrary");
-        System.loadLibrary("ctsimagereader_jni");
+        System.loadLibrary("ctsmediamisc_jni");
         Log.i("NativeImageReaderTest", "after loadlibrary");
     }
 
diff --git a/tests/tests/media/src/android/media/cts/ParamsTest.java b/tests/tests/media/misc/src/android/media/misc/cts/ParamsTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/ParamsTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/ParamsTest.java
index adbad8d..69b3032 100644
--- a/tests/tests/media/src/android/media/cts/ParamsTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/ParamsTest.java
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
-
-import android.media.cts.R;
+package android.media.misc.cts;
 
 import android.media.PlaybackParams;
 import android.media.SyncParams;
diff --git a/tests/tests/media/src/android/media/cts/PlaybackStateTest.java b/tests/tests/media/misc/src/android/media/misc/cts/PlaybackStateTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/PlaybackStateTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/PlaybackStateTest.java
index d8b4aec..1b07854 100644
--- a/tests/tests/media/src/android/media/cts/PlaybackStateTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/PlaybackStateTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
diff --git a/tests/tests/media/src/android/media/cts/PresentationSyncTest.java b/tests/tests/media/misc/src/android/media/misc/cts/PresentationSyncTest.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/PresentationSyncTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/PresentationSyncTest.java
index 25d6adb..1d0bd0c 100644
--- a/tests/tests/media/src/android/media/cts/PresentationSyncTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/PresentationSyncTest.java
@@ -14,13 +14,16 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.opengl.GLES20;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Trace;
+import android.media.cts.InputSurface;
+import android.media.cts.MediaStubActivity;
+import android.media.cts.NonMediaMainlineTest;
 import android.platform.test.annotations.AppModeFull;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.Suppress;
diff --git a/tests/tests/media/src/android/media/cts/RatingTest.java b/tests/tests/media/misc/src/android/media/misc/cts/RatingTest.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/RatingTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/RatingTest.java
index 4b8857a..9b6975a 100644
--- a/tests/tests/media/src/android/media/cts/RatingTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/RatingTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static android.media.Rating.RATING_3_STARS;
 import static android.media.Rating.RATING_4_STARS;
@@ -32,6 +32,7 @@
 
 import android.media.Rating;
 import android.os.Parcel;
+import android.media.cts.NonMediaMainlineTest;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
diff --git a/tests/tests/media/src/android/media/cts/RemoteControllerTest.java b/tests/tests/media/misc/src/android/media/misc/cts/RemoteControllerTest.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/RemoteControllerTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/RemoteControllerTest.java
index a7d9f72..4eaa04a 100644
--- a/tests/tests/media/src/android/media/cts/RemoteControllerTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/RemoteControllerTest.java
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.content.Context;
 import android.media.RemoteController;
 import android.media.RemoteController.OnClientUpdateListener;
+import android.media.cts.NonMediaMainlineTest;
 import android.platform.test.annotations.AppModeFull;
 import android.test.InstrumentationTestCase;
 import android.test.UiThreadTest;
diff --git a/tests/tests/media/src/android/media/cts/RemoteService.java b/tests/tests/media/misc/src/android/media/misc/cts/RemoteService.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/RemoteService.java
rename to tests/tests/media/misc/src/android/media/misc/cts/RemoteService.java
index 0d98251..357d241 100644
--- a/tests/tests/media/src/android/media/cts/RemoteService.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/RemoteService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertTrue;
 
diff --git a/tests/tests/media/src/android/media/cts/ResourceManagerStubActivity.java b/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerStubActivity.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/ResourceManagerStubActivity.java
rename to tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerStubActivity.java
index 5595800..1503cd1 100644
--- a/tests/tests/media/src/android/media/cts/ResourceManagerStubActivity.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerStubActivity.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.app.Activity;
 import android.content.Context;
diff --git a/tests/tests/media/src/android/media/cts/ResourceManagerTest.java b/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTest.java
similarity index 92%
rename from tests/tests/media/src/android/media/cts/ResourceManagerTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTest.java
index 115701b..5a9575f 100644
--- a/tests/tests/media/src/android/media/cts/ResourceManagerTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.os.Bundle;
 import android.platform.test.annotations.AppModeFull;
@@ -30,13 +30,13 @@
         extends ActivityInstrumentationTestCase2<ResourceManagerStubActivity> {
 
     public ResourceManagerTest() {
-        super("android.media.cts", ResourceManagerStubActivity.class);
+        super("android.media.misc.cts", ResourceManagerStubActivity.class);
     }
 
     private void doTestReclaimResource(int type1, int type2) throws Exception {
         Bundle extras = new Bundle();
         ResourceManagerStubActivity activity = launchActivity(
-                "android.media.cts", ResourceManagerStubActivity.class, extras);
+                "android.media.misc.cts", ResourceManagerStubActivity.class, extras);
         activity.testReclaimResource(type1, type2);
         activity.finish();
     }
diff --git a/tests/tests/media/src/android/media/cts/ResourceManagerTestActivity1.java b/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTestActivity1.java
similarity index 97%
rename from tests/tests/media/src/android/media/cts/ResourceManagerTestActivity1.java
rename to tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTestActivity1.java
index a11d773..b1f1178 100644
--- a/tests/tests/media/src/android/media/cts/ResourceManagerTestActivity1.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTestActivity1.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/media/src/android/media/cts/ResourceManagerTestActivity2.java b/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTestActivity2.java
similarity index 96%
rename from tests/tests/media/src/android/media/cts/ResourceManagerTestActivity2.java
rename to tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTestActivity2.java
index ea0567f..b725e62 100644
--- a/tests/tests/media/src/android/media/cts/ResourceManagerTestActivity2.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTestActivity2.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/tests/tests/media/src/android/media/cts/ResourceManagerTestActivityBase.java b/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTestActivityBase.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/ResourceManagerTestActivityBase.java
rename to tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTestActivityBase.java
index 76c7b0f..664fba4 100644
--- a/tests/tests/media/src/android/media/cts/ResourceManagerTestActivityBase.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/ResourceManagerTestActivityBase.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.app.Activity;
 import android.media.MediaCodec;
diff --git a/tests/tests/media/src/android/media/cts/RouteDiscoveryPreferenceTest.java b/tests/tests/media/misc/src/android/media/misc/cts/RouteDiscoveryPreferenceTest.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/RouteDiscoveryPreferenceTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/RouteDiscoveryPreferenceTest.java
index 2891d4a..68a5725 100644
--- a/tests/tests/media/src/android/media/cts/RouteDiscoveryPreferenceTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/RouteDiscoveryPreferenceTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -23,6 +23,7 @@
 import static org.testng.Assert.assertThrows;
 
 import android.media.RouteDiscoveryPreference;
+import android.media.cts.NonMediaMainlineTest;
 import android.os.Parcel;
 
 import org.junit.Test;
diff --git a/tests/tests/media/src/android/media/cts/RoutingSessionInfoTest.java b/tests/tests/media/misc/src/android/media/misc/cts/RoutingSessionInfoTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/RoutingSessionInfoTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/RoutingSessionInfoTest.java
index 3ff5e24..17b0774 100644
--- a/tests/tests/media/src/android/media/cts/RoutingSessionInfoTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/RoutingSessionInfoTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
 
@@ -25,6 +25,7 @@
 import static org.testng.Assert.assertThrows;
 
 import android.media.RoutingSessionInfo;
+import android.media.cts.NonMediaMainlineTest;
 import android.os.Bundle;
 import android.os.Parcel;
 
diff --git a/tests/tests/media/src/android/media/cts/ScannerNotificationReceiver.java b/tests/tests/media/misc/src/android/media/misc/cts/ScannerNotificationReceiver.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/ScannerNotificationReceiver.java
rename to tests/tests/media/misc/src/android/media/misc/cts/ScannerNotificationReceiver.java
index 9d91671..bdc89b2 100644
--- a/tests/tests/media/src/android/media/cts/ScannerNotificationReceiver.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/ScannerNotificationReceiver.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
diff --git a/tests/tests/media/src/android/media/cts/Session2CommandGroupTest.java b/tests/tests/media/misc/src/android/media/misc/cts/Session2CommandGroupTest.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/Session2CommandGroupTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/Session2CommandGroupTest.java
index 988ea87..c6239fb 100644
--- a/tests/tests/media/src/android/media/cts/Session2CommandGroupTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/Session2CommandGroupTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
diff --git a/tests/tests/media/src/android/media/cts/Session2CommandTest.java b/tests/tests/media/misc/src/android/media/misc/cts/Session2CommandTest.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/Session2CommandTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/Session2CommandTest.java
index 91de258..36a22bc 100644
--- a/tests/tests/media/src/android/media/cts/Session2CommandTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/Session2CommandTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
diff --git a/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java b/tests/tests/media/misc/src/android/media/misc/cts/StubMediaBrowserService.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/StubMediaBrowserService.java
rename to tests/tests/media/misc/src/android/media/misc/cts/StubMediaBrowserService.java
index f9ec34c..f96adfc 100644
--- a/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/StubMediaBrowserService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.annotation.NonNull;
 import android.media.MediaDescription;
diff --git a/tests/tests/media/src/android/media/cts/StubMediaRoute2ProviderService.java b/tests/tests/media/misc/src/android/media/misc/cts/StubMediaRoute2ProviderService.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/StubMediaRoute2ProviderService.java
rename to tests/tests/media/misc/src/android/media/misc/cts/StubMediaRoute2ProviderService.java
index efe4859..b9d17e8 100644
--- a/tests/tests/media/src/android/media/cts/StubMediaRoute2ProviderService.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/StubMediaRoute2ProviderService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
 import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
@@ -69,8 +69,8 @@
     public static final String ROUTE_ID_VARIABLE_VOLUME = "route_variable_volume";
     public static final String ROUTE_NAME_VARIABLE_VOLUME = "Variable Volume Route";
 
-    public static final String FEATURE_SAMPLE = "android.media.cts.FEATURE_SAMPLE";
-    public static final String FEATURE_SPECIAL = "android.media.cts.FEATURE_SPECIAL";
+    public static final String FEATURE_SAMPLE = "android.media.misc.cts.FEATURE_SAMPLE";
+    public static final String FEATURE_SPECIAL = "android.media.misc.cts.FEATURE_SPECIAL";
 
     public static final List<String> FEATURES_ALL = new ArrayList();
     public static final List<String> FEATURES_SPECIAL = new ArrayList();
diff --git a/tests/tests/media/src/android/media/cts/StubMediaSession2Service.java b/tests/tests/media/misc/src/android/media/misc/cts/StubMediaSession2Service.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/StubMediaSession2Service.java
rename to tests/tests/media/misc/src/android/media/misc/cts/StubMediaSession2Service.java
index 687910c..852a0fe 100644
--- a/tests/tests/media/src/android/media/cts/StubMediaSession2Service.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/StubMediaSession2Service.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.media.MediaSession2;
 import android.media.MediaSession2.ControllerInfo;
diff --git a/tests/tests/media/src/android/media/cts/SubtitleDataTest.java b/tests/tests/media/misc/src/android/media/misc/cts/SubtitleDataTest.java
similarity index 94%
rename from tests/tests/media/src/android/media/cts/SubtitleDataTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/SubtitleDataTest.java
index 9cd4144..d2b6686 100644
--- a/tests/tests/media/src/android/media/cts/SubtitleDataTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/SubtitleDataTest.java
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.media.SubtitleData;
+import android.media.cts.NonMediaMainlineTest;
 import android.test.AndroidTestCase;
 
 import java.nio.charset.StandardCharsets;
diff --git a/tests/tests/media/src/android/media/cts/SystemMediaRouter2Test.java b/tests/tests/media/misc/src/android/media/misc/cts/SystemMediaRouter2Test.java
similarity index 97%
rename from tests/tests/media/src/android/media/cts/SystemMediaRouter2Test.java
rename to tests/tests/media/misc/src/android/media/misc/cts/SystemMediaRouter2Test.java
index 3623f15..4126daf 100644
--- a/tests/tests/media/src/android/media/cts/SystemMediaRouter2Test.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/SystemMediaRouter2Test.java
@@ -14,20 +14,20 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static android.content.Context.AUDIO_SERVICE;
 import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
 import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
-import static android.media.cts.StubMediaRoute2ProviderService.FEATURE_SAMPLE;
-import static android.media.cts.StubMediaRoute2ProviderService.FEATURE_SPECIAL;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID1;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID2;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID3_SESSION_CREATION_FAILED;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID4_TO_SELECT_AND_DESELECT;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_ID_VARIABLE_VOLUME;
-import static android.media.cts.StubMediaRoute2ProviderService.ROUTE_NAME2;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.FEATURE_SAMPLE;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.FEATURE_SPECIAL;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID1;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID2;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID3_SESSION_CREATION_FAILED;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID4_TO_SELECT_AND_DESELECT;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_ID_VARIABLE_VOLUME;
+import static android.media.misc.cts.StubMediaRoute2ProviderService.ROUTE_NAME2;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -50,6 +50,7 @@
 import android.media.MediaRouter2Manager;
 import android.media.RouteDiscoveryPreference;
 import android.media.RoutingSessionInfo;
+import android.media.cts.NonMediaMainlineTest;
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.LargeTest;
 import android.text.TextUtils;
diff --git a/tests/tests/media/src/android/media/cts/TestProxyFileDescriptorCallback.java b/tests/tests/media/misc/src/android/media/misc/cts/TestProxyFileDescriptorCallback.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/TestProxyFileDescriptorCallback.java
rename to tests/tests/media/misc/src/android/media/misc/cts/TestProxyFileDescriptorCallback.java
index 0bc0215..b0d1032 100644
--- a/tests/tests/media/src/android/media/cts/TestProxyFileDescriptorCallback.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/TestProxyFileDescriptorCallback.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.content.res.AssetFileDescriptor;
 import android.os.ProxyFileDescriptorCallback;
diff --git a/tests/tests/media/src/android/media/cts/ThumbnailUtilsTest.java b/tests/tests/media/misc/src/android/media/misc/cts/ThumbnailUtilsTest.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/ThumbnailUtilsTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/ThumbnailUtilsTest.java
index 6fdf955..afca910 100644
--- a/tests/tests/media/src/android/media/cts/ThumbnailUtilsTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/ThumbnailUtilsTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -24,6 +24,7 @@
 import android.graphics.Color;
 import static android.media.MediaFormat.MIMETYPE_VIDEO_HEVC;
 import android.media.ThumbnailUtils;
+import android.media.cts.Preconditions;
 import android.os.Build;
 import android.platform.test.annotations.AppModeFull;
 import android.util.Size;
diff --git a/tests/tests/media/src/android/media/cts/TimedMetaDataTest.java b/tests/tests/media/misc/src/android/media/misc/cts/TimedMetaDataTest.java
similarity index 94%
rename from tests/tests/media/src/android/media/cts/TimedMetaDataTest.java
rename to tests/tests/media/misc/src/android/media/misc/cts/TimedMetaDataTest.java
index 1e4d035..a14f933 100644
--- a/tests/tests/media/src/android/media/cts/TimedMetaDataTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/TimedMetaDataTest.java
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.media.TimedMetaData;
+import android.media.cts.NonMediaMainlineTest;
 import android.test.AndroidTestCase;
 
 import java.nio.charset.StandardCharsets;
diff --git a/tests/tests/media/src/android/media/cts/WorkDir.java b/tests/tests/media/misc/src/android/media/misc/cts/WorkDir.java
similarity index 88%
rename from tests/tests/media/src/android/media/cts/WorkDir.java
rename to tests/tests/media/misc/src/android/media/misc/cts/WorkDir.java
index d29b810..0c39229 100644
--- a/tests/tests/media/src/android/media/cts/WorkDir.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/WorkDir.java
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-package android.media.cts;
+package android.media.misc.cts;
 
 import android.media.cts.WorkDirBase;
 
 class WorkDir extends WorkDirBase {
     public static final String getMediaDirString() {
-        return getMediaDirString("CtsMediaTestCases-1.4");
+        return getMediaDirString("CtsMediaMiscTestCases-1.0");
     }
 }
diff --git a/tests/tests/media/muxer/src/android/media/muxer/cts/MediaMuxerTest.java b/tests/tests/media/muxer/src/android/media/muxer/cts/MediaMuxerTest.java
index 972685a..c9e12fb 100644
--- a/tests/tests/media/muxer/src/android/media/muxer/cts/MediaMuxerTest.java
+++ b/tests/tests/media/muxer/src/android/media/muxer/cts/MediaMuxerTest.java
@@ -49,7 +49,7 @@
 public class MediaMuxerTest extends AndroidTestCase {
     private static final String TAG = "MediaMuxerTest";
     private static final boolean VERBOSE = false;
-    private static final int MAX_SAMPLE_SIZE = 256 * 1024;
+    private static final int MAX_SAMPLE_SIZE = 1024 * 1024;
     private static final float LATITUDE = 0.0000f;
     private static final float LONGITUDE  = -180.0f;
     private static final float BAD_LATITUDE = 91.0f;
@@ -83,6 +83,44 @@
     }
 
     /**
+     * Test: make sure the muxer handles dovi profile 8.4 video track only file correctly.
+     */
+    // TODO(b/216824291) Enable once extractor issue is fixed
+    public void SKIP_testDolbyVisionVideoOnlyP8() throws Exception {
+        final String source = "video_dovi_1920x1080_60fps_dvhe_08_04.mp4";
+        String outputFilePath = File.createTempFile("MediaMuxerTest_dolbyvisionP8videoOnly", ".mp4")
+                .getAbsolutePath();
+        try {
+            cloneAndVerify(source, outputFilePath, 2 /* expectedTrackCount */, 180 /* degrees */,
+                    MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4,
+                    MediaMuxerTest::filterOutNonDolbyVisionFormat);
+        } finally {
+            new File(outputFilePath).delete();
+        }
+    }
+
+    /**
+     * Test: make sure the muxer handles dovi profile 9.2 video track only file correctly.
+     */
+    public void testDolbyVisionVideoOnlyP9() throws Exception {
+        final String source = "video_dovi_1920x1080_60fps_dvav_09_02.mp4";
+        String outputFilePath = File.createTempFile("MediaMuxerTest_dolbyvisionP9videoOnly", ".mp4")
+                .getAbsolutePath();
+        try {
+            cloneAndVerify(source, outputFilePath, 2 /* expectedTrackCount */, 180 /* degrees */,
+                    MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4,
+                    MediaMuxerTest::filterOutNonDolbyVisionFormat);
+        } finally {
+            new File(outputFilePath).delete();
+        }
+    }
+
+    private static MediaFormat filterOutNonDolbyVisionFormat(MediaFormat format) {
+        String mime = format.getString(MediaFormat.KEY_MIME);
+        return mime.equals(MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION) ? format : null;
+    }
+
+    /**
      * Test: makes sure if audio and video muxing using MPEG4Writer works well when there are frame
      * drops as in b/63590381 and b/64949961 while B Frames encoding is enabled.
      */
@@ -433,6 +471,19 @@
      */
     private void cloneAndVerify(final String srcMedia, String outputMediaFile,
             int expectedTrackCount, int degrees, int fmt) throws IOException {
+        cloneAndVerify(srcMedia, outputMediaFile, expectedTrackCount, degrees, fmt,
+                Function.identity());
+    }
+
+    /**
+     * Clones a given file using MediaMuxer and verifies the output matches the input.
+     *
+     * <p>See {@link #cloneMediaUsingMuxer} for information about the parameters.
+     */
+    private void cloneAndVerify(final String srcMedia, String outputMediaFile,
+            int expectedTrackCount, int degrees, int fmt,
+            Function<MediaFormat, MediaFormat> muxerInputTrackFormatTransformer)
+            throws IOException {
         try {
             cloneMediaUsingMuxer(
                     srcMedia,
@@ -440,7 +491,7 @@
                     expectedTrackCount,
                     degrees,
                     fmt,
-                    Function.identity());
+                    muxerInputTrackFormatTransformer);
             if (fmt == MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4 ||
                     fmt == MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP) {
                 verifyAttributesMatch(srcMedia, outputMediaFile, degrees);
@@ -454,7 +505,21 @@
         }
     }
 
-    /** Using the MediaMuxer to clone a media file. */
+
+    /**
+     * Clones a given file using MediaMuxer.
+     *
+     * @param srcMedia Input file path passed to extractor
+     * @param dstMediaPath Output file path passed to muxer
+     * @param expectedTrackCount Expected number of tracks in the input file
+     * @param degrees orientation hint in degrees
+     * @param fmt one of the values defined in {@link MediaMuxer.OutputFormat}.
+     * @param muxerInputTrackFormatTransformer Function applied on the MediaMuxer input formats.
+     *                                         If the function returns null for a given MediaFormat,
+     *                                         the corresponding track is discarded and not passed
+     *                                         to MediaMuxer.
+     * @throws IOException if muxer failed to open output file for write.
+     */
     private void cloneMediaUsingMuxer(
             final String srcMedia,
             String dstMediaPath,
@@ -479,10 +544,13 @@
         // Set up the tracks.
         HashMap<Integer, Integer> indexMap = new HashMap<Integer, Integer>(trackCount);
         for (int i = 0; i < trackCount; i++) {
-            extractor.selectTrack(i);
             MediaFormat format = extractor.getTrackFormat(i);
-            int dstIndex = muxer.addTrack(muxerInputTrackFormatTransformer.apply(format));
-            indexMap.put(i, dstIndex);
+            MediaFormat muxedFormat = muxerInputTrackFormatTransformer.apply(format);
+            if (muxedFormat != null) {
+                extractor.selectTrack(i);
+                int dstIndex = muxer.addTrack(muxedFormat);
+                indexMap.put(i, dstIndex);
+            }
         }
 
         // Copy the samples from MediaExtractor to MediaMuxer.
diff --git a/tests/tests/media/player/AndroidManifest.xml b/tests/tests/media/player/AndroidManifest.xml
index 050868a..2896da2 100644
--- a/tests/tests/media/player/AndroidManifest.xml
+++ b/tests/tests/media/player/AndroidManifest.xml
@@ -19,10 +19,12 @@
      android:targetSandboxVersion="2">
 
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.CAMERA"/>
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"/>
-
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
diff --git a/tests/tests/media/player/src/android/media/player/cts/MediaPlayerRandomTest.java b/tests/tests/media/player/src/android/media/player/cts/MediaPlayerRandomTest.java
index abecaf8..9060bd46 100644
--- a/tests/tests/media/player/src/android/media/player/cts/MediaPlayerRandomTest.java
+++ b/tests/tests/media/player/src/android/media/player/cts/MediaPlayerRandomTest.java
@@ -42,9 +42,10 @@
 @MediaHeavyPresubmitTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class MediaPlayerRandomTest extends ActivityInstrumentationTestCase2<MediaStubActivity> {
+    private static final int MAX_PARAM = 1000000;
     private static final String TAG = "MediaPlayerRandomTest";
 
-    static final String mInpPrefix = WorkDir.getMediaDirString();
+    private static final String mInpPrefix = WorkDir.getMediaDirString();
 
     private static final int NUMBER_OF_PLAYER_RANDOM_ACTIONS = 100000;
 
@@ -146,9 +147,10 @@
 
             watchDog.start();
             for (int i = 0; i < NUMBER_OF_PLAYER_RANDOM_ACTIONS; i++) {
-                int action = r.nextInt() % 12;
-                int param = r.nextInt() % 1000000;
-                Log.d(TAG, "Action: " + action + " Param: " + param);
+                int action = r.nextInt(12);
+                int param1 = r.nextInt(MAX_PARAM);
+                int param2 = r.nextInt(MAX_PARAM);
+                Log.d(TAG, "Action: " + action + " Param1: " + param1 + " Param2: " + param2);
                 watchDog.reset();
                 assertTrue(!mMediaServerDied);
 
@@ -180,20 +182,20 @@
                             mPlayer.prepareAsync();
                             break;
                         case 7:
-                            mPlayer.seekTo((int) (param));
+                            mPlayer.seekTo(param1);
                             break;
                         case 8:
-                            mPlayer.setLooping(param % 2 == 0);
+                            mPlayer.setLooping(param1 % 2 == 0);
                             break;
                         case 9:
-                            mPlayer.setVolume((param % 1000) / 500.0f,
-                                    (param / 1000) / 500.0f);
+                            mPlayer.setVolume((param1 * 2.0f) / MAX_PARAM,
+                                    (param2 * 2.0f) / MAX_PARAM);
                             break;
                         case 10:
                             mPlayer.start();
                             break;
                         case 11:
-                            Thread.sleep(param % 20);
+                            Thread.sleep(param1 % 20);
                             break;
                     }
                 } catch (Exception e) {
diff --git a/tests/tests/media/recorder/AndroidManifest.xml b/tests/tests/media/recorder/AndroidManifest.xml
index fdfb196..28ddf67 100644
--- a/tests/tests/media/recorder/AndroidManifest.xml
+++ b/tests/tests/media/recorder/AndroidManifest.xml
@@ -21,7 +21,8 @@
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"/>
-
+    <uses-permission android:name="android.permission.CAMERA"/>
+    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
diff --git a/tests/tests/media/recorder/src/android/media/recorder/cts/MediaRecorderRandomTest.java b/tests/tests/media/recorder/src/android/media/recorder/cts/MediaRecorderRandomTest.java
index d1376ed..06f3b8f 100644
--- a/tests/tests/media/recorder/src/android/media/recorder/cts/MediaRecorderRandomTest.java
+++ b/tests/tests/media/recorder/src/android/media/recorder/cts/MediaRecorderRandomTest.java
@@ -40,7 +40,7 @@
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class MediaRecorderRandomTest extends ActivityInstrumentationTestCase2<MediaStubActivity> {
     private static final String TAG = "MediaRecorderRandomTest";
-
+    private static final int MAX_PARAM = 1000000;
     private static final String OUTPUT_FILE =
             Environment.getExternalStorageDirectory().toString() + "/record.3gp";
 
@@ -115,7 +115,7 @@
             watchDog.start();
             for (int i = 0; i < NUMBER_OF_RECORDER_RANDOM_ACTIONS; i++) {
                 int action = r.nextInt(14);
-                int param = r.nextInt(1000000);
+                int param = r.nextInt(MAX_PARAM);
 
                 Log.d(TAG, "Action: " + action + " Param: " + param);
                 watchDog.reset();
@@ -132,9 +132,9 @@
                             break;
                         }
                         case 1:
-                            // XXX:
-                            // Fix gralloc source and change
-                            // mRecorder.setVideoSource(param % 3);
+                            // Limiting the random test to test default and camera source
+                            // and not include video surface as required setInputSurface isn't
+                            // done in this test.
                             mRecorder.setVideoSource(param % 2);
                             break;
                         case 2:
@@ -154,7 +154,7 @@
                             mRecorder.setVideoSize(width[index], height[index]);
                             break;
                         case 7:
-                            mRecorder.setVideoFrameRate(param % 40 - 5);
+                            mRecorder.setVideoFrameRate((param % 40) - 1);
                             break;
                         case 8:
                             mRecorder.setOutputFile(OUTPUT_FILE);
diff --git a/tests/tests/nativehardware/jni/Android.bp b/tests/tests/nativehardware/jni/Android.bp
index 8ad2b05..bf88b12 100644
--- a/tests/tests/nativehardware/jni/Android.bp
+++ b/tests/tests/nativehardware/jni/Android.bp
@@ -19,6 +19,9 @@
 cc_library_shared {
     name: "libahardwarebuffertest",
     compile_multilib: "both",
+    tidy_timeout_srcs: [
+        "AHardwareBufferGLTest.cpp",
+    ],
     srcs: [
         "AHardwareBufferGLTest.cpp",
         "AHardwareBufferTest.cpp",
diff --git a/tests/tests/net/native/src/TagSocketTest.cpp b/tests/tests/net/native/src/TagSocketTest.cpp
index 9826747..75d83d5 100644
--- a/tests/tests/net/native/src/TagSocketTest.cpp
+++ b/tests/tests/net/native/src/TagSocketTest.cpp
@@ -87,22 +87,17 @@
   uint64_t cookie = getSocketCookie(sock);
   EXPECT_NE(NONEXISTENT_COOKIE, cookie);
 
-  // TODO(b/214338829): Uncomment lines that check tagging result from BPF map when the
-  // connectivity service is in charge of dumping BPF maps. Currently, it
-  // doesn't work because BPF maps are dumped by netd. The shell does not have
-  // permission to find netd service in user build. So, it only verify API
-  // return codes for now.
-  // EXPECT_TRUE(socketIsNotTagged(mBinder, cookie));
+  EXPECT_TRUE(socketIsNotTagged(mBinder, cookie));
 
   EXPECT_EQ(0, android_tag_socket(sock, TEST_TAG));
-  // EXPECT_TRUE(socketIsTagged(mBinder, cookie, geteuid(), TEST_TAG));
+  EXPECT_TRUE(socketIsTagged(mBinder, cookie, geteuid(), TEST_TAG));
   EXPECT_EQ(0, android_untag_socket(sock));
-  // EXPECT_TRUE(socketIsNotTagged(mBinder, cookie));
+  EXPECT_TRUE(socketIsNotTagged(mBinder, cookie));
 
   EXPECT_EQ(0, android_tag_socket_with_uid(sock, TEST_TAG, TEST_UID));
-  // EXPECT_TRUE(socketIsTagged(mBinder, cookie, TEST_UID, TEST_TAG));
+  EXPECT_TRUE(socketIsTagged(mBinder, cookie, TEST_UID, TEST_TAG));
   EXPECT_EQ(0, android_untag_socket(sock));
-  // EXPECT_TRUE(socketIsNotTagged(mBinder, cookie));
+  EXPECT_TRUE(socketIsNotTagged(mBinder, cookie));
 }
 
 TEST_F(TagSocketTest, TagSocketErrors) {
@@ -113,7 +108,7 @@
 
   // Untag an untagged socket.
   EXPECT_EQ(-ENOENT, android_untag_socket(sock));
-  // EXPECT_TRUE(socketIsNotTagged(mBinder, cookie));
+  EXPECT_TRUE(socketIsNotTagged(mBinder, cookie));
 
   // Untag a closed socket.
   close(sock);
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 e240809..a35ff16 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
@@ -227,6 +227,7 @@
 
 extern "C"
 JNIEXPORT jint JNICALL Java_android_os_cts_uffdgc_UserfaultfdTest_performMinorUffd(JNIEnv*) {
+  uint64_t req_features;
   int ret = 0;
   int uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY);
   if (uffd < 0) {
@@ -236,15 +237,15 @@
   struct uffdio_api api;
   std::memset(&api, '\0', sizeof api);
   api.api = UFFD_API;
-  // TODO: Remove the following define once its definition is available in
-  // linux/userfaultfd.h header file.
-#ifndef UFFD_FEATURE_MINOR_SHMEM
-#define UFFD_FEATURE_MINOR_SHMEM (1 << 10)
-#endif
-  api.features = UFFD_FEATURE_MINOR_SHMEM;
+  req_features = UFFD_FEATURE_MINOR_SHMEM;
+  api.features = req_features;
   if (ioctl(uffd, UFFDIO_API, &api) < 0) {
     ret = errno;
   }
+  // Minor feature is not supported by this kernel.
+  if ((api.features & req_features) != req_features) {
+    ret = -EINVAL;
+  }
   close(uffd);
 out:
   return ret;
diff --git a/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt b/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
index b1688d2..69d020b 100644
--- a/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
+++ b/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
@@ -56,7 +56,7 @@
 // Time to find a notification. Unlikely, but in cases with a lot of notifications, it may take
 // time to find the notification we're looking for
 const val NOTIF_FIND_TIMEOUT = 20000L
-const val VIEW_WAIT_TIMEOUT = 1000L
+const val VIEW_WAIT_TIMEOUT = 3000L
 
 const val CMD_EXPAND_NOTIFICATIONS = "cmd statusbar expand-notifications"
 const val CMD_COLLAPSE = "cmd statusbar collapse"
diff --git a/tests/tests/os/src/android/os/cts/BuildTest.java b/tests/tests/os/src/android/os/cts/BuildTest.java
index 94e4ee4..2aedad2 100644
--- a/tests/tests/os/src/android/os/cts/BuildTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildTest.java
@@ -35,6 +35,7 @@
 import java.util.Scanner;
 import java.util.Set;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 public class BuildTest extends TestCase {
 
@@ -281,12 +282,21 @@
         assertTrue(TYPE_PATTERN.matcher(Build.TYPE).matches());
 
         assertNotEmpty(Build.USER);
+    }
 
+    /**
+     * Tests that check for valid values of codenames related constants.
+     */
+    public void testBuildCodenameConstants() {
         // CUR_DEVELOPMENT must be larger than any released version.
         Field[] fields = Build.VERSION_CODES.class.getDeclaredFields();
-        List<String> codenames = Arrays.asList(ACTIVE_CODENAMES);
+        List<String> activeCodenames = Arrays.asList(ACTIVE_CODENAMES);
         // Make the codenames uppercase to match the field names.
-        codenames.replaceAll(String::toUpperCase);
+        activeCodenames.replaceAll(String::toUpperCase);
+        Set<String> knownCodenames = Build.VERSION.KNOWN_CODENAMES.stream()
+                .map(String::toUpperCase)
+                .collect(Collectors.toSet());
+        HashSet<String> declaredCodenames = new HashSet<>();
         for (Field field : fields) {
             if (field.getType().equals(int.class) && Modifier.isStatic(field.getModifiers())) {
                 String fieldName = field.getName();
@@ -296,22 +306,45 @@
                 } catch (IllegalAccessException e) {
                     throw new AssertionError(e.getMessage());
                 }
+                declaredCodenames.add(fieldName);
                 if (fieldName.equals("CUR_DEVELOPMENT")) {
                     // It should be okay to change the value of this constant in future, but it
                     // should at least be a conscious decision.
                     assertEquals(10000, fieldValue);
-                } else if (codenames.contains(fieldName)) {
-                    // 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.
-                    assertTrue("Expected " + fieldName + " value to be <= " + CUR_DEVELOPMENT
-                            + ", got " + fieldValue, fieldValue <= CUR_DEVELOPMENT);
                 } else {
-                    assertTrue("Expected " + fieldName + " value to be < " + CUR_DEVELOPMENT
-                            + ", got " + fieldValue, fieldValue < CUR_DEVELOPMENT);
+                    if (activeCodenames.contains(fieldName)) {
+                        // 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.
+                        assertTrue("Expected " + fieldName + " value to be <= " + CUR_DEVELOPMENT
+                                + ", got " + fieldValue, fieldValue <= CUR_DEVELOPMENT);
+                    } else {
+                        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
+                                        + " to be declared in Build.VERSION.KNOWN_CODENAMES",
+                                knownCodenames.contains(name));
+                    }
                 }
             }
         }
+
+        HashSet<String> diff = new HashSet<>(knownCodenames);
+        diff.removeAll(declaredCodenames);
+        assertTrue(
+                "Expected all elements in Build.VERSION.KNOWN_CODENAMES to be declared in"
+                        + " Build.VERSION_CODES, found " + diff, diff.isEmpty());
+
+        if (!Build.VERSION.CODENAME.equals("REL")) {
+            assertTrue("In-development CODENAME must be declared in Build.VERSION.KNOWN_CODENAMES",
+                Build.VERSION.KNOWN_CODENAMES.contains(Build.VERSION.CODENAME));
+        }
     }
 
     /**
diff --git a/tests/tests/os/src/android/os/cts/BundleTest.java b/tests/tests/os/src/android/os/cts/BundleTest.java
index 8c91216..27d5643 100644
--- a/tests/tests/os/src/android/os/cts/BundleTest.java
+++ b/tests/tests/os/src/android/os/cts/BundleTest.java
@@ -62,6 +62,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertFalse;
@@ -552,6 +553,30 @@
         assertBundleEquals(bundle, (Bundle) mBundle.getParcelable(KEY1));
     }
 
+    @Test
+    public void testGetParcelableTypeSafe_withMismatchingType_returnsNull() {
+        mBundle.putParcelable(KEY1, new CustomParcelable(42, "don't panic"));
+        roundtrip();
+        assertNull(mBundle.getParcelable(KEY1, Intent.class));
+        assertFalse(CustomParcelable.sDeserialized);
+    }
+
+    @Test
+    public void testGetParcelableTypeSafe_withMatchingType_returnsObject() {
+        final CustomParcelable original = new CustomParcelable(42, "don't panic");
+        mBundle.putParcelable(KEY1, original);
+        roundtrip();
+        assertEquals(original, mBundle.getParcelable(KEY1, CustomParcelable.class));
+    }
+
+    @Test
+    public void testGetParcelableTypeSafe_withBaseType_returnsObject() {
+        final CustomParcelable original = new CustomParcelable(42, "don't panic");
+        mBundle.putParcelable(KEY1, original);
+        roundtrip();
+        assertEquals(original, mBundle.getParcelable(KEY1, Parcelable.class));
+    }
+
     // getParcelableArray should only return the ParcelableArray set by putParcelableArray
     @Test
     public void testGetParcelableArray() {
@@ -572,6 +597,38 @@
         assertBundleEquals(bundle2, (Bundle) parcelableArray[1]);
     }
 
+    @Test
+    public void testGetParcelableArrayTypeSafe_withMismatchingType_returnsNull() {
+        mBundle.putParcelableArray(KEY1, new CustomParcelable[] {
+                new CustomParcelable(42, "don't panic")
+        });
+        roundtrip();
+        assertNull(mBundle.getParcelableArray(KEY1, Intent.class));
+        assertFalse(CustomParcelable.sDeserialized);
+    }
+
+    @Test
+    public void testGetParcelableArrayTypeSafe_withMatchingType_returnsObject() {
+        final CustomParcelable[] original = new CustomParcelable[] {
+                new CustomParcelable(42, "don't panic"),
+                new CustomParcelable(1961, "off we go")
+        };
+        mBundle.putParcelableArray(KEY1, original);
+        roundtrip();
+        assertArrayEquals(original, mBundle.getParcelableArray(KEY1, CustomParcelable.class));
+    }
+
+    @Test
+    public void testGetParcelableArrayTypeSafe_withBaseType_returnsObject() {
+        final CustomParcelable[] original = new CustomParcelable[] {
+                new CustomParcelable(42, "don't panic"),
+                new CustomParcelable(1961, "off we go")
+        };
+        mBundle.putParcelableArray(KEY1, original);
+        roundtrip();
+        assertArrayEquals(original, mBundle.getParcelableArray(KEY1, Parcelable.class));
+    }
+
     // getParcelableArrayList should only return the parcelableArrayList set by putParcelableArrayList
     @Test
     public void testGetParcelableArrayList() {
@@ -594,6 +651,60 @@
     }
 
     @Test
+    public void testGetParcelableArrayListTypeSafe_withMismatchingType_returnsNull() {
+        final ArrayList<CustomParcelable> originalObjects = new ArrayList<>();
+        originalObjects.add(new CustomParcelable(42, "don't panic"));
+        mBundle.putParcelableArrayList(KEY1, originalObjects);
+        roundtrip();
+        assertNull(mBundle.getParcelableArrayList(KEY1, Intent.class));
+        assertFalse(CustomParcelable.sDeserialized);
+    }
+
+    @Test
+    public void testGetParcelableArrayListTypeSafe_withMatchingType_returnsObject() {
+        final ArrayList<CustomParcelable> original = new ArrayList<>();
+        original.add(new CustomParcelable(42, "don't panic"));
+        original.add(new CustomParcelable(1961, "off we go"));
+        mBundle.putParcelableArrayList(KEY1, original);
+        roundtrip();
+        assertEquals(original, mBundle.getParcelableArrayList(KEY1, CustomParcelable.class));
+    }
+
+    @Test
+    public void testGetParcelableArrayListTypeSafe_withBaseType_returnsObject() {
+        final ArrayList<CustomParcelable> original = new ArrayList<>();
+        original.add(new CustomParcelable(42, "don't panic"));
+        original.add(new CustomParcelable(1961, "off we go"));
+        mBundle.putParcelableArrayList(KEY1, original);
+        roundtrip();
+        assertEquals(original, mBundle.getParcelableArrayList(KEY1, Parcelable.class));
+    }
+
+    @Test
+    public void testGetSerializableTypeSafe_withMismatchingType_returnsNull() {
+        mBundle.putSerializable(KEY1, new CustomSerializable());
+        roundtrip();
+        assertNull(mBundle.getSerializable(KEY1, AnotherSerializable.class));
+        assertFalse(CustomSerializable.sDeserialized);
+    }
+
+    @Test
+    public void testGetSerializableTypeSafe_withMatchingType_returnsObject() {
+        mBundle.putSerializable(KEY1, new CustomSerializable());
+        roundtrip();
+        assertNotNull(mBundle.getSerializable(KEY1, CustomSerializable.class));
+        assertTrue(CustomSerializable.sDeserialized);
+    }
+
+    @Test
+    public void testGetSerializableTypeSafe_withBaseType_returnsObject() {
+        mBundle.putSerializable(KEY1, new CustomSerializable());
+        roundtrip();
+        assertNotNull(mBundle.getSerializable(KEY1, Serializable.class));
+        assertTrue(CustomSerializable.sDeserialized);
+    }
+
+    @Test
     public void testGetSerializableWithString() {
         assertNull(mBundle.getSerializable(KEY1));
         String s = "android";
@@ -695,6 +806,49 @@
     }
 
     @Test
+    public void testGetSparseParcelableArrayTypeSafe_withMismatchingType_returnsNull() {
+        final SparseArray<CustomParcelable> originalObjects = new SparseArray<>();
+        originalObjects.put(42, new CustomParcelable(42, "don't panic"));
+        mBundle.putSparseParcelableArray(KEY1, originalObjects);
+        roundtrip();
+        assertNull(mBundle.getSparseParcelableArray(KEY1, Intent.class));
+        assertFalse(CustomParcelable.sDeserialized);
+    }
+
+    @Test
+    public void testGetSparseParcelableArrayTypeSafe_withMatchingType_returnsObject() {
+        final SparseArray<CustomParcelable> original = new SparseArray<>();
+        original.put(42, new CustomParcelable(42, "don't panic"));
+        original.put(1961, new CustomParcelable(1961, "off we go"));
+        mBundle.putSparseParcelableArray(KEY1, original);
+        roundtrip();
+        assertTrue(original.contentEquals(mBundle.getSparseParcelableArray(KEY1, CustomParcelable.class)));
+    }
+
+    @Test
+    public void testGetSparseParcelableArrayTypeSafe_withBaseType_returnsObject() {
+        final SparseArray<CustomParcelable> original = new SparseArray<>();
+        original.put(42, new CustomParcelable(42, "don't panic"));
+        original.put(1961, new CustomParcelable(1961, "off we go"));
+        mBundle.putSparseParcelableArray(KEY1, original);
+        roundtrip();
+        assertTrue(original.contentEquals(mBundle.getSparseParcelableArray(KEY1, Parcelable.class)));
+    }
+
+    @Test
+    public void testGetSparseParcelableArrayTypeSafe_withMixedTypes_returnsObject() {
+        final SparseArray<Parcelable> original = new SparseArray<>();
+        original.put(42, new CustomParcelable(42, "don't panic"));
+        original.put(1961, new Intent("action"));
+        mBundle.putSparseParcelableArray(KEY1, original);
+        roundtrip();
+        final SparseArray<Parcelable> received = mBundle.getSparseParcelableArray(KEY1, Parcelable.class);
+        assertEquals(original.size(), received.size());
+        assertEquals(original.get(42), received.get(42));
+        assertIntentEquals((Intent) original.get(1961), (Intent) received.get(1961));
+    }
+
+    @Test
     public void testGetString() {
         assertNull(mBundle.getString(KEY1));
         mBundle.putString(KEY1, "android");
@@ -1338,6 +1492,9 @@
         }
     }
 
+    private static class AnotherSerializable implements Serializable {
+    }
+
     private static class CustomParcelable implements Parcelable {
         public static boolean sDeserialized = false;
 
@@ -1540,4 +1697,4 @@
             throw new AssertionError(e);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/os/src/android/os/cts/ParcelTest.java b/tests/tests/os/src/android/os/cts/ParcelTest.java
index a0ad68e..2261fbe 100644
--- a/tests/tests/os/src/android/os/cts/ParcelTest.java
+++ b/tests/tests/os/src/android/os/cts/ParcelTest.java
@@ -3614,6 +3614,10 @@
         p.writeFixedArray(ints, 0, new int[]{2, 3});
         p.setDataPosition(0);
         assertArrayEquals(ints, p.createFixedArray(int[][].class, new int[]{2, 3}));
+        int[][] readInts = new int[2][3];
+        p.setDataPosition(0);
+        p.readFixedArray(readInts);
+        assertArrayEquals(ints, readInts);
 
         // test Parcelable[2][3]
         p.setDataPosition(0);
@@ -3623,6 +3627,10 @@
         p.writeFixedArray(signatures, 0, new int[]{2, 3});
         p.setDataPosition(0);
         assertArrayEquals(signatures, p.createFixedArray(Signature[][].class, Signature.CREATOR, new int[]{2, 3}));
+        Signature[][] readSignatures = new Signature[2][3];
+        p.setDataPosition(0);
+        p.readFixedArray(readSignatures, Signature.CREATOR);
+        assertArrayEquals(signatures, readSignatures);
 
         // test IInterface[2][3]
         p.setDataPosition(0);
@@ -3635,6 +3643,10 @@
             MockIInterface::asInterface, new int[]{2, 3});
         assertEquals(2, interfacesRead.length);
         assertEquals(3, interfacesRead[0].length);
+        MockIInterface[][] mockInterfaces = new MockIInterface[2][3];
+        p.setDataPosition(0);
+        p.readFixedArray(mockInterfaces, MockIInterface::asInterface);
+        assertArrayEquals(interfaces, mockInterfaces);
 
         // test null
         p.setDataPosition(0);
diff --git a/tests/tests/permission/OWNERS b/tests/tests/permission/OWNERS
index d401f0d..6b28459 100644
--- a/tests/tests/permission/OWNERS
+++ b/tests/tests/permission/OWNERS
@@ -8,4 +8,5 @@
 per-file NoAudioPermissionTest.java = elaurent@google.com
 per-file MainlineNetworkStackPermissionTest.java = file: platform/frameworks/base:/services/net/OWNERS
 per-file Camera2PermissionTest.java = file: platform/frameworks/av:/camera/OWNERS
-per-file NoRollbackPermissionTest.java = mpgroover@google.com
\ No newline at end of file
+per-file NoRollbackPermissionTest.java = mpgroover@google.com
+per-file EthernetManagerPermissionTest.java = file: platform/frameworks/base:/services/net/OWNERS
\ No newline at end of file
diff --git a/tests/tests/permission/src/android/permission/cts/EthernetManagerPermissionTest.java b/tests/tests/permission/src/android/permission/cts/EthernetManagerPermissionTest.java
new file mode 100644
index 0000000..069162e
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/EthernetManagerPermissionTest.java
@@ -0,0 +1,157 @@
+/*
+ * 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.permission.cts;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.EthernetManager;
+import android.net.EthernetNetworkUpdateRequest;
+import android.net.IpConfiguration;
+import android.net.NetworkCapabilities;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Executor;
+import java.util.function.BiConsumer;
+
+/**
+ * Test protected android.net.EthernetManager methods cannot be called without permissions.
+ */
+@RunWith(AndroidJUnit4.class)
+public class EthernetManagerPermissionTest {
+    private static final String TEST_IFACE = "test123abc789";
+    private EthernetManager mEthernetManager;
+    private Context mContext;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mEthernetManager = mContext.getSystemService(EthernetManager.class);
+        // mEthernetManager may be null depending on the device's configuration.
+        assumeNotNull(mEthernetManager);
+    }
+
+    private void callUpdateConfiguration() {
+        final IpConfiguration ipConfig = new IpConfiguration.Builder().build();
+        final NetworkCapabilities networkCapabilities =
+                new NetworkCapabilities.Builder().build();
+        final EthernetNetworkUpdateRequest request =
+                new EthernetNetworkUpdateRequest.Builder()
+                        .setIpConfiguration(ipConfig)
+                        .setNetworkCapabilities(networkCapabilities)
+                        .build();
+        mEthernetManager.updateConfiguration(TEST_IFACE, request, null, null);
+    }
+
+    /**
+     * Verify that calling {@link EthernetManager#updateConfiguration(String,
+     * EthernetNetworkUpdateRequest, Executor, BiConsumer)} requires permissions.
+     * <p>Tests Permission:
+     *   {@link android.Manifest.permission#MANAGE_ETHERNET_NETWORKS}.
+     */
+    @Test
+    public void testUpdateConfiguration() {
+        assumeTrue(mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_AUTOMOTIVE));
+        assertThrows("Should not be able to call updateConfiguration without permission",
+                SecurityException.class, () -> callUpdateConfiguration());
+    }
+
+    /**
+     * Verify that calling {@link EthernetManager#connectNetwork(String, Executor, BiConsumer)}
+     * requires permissions.
+     * <p>Tests Permission:
+     *   {@link android.Manifest.permission#MANAGE_ETHERNET_NETWORKS}.
+     */
+    @Test
+    public void testConnectNetwork() {
+        assumeTrue(mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_AUTOMOTIVE));
+        assertThrows("Should not be able to call connectNetwork without permission",
+                SecurityException.class,
+                () -> mEthernetManager.connectNetwork(TEST_IFACE, null, null));
+    }
+
+    /**
+     * Verify that calling {@link EthernetManager#disconnectNetwork(String, Executor, BiConsumer)}
+     * requires permissions.
+     * <p>Tests Permission:
+     *   {@link android.Manifest.permission#MANAGE_ETHERNET_NETWORKS}.
+     */
+    @Test
+    public void testDisconnectNetwork() {
+        assumeTrue(mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_AUTOMOTIVE));
+        assertThrows("Should not be able to call disconnectNetwork without permission",
+                SecurityException.class,
+                () -> mEthernetManager.disconnectNetwork(TEST_IFACE, null, null));
+    }
+
+    /**
+     * Verify that calling {@link EthernetManager#updateConfiguration(
+     * String, EthernetNetworkUpdateRequest, Executor, BiConsumer)} requires automotive feature.
+     * <p>Tests Feature:
+     *   {@link PackageManager#FEATURE_AUTOMOTIVE}.
+     */
+    @Test
+    public void testUpdateConfigurationHasAutomotiveFeature() {
+        assumeFalse(mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_AUTOMOTIVE));
+        assertThrows("Should not be able to call updateConfiguration without automotive feature",
+                UnsupportedOperationException.class, () -> callUpdateConfiguration());
+    }
+
+    /**
+     * Verify that calling {@link EthernetManager#connectNetwork(String, Executor, BiConsumer)}
+     * requires automotive feature.
+     * <p>Tests Feature:
+     *   {@link PackageManager#FEATURE_AUTOMOTIVE}.
+     */
+    @Test
+    public void testConnectNetworkHasAutomotiveFeature() {
+        assumeFalse(mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_AUTOMOTIVE));
+        assertThrows("Should not be able to call connectNetwork without automotive feature",
+                UnsupportedOperationException.class,
+                () -> mEthernetManager.connectNetwork(TEST_IFACE, null, null));
+    }
+
+    /**
+     * Verify that calling {@link EthernetManager#disconnectNetwork(String, Executor, BiConsumer)}
+     * requires automotive feature.
+     * <p>Tests Feature:
+     *   {@link PackageManager#FEATURE_AUTOMOTIVE}.
+     */
+    @Test
+    public void testDisconnectNetworkHasAutomotiveFeature() {
+        assumeFalse(mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_AUTOMOTIVE));
+        assertThrows("Should not be able to call disconnectNetwork without automotive feature",
+                UnsupportedOperationException.class,
+                () -> mEthernetManager.disconnectNetwork(TEST_IFACE, null, null));
+    }
+}
diff --git a/tests/tests/selinux/selinuxTargetSdk30/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdk30/src/android/security/SELinuxTargetSdkTest.java
index 64e40ff..279f9e6 100644
--- a/tests/tests/selinux/selinuxTargetSdk30/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdk30/src/android/security/SELinuxTargetSdkTest.java
@@ -49,6 +49,10 @@
         checkNetlinkRouteGetneigh(true);
     }
 
+    public void testNoHardwareAddress() throws Exception {
+        checkNetworkInterfaceHardwareAddress_returnsNull();
+    }
+
     public void testCanNotExecuteFromHomeDir() throws Exception {
         assertFalse(canExecuteFromHomeDir());
     }
diff --git a/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java
index 93d92e5..3e01ec1 100644
--- a/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java
@@ -45,6 +45,10 @@
         checkNetlinkRouteGetneigh(false);
     }
 
+    public void testNoHardwareAddress() throws Exception {
+        checkNetworkInterfaceHardwareAddress_returnsNull();
+    }
+
     public void testCanNotExecuteFromHomeDir() throws Exception {
         assertFalse(canExecuteFromHomeDir());
     }
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionTest.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionTest.java
index 29beb99..b7c05b7 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionTest.java
@@ -195,7 +195,6 @@
         control.checkBindStatus(true /* bindStatus */);
 
         connection.waitOnInCallServiceTrackingChanged();
-        assertTrue(connection.isTracked());
         assertTrue(connection.isAlternativeUiShowing());
 
         connection.disconnectAndDestroy();
diff --git a/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl b/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl
index 2529ada..71924a2 100644
--- a/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl
@@ -29,4 +29,5 @@
     boolean isRcsFeatureCreated();
     boolean isMmTelFeatureCreated();
     void resetState();
+    boolean isTelephonyBound();
 }
diff --git a/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java b/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java
index 9101ae51..eaeb6d1 100644
--- a/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java
@@ -29,7 +29,7 @@
  */
 
 public class TestExternalImsService extends TestImsService {
-    private static final String TAG = "GtsImsTestDeviceImsService";
+    private static final String TAG = "CtsImsTestDeviceImsService";
     // TODO: Use ImsService.SERVICE_INTERFACE definition when it becomes public.
     private static final String ACTION_BIND_IMS_SERVICE = "android.telephony.ims.ImsService";
 
@@ -56,19 +56,26 @@
         public void resetState() {
             TestExternalImsService.this.resetState();
         }
+
+        public boolean isTelephonyBound() {
+            return TestExternalImsService.this.isTelephonyBound();
+        }
     }
 
     @Override
     public IBinder onBind(Intent intent) {
-        if (ACTION_BIND_IMS_SERVICE.equals(intent.getAction())) {
-            if (ImsUtils.VDBG) {
-                Log.i(TAG, "onBind-Remote");
+        synchronized (mLock) {
+            if (ACTION_BIND_IMS_SERVICE.equals(intent.getAction())) {
+                if (ImsUtils.VDBG) {
+                    Log.i(TAG, "onBind-Remote");
+                }
+                mIsTelephonyBound = true;
+                return super.onBind(intent);
             }
-            return super.onBind(intent);
+            if (ImsUtils.VDBG) {
+                Log.i(TAG, "onBind-Local");
+            }
+            return mBinder;
         }
-        if (ImsUtils.VDBG) {
-            Log.i(TAG, "onBind-Local");
-        }
-        return mBinder;
     }
 }
diff --git a/tests/tests/telephony/current/assets/mock_sim_tw_cht.xml b/tests/tests/telephony/current/assets/mock_sim_tw_cht.xml
new file mode 100644
index 0000000..aaabe62
--- /dev/null
+++ b/tests/tests/telephony/current/assets/mock_sim_tw_cht.xml
@@ -0,0 +1,28 @@
+<MockSim numofapp="2" iccid="89886920042507847155">
+<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">A0000000871002F886FF9289050B00FE</EFDIR>
+    </MF>
+
+    <ADF aid="A0000000871002F886FF9289050B00FE">
+        <EF name="EF_IMSI" id="6F07">311740123456789</EF>
+    </ADF>
+</MockSimProfile>
+
+<MockSimProfile id="1" type="APPTYPE_ISIM">
+    <PinProfile appstate="APPSTATE_DETECTED">
+        <Pin1State>PINSTATE_DISABLED</Pin1State>
+        <Pin2State>PINSTATE_ENABLED_NOT_VERIFIED</Pin2State>
+    </PinProfile>
+</MockSimProfile>
+</MockSim>
\ No newline at end of file
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CellLocationTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CellLocationTest.java
index fc97d48..871e378 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CellLocationTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellLocationTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Looper;
 import android.net.ConnectivityManager;
 import android.telephony.CellLocation;
@@ -40,6 +41,7 @@
     private boolean mOnCellLocationChangedCalled;
     private final Object mLock = new Object();
     private TelephonyManager mTelephonyManager;
+    private PackageManager mPackageManager;
     private PhoneStateListener mListener;
     private static ConnectivityManager mCm;
     private static final String TAG = "android.telephony.cts.CellLocationTest";
@@ -49,6 +51,7 @@
         mTelephonyManager =
                 (TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE);
         mCm = (ConnectivityManager)getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+        mPackageManager = getContext().getPackageManager();
     }
 
     @After
@@ -61,8 +64,8 @@
 
     @Test
     public void testCellLocation() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
 
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/IRadioSimImpl.java b/tests/tests/telephony/current/src/android/telephony/cts/IRadioSimImpl.java
index 8a9f241..08980a3 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/IRadioSimImpl.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/IRadioSimImpl.java
@@ -27,8 +27,11 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.RemoteException;
+import android.telephony.cts.MockSimService.SimAppData;
 import android.util.Log;
 
+import java.util.ArrayList;
+
 public class IRadioSimImpl extends IRadioSim.Stub {
     private static final String TAG = "MRSIM";
 
@@ -42,10 +45,12 @@
 
     // ***** Events
     static final int EVENT_SIM_CARD_STATUS_CHANGED = 1;
+    static final int EVENT_SIM_APP_DATA_CHANGED = 2;
 
     // ***** Cache of modem attributes/status
     private int mNumOfLogicalSim;
     private CardStatus mCardStatus;
+    private ArrayList<SimAppData> mSimAppList;
 
     public IRadioSimImpl(
             MockModemService service, MockModemConfigInterface[] interfaces, int instanceId) {
@@ -62,6 +67,10 @@
         // Register events
         sMockModemConfigInterfaces[mSubId].registerForCardStatusChanged(
                 mHandler, EVENT_SIM_CARD_STATUS_CHANGED, null);
+
+        // Register events
+        sMockModemConfigInterfaces[mSubId].registerForSimAppDataChanged(
+                mHandler, EVENT_SIM_APP_DATA_CHANGED, null);
     }
 
     /** Handler class to handle callbacks */
@@ -82,6 +91,21 @@
                             Log.e(TAG, msg.what + " failure. Exception: " + ar.exception);
                         }
                         break;
+
+                    case EVENT_SIM_APP_DATA_CHANGED:
+                        Log.d(TAG, "Received EVENT_SIM_APP_DATA_CHANGED");
+                        ar = (AsyncResult) msg.obj;
+                        if (ar != null && ar.exception == null) {
+                            mSimAppList = (ArrayList<SimAppData>) ar.result;
+                            if (mSimAppList != null) {
+                                Log.i(TAG, "number of SIM app data: " + mSimAppList.size());
+                            } else {
+                                Log.e(TAG, "mSimAppList = null");
+                            }
+                        } else {
+                            Log.e(TAG, msg.what + " failure. Exception: " + ar.exception);
+                        }
+                        break;
                 }
             }
         }
@@ -213,13 +237,49 @@
     public void getFacilityLockForApp(
             int serial, String facility, String password, int serviceClass, String appId) {
         Log.d(TAG, "getFacilityLockForApp");
+        int numOfSimApp = mSimAppList.size();
+        int responseError = RadioError.NONE;
+        int simAppIdx;
+        boolean isHandled = false;
+        boolean isFacilitySupport = true;
+        int responseData = -1;
 
-        // TODO: cache value
-        int response = 0;
+        // 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;
+            }
+        }
 
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        if (!isHandled) {
+            Log.e(TAG, "Not support sim application aid = " + appId);
+            responseError = RadioError.NO_SUCH_ELEMENT;
+        } else if (!isFacilitySupport) {
+            Log.e(TAG, "Not support facility = " + facility);
+            responseError = RadioError.REQUEST_NOT_SUPPORTED;
+        } else if (responseData == -1) {
+            responseError = RadioError.INTERNAL_ERR;
+        }
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, responseError);
         try {
-            mRadioSimResponse.getFacilityLockForAppResponse(rsp, response);
+            mRadioSimResponse.getFacilityLockForAppResponse(rsp, responseData);
         } catch (RemoteException ex) {
             Log.e(TAG, "Failed to getFacilityLockForApp from AIDL. Exception" + ex);
         }
@@ -245,10 +305,25 @@
     @Override
     public void getImsiForApp(int serial, String aid) {
         Log.d(TAG, "getImsiForApp");
-        // TODO: cache value
         String imsi = "";
+        int numOfSimApp = mSimAppList.size();
+        int responseError = RadioError.NONE;
+        int simAppIdx;
+        boolean isHandled;
 
-        RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+        for (simAppIdx = 0, isHandled = false; simAppIdx < numOfSimApp && !isHandled; simAppIdx++) {
+            if (aid.equals(mSimAppList.get(simAppIdx).getAid())) {
+                imsi = mSimAppList.get(simAppIdx).getImsi();
+                isHandled = true;
+            }
+        }
+
+        if (!isHandled) {
+            Log.e(TAG, "Not support sim application aid = " + aid);
+            responseError = RadioError.NO_SUCH_ELEMENT;
+        }
+
+        RadioResponseInfo rsp = mService.makeSolRsp(serial, responseError);
         try {
             mRadioSimResponse.getImsiForAppResponse(rsp, imsi);
         } catch (RemoteException ex) {
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigBase.java b/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigBase.java
index 6a8731d..a77dd66 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigBase.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigBase.java
@@ -20,13 +20,17 @@
 import android.hardware.radio.config.PhoneCapability;
 import android.hardware.radio.config.SimPortInfo;
 import android.hardware.radio.config.SimSlotStatus;
+import android.hardware.radio.config.SlotPortMapping;
 import android.hardware.radio.sim.CardStatus;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
 import android.os.RegistrantList;
+import android.telephony.cts.MockSimService.SimAppData;
 import android.util.Log;
 
+import java.util.ArrayList;
+
 public class MockModemConfigBase implements MockModemConfigInterface {
     // ***** Instance Variables
     private static final int DEFAULT_SUB_ID = 0;
@@ -41,7 +45,7 @@
 
     // ***** Events
     static final int EVENT_SET_RADIO_POWER = 1;
-    static final int EVENT_SET_SIM_PRESENT = 2;
+    static final int EVENT_CHANGE_SIM_PROFILE = 2;
 
     // ***** Modem config values
     private String mBasebandVersion = MockModemConfigInterface.DEFAULT_BASEBAND_VERSION;
@@ -53,8 +57,10 @@
     private byte mNumOfLiveModem = MockModemConfigInterface.DEFAULT_NUM_OF_LIVE_MODEM;
     private SimSlotStatus[] mSimSlotStatus;
     private CardStatus mCardStatus;
-    private MockSimCard[] mSIMCard;
+    private int mFdnStatus;
+    private MockSimService[] mSimService;
     private PhoneCapability mPhoneCapability = new PhoneCapability();
+    private ArrayList<SimAppData> mSimAppList;
 
     // ***** RegistrantLists
     // ***** IRadioConfig RegistrantLists
@@ -69,6 +75,7 @@
 
     // ***** IRadioSim RegistrantLists
     private RegistrantList mCardStatusChangedRegistrants = new RegistrantList();
+    private RegistrantList mSimAppDataChangedRegistrants = new RegistrantList();
 
     public MockModemConfigBase(Context context, int instanceId, int numOfSim, int numOfPhone) {
         mContext = context;
@@ -86,7 +93,7 @@
         mHandler = new MockModemConfigHandler();
         mSimSlotStatus = new SimSlotStatus[mNumOfSim];
         mCardStatus = new CardStatus();
-        mSIMCard = new MockSimCard[mNumOfSim];
+        mSimService = new MockSimService[mNumOfSim];
         mSimPhyicalId = mSubId; // for default mapping
         createSIMCards();
         setDefaultConfigValue();
@@ -118,21 +125,24 @@
                             mRadioStateChangedRegistrants.notifyRegistrants(null);
                         }
                         break;
-                    case EVENT_SET_SIM_PRESENT:
-                        boolean isPresent = msg.getData().getBoolean("isPresent", false);
-                        Log.d(mTAG, "EVENT_SET_SIM_PRESENT: " + (isPresent ? "Present" : "Absent"));
-                        int newCardState =
-                                isPresent ? CardStatus.STATE_PRESENT : CardStatus.STATE_ABSENT;
-                        if (mSubId == DEFAULT_SUB_ID
-                                && mSimSlotStatus[mSimPhyicalId].cardState != newCardState) {
-                            mSimSlotStatus[mSimPhyicalId].cardState = newCardState;
-                            mSimSlotStatusChangedRegistrants.notifyRegistrants(
-                                    new AsyncResult(null, mSimSlotStatus, null));
-                        }
-                        if (mCardStatus.cardState != newCardState) {
-                            mCardStatus.cardState = newCardState;
+                    case EVENT_CHANGE_SIM_PROFILE:
+                        int simprofileid =
+                                msg.getData()
+                                        .getInt(
+                                                "changeSimProfile",
+                                                MockSimService.MOCK_SIM_PROFILE_ID_DEFAULT);
+                        Log.d(mTAG, "EVENT_CHANGE_SIM_PROFILE: sim profile(" + simprofileid + ")");
+                        if (loadSIMCard(simprofileid)) {
+                            if (mSubId == DEFAULT_SUB_ID) {
+                                mSimSlotStatusChangedRegistrants.notifyRegistrants(
+                                        new AsyncResult(null, mSimSlotStatus, null));
+                            }
                             mCardStatusChangedRegistrants.notifyRegistrants(
                                     new AsyncResult(null, mCardStatus, null));
+                            mSimAppDataChangedRegistrants.notifyRegistrants(
+                                    new AsyncResult(null, mSimAppList, null));
+                        } else {
+                            Log.e(mTAG, "Load Sim card failed.");
                         }
                         break;
                 }
@@ -151,9 +161,9 @@
             mNumOfLiveModem = MockModemConfigInterface.DEFAULT_NUM_OF_LIVE_MODEM;
             setDefaultPhoneCapability(mPhoneCapability);
             if (mSubId == DEFAULT_SUB_ID) {
-                setDefaultSimSlotStatus();
+                updateSimSlotStatus();
             }
-            setDefaultCardStatus();
+            updateCardStatus();
         }
     }
 
@@ -171,59 +181,84 @@
 
     private void createSIMCards() {
         for (int i = 0; i < mNumOfSim; i++) {
-            mSIMCard[i] = new MockSimCard(i);
+            mSimService[i] = new MockSimService(mContext, i);
         }
     }
 
-    private void setDefaultSimSlotStatus() {
+    private void updateSimSlotStatus() {
         if (mSubId != DEFAULT_SUB_ID) {
             // Only sub 0 needs to response SimSlotStatus
             return;
         }
 
+        if (mSimService == null) {
+            Log.e(mTAG, "SIM service didn't be created yet.");
+        }
+
         for (int i = 0; i < mNumOfSim; i++) {
-            int portInfoListLen = mSIMCard[i].getNumOfSimPortInfo();
+            if (mSimService[i] == null) {
+                Log.e(mTAG, "SIM service[" + i + "] didn't be created yet.");
+                continue;
+            }
+            int portInfoListLen = mSimService[i].getNumOfSimPortInfo();
             mSimSlotStatus[i] = new SimSlotStatus();
             mSimSlotStatus[i].cardState =
-                    mSIMCard[i].isCardPresent()
+                    mSimService[i].isCardPresent()
                             ? CardStatus.STATE_PRESENT
                             : CardStatus.STATE_ABSENT;
-            mSimSlotStatus[i].atr = mSIMCard[i].getATR();
-            mSimSlotStatus[i].eid = mSIMCard[i].getEID();
-            // Current only support one Sim port in MockSimCard
+            mSimSlotStatus[i].atr = mSimService[i].getATR();
+            mSimSlotStatus[i].eid = mSimService[i].getEID();
+            // Current only support one Sim port in MockSimService
             SimPortInfo[] portInfoList0 = new SimPortInfo[portInfoListLen];
             portInfoList0[0] = new SimPortInfo();
-            portInfoList0[0].portActive = mSIMCard[i].isSlotPortActive();
-            portInfoList0[0].logicalSlotId = mSIMCard[i].getLogicalSlotId();
-            portInfoList0[0].iccId = mSIMCard[i].getICCID();
+            portInfoList0[0].portActive = mSimService[i].isSlotPortActive();
+            portInfoList0[0].logicalSlotId = mSimService[i].getLogicalSlotId();
+            portInfoList0[0].iccId = mSimService[i].getICCID();
             mSimSlotStatus[i].portInfo = portInfoList0;
         }
     }
 
-    private void setDefaultCardStatus() {
-        if (mSimPhyicalId != -1) {
-            int numbOfSimApp = mSIMCard[mSimPhyicalId].getNumOfSimApp();
+    private void updateCardStatus() {
+        if (mSimPhyicalId != -1 && mSimService != null && mSimService[mSimPhyicalId] != null) {
+            int numOfSimApp = mSimService[mSimPhyicalId].getNumOfSimApp();
             mCardStatus = new CardStatus();
             mCardStatus.cardState =
-                    mSIMCard[mSimPhyicalId].isCardPresent()
+                    mSimService[mSimPhyicalId].isCardPresent()
                             ? CardStatus.STATE_PRESENT
                             : CardStatus.STATE_ABSENT;
-            mCardStatus.universalPinState = mSIMCard[mSimPhyicalId].getUniversalPinState();
-            mCardStatus.gsmUmtsSubscriptionAppIndex = mSIMCard[mSimPhyicalId].getGsmAppIndex();
-            mCardStatus.cdmaSubscriptionAppIndex = mSIMCard[mSimPhyicalId].getCdmaAppIndex();
-            mCardStatus.imsSubscriptionAppIndex = mSIMCard[mSimPhyicalId].getImsAppIndex();
-            mCardStatus.applications = new android.hardware.radio.sim.AppStatus[numbOfSimApp];
-            mCardStatus.atr = mSIMCard[mSimPhyicalId].getATR();
-            mCardStatus.iccid = mSIMCard[mSimPhyicalId].getICCID();
-            mCardStatus.eid = mSIMCard[mSimPhyicalId].getEID();
-            mCardStatus.slotMap = new android.hardware.radio.config.SlotPortMapping();
-            mCardStatus.slotMap.physicalSlotId = mSIMCard[mSimPhyicalId].getPhysicalSlotId();
-            mCardStatus.slotMap.portId = mSIMCard[mSimPhyicalId].getSlotPortId();
+            mCardStatus.universalPinState = mSimService[mSimPhyicalId].getUniversalPinState();
+            mCardStatus.gsmUmtsSubscriptionAppIndex = mSimService[mSimPhyicalId].getGsmAppIndex();
+            mCardStatus.cdmaSubscriptionAppIndex = mSimService[mSimPhyicalId].getCdmaAppIndex();
+            mCardStatus.imsSubscriptionAppIndex = mSimService[mSimPhyicalId].getImsAppIndex();
+            mCardStatus.applications = mSimService[mSimPhyicalId].getSimApp();
+            mCardStatus.atr = mSimService[mSimPhyicalId].getATR();
+            mCardStatus.iccid = mSimService[mSimPhyicalId].getICCID();
+            mCardStatus.eid = mSimService[mSimPhyicalId].getEID();
+            mCardStatus.slotMap = new SlotPortMapping();
+            mCardStatus.slotMap.physicalSlotId = mSimService[mSimPhyicalId].getPhysicalSlotId();
+            mCardStatus.slotMap.portId = mSimService[mSimPhyicalId].getSlotPortId();
+            mSimAppList = mSimService[mSimPhyicalId].getSimAppList();
         } else {
-            Log.e(mTAG, "Invalid Sim physical id");
+            Log.e(
+                    mTAG,
+                    "Invalid Sim physical id("
+                            + mSimPhyicalId
+                            + ") or SIM card didn't be created.");
         }
     }
 
+    private boolean loadSIMCard(int simProfileId) {
+        boolean result = false;
+        if (mSimPhyicalId != -1 && mSimService != null && mSimService[mSimPhyicalId] != null) {
+            result = mSimService[mSimPhyicalId].loadSimCard(simProfileId);
+            if (mSubId == DEFAULT_SUB_ID) {
+                updateSimSlotStatus();
+            }
+            updateCardStatus();
+        }
+        return result;
+    }
+
     private void notifyDeviceIdentityChangedRegistrants() {
         String[] deviceIdentity = new String[4];
         synchronized (mConfigAccess) {
@@ -259,6 +294,8 @@
             // IRadioSim
             mCardStatusChangedRegistrants.notifyRegistrants(
                     new AsyncResult(null, mCardStatus, null));
+            mSimAppDataChangedRegistrants.notifyRegistrants(
+                    new AsyncResult(null, mSimAppList, null));
         }
     }
 
@@ -335,6 +372,16 @@
         mCardStatusChangedRegistrants.remove(h);
     }
 
+    @Override
+    public void registerForSimAppDataChanged(Handler h, int what, Object obj) {
+        mSimAppDataChangedRegistrants.addUnique(h, what, obj);
+    }
+
+    @Override
+    public void unregisterForSimAppDataChanged(Handler h) {
+        mSimAppDataChangedRegistrants.remove(h);
+    }
+
     // ***** IRadioConfig set APIs implementation
 
     // ***** IRadioModem set APIs implementation
@@ -359,11 +406,17 @@
 
     // ***** Helper APIs implementation
     @Override
-    public void setSimPresent(boolean isPresent, String client) {
-        Log.d(mTAG, "setSimPresent (" + (isPresent ? "Present" : "Absent") + ") from: " + client);
+    public boolean isSimCardPresent(String client) {
+        Log.d(mTAG, "isSimCardPresent from: " + client);
+        return (mCardStatus.cardState == CardStatus.STATE_PRESENT) ? true : false;
+    }
 
-        Message msg = mHandler.obtainMessage(EVENT_SET_SIM_PRESENT);
-        msg.getData().putBoolean("isPresent", isPresent);
+    @Override
+    public void changeSimProfile(int simprofileid, String client) {
+        Log.d(mTAG, "changeSimProfile: profile id(" + simprofileid + ") from: " + client);
+
+        Message msg = mHandler.obtainMessage(EVENT_CHANGE_SIM_PROFILE);
+        msg.getData().putInt("changeSimProfile", simprofileid);
         mHandler.sendMessage(msg);
     }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigInterface.java b/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigInterface.java
index 5632255..32b2908 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigInterface.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigInterface.java
@@ -84,6 +84,11 @@
 
     void unregisterForCardStatusChanged(Handler h);
 
+    /** Register/unregister notification handler for sim app data changed */
+    void registerForSimAppDataChanged(Handler h, int what, Object obj);
+
+    void unregisterForSimAppDataChanged(Handler h);
+
     /**
      * Sets the latest radio power state of modem
      *
@@ -93,10 +98,18 @@
     void setRadioState(int state, String client);
 
     /**
-     * Sets a specific logical SIM state to absent or present
+     * Query whether any SIM cards are present or not.
      *
-     * @param isPresent true means "present", false means "absent".
+     * @param client for tracking calling client
+     * @return boolean true if any sim card inserted, otherwise false.
+     */
+    boolean isSimCardPresent(String client);
+
+    /**
+     * Change SIM profile
+     *
+     * @param simProfileId The target profile to be switched.
      * @param client for tracking calling client
      */
-    void setSimPresent(boolean isPresent, String client);
+    void changeSimProfile(int simProfileId, String client);
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemManager.java b/tests/tests/telephony/current/src/android/telephony/cts/MockModemManager.java
index 24eaa7a..38e36dd 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockModemManager.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MockModemManager.java
@@ -48,6 +48,15 @@
      * @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) {
@@ -56,7 +65,8 @@
         }
 
         if (sServiceConnector != null) {
-            result = sServiceConnector.connectMockModemService();
+            // TODO: support DSDS
+            result = sServiceConnector.connectMockModemService(simprofile);
 
             if (result) {
                 mMockModemService = sServiceConnector.getMockModemService();
@@ -104,19 +114,62 @@
     }
 
     /**
-     * Set SIM card status as present.
+     * Query whether an active SIM card is present on this sub or not.
      *
-     * @param subId which sub needs to be set.
-     * @return boolean true if the operation is successful, otherwise false.
+     * @param subId which sub would be checked.
+     * @return boolean true if any sim card inserted, otherwise false.
      */
-    public boolean setSimPresent(int subId) throws Exception {
-        Log.d(TAG, "setSimPresent[" + subId + "]");
-        boolean result = true;
+    public boolean isSimCardPresent(int subId) throws Exception {
+        Log.d(TAG, "isSimCardPresent[" + subId + "]");
 
         MockModemConfigInterface[] configInterfaces =
                 mMockModemService.getMockModemConfigInterfaces();
-        configInterfaces[subId].setSimPresent(true, TAG);
-        waitForTelephonyFrameworkDone(1);
+        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;
     }
 
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemService.java b/tests/tests/telephony/current/src/android/telephony/cts/MockModemService.java
index 38e7086..741b0e7 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockModemService.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MockModemService.java
@@ -233,6 +233,17 @@
         int numPhysicalSlots =
                 sContext.getResources()
                         .getInteger(com.android.internal.R.integer.config_num_physical_slots);
+        if (numPhysicalSlots > MockSimService.MOCK_SIM_SLOT_MAX) {
+            Log.d(
+                    TAG,
+                    "Number of physical Slot ("
+                            + numPhysicalSlots
+                            + ") > mock sim slot support. Reset to max number supported ("
+                            + MockSimService.MOCK_SIM_SLOT_MAX
+                            + ").");
+            numPhysicalSlots = MockSimService.MOCK_SIM_SLOT_MAX;
+        }
+
         return numPhysicalSlots;
     }
 
@@ -254,12 +265,16 @@
         return rspInfo;
     }
 
-    public boolean initialize() {
-        Log.d(TAG, "initialize");
+    public boolean initialize(int simprofile) {
+        Log.d(TAG, "initialize simprofile = " + simprofile);
         boolean result = true;
 
         // Sync mock modem status between modules
         for (int i = 0; i < mNumOfPhone; i++) {
+            // Set initial SIM profile
+            sMockModemConfigInterfaces[i].changeSimProfile(simprofile, TAG);
+
+            // Sync modem configurations to radio modules
             sMockModemConfigInterfaces[i].notifyAllRegistrantNotifications();
         }
 
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemServiceConnector.java b/tests/tests/telephony/current/src/android/telephony/cts/MockModemServiceConnector.java
index beeb720..039a1e1 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockModemServiceConnector.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MockModemServiceConnector.java
@@ -186,7 +186,7 @@
      *
      * @return true if this request succeeded, false otherwise.
      */
-    boolean switchFrameworkConnectionToMockModemService() throws Exception {
+    boolean switchFrameworkConnectionToMockModemService(int simprofile) throws Exception {
         boolean isComplete = false;
 
         if (overrideModemService()) {
@@ -196,7 +196,8 @@
                             BIND_RADIO_INTERFACE_READY_TIMEOUT_MS);
 
             if (isComplete) {
-                isComplete = mMockModemService.initialize();
+                // TODO: support DSDS
+                isComplete = mMockModemService.initialize(simprofile);
             }
         }
 
@@ -211,13 +212,13 @@
         return isServiceTheSame(mModemServiceName, serviceName);
     }
 
-    boolean connectMockModemService() throws Exception {
+    boolean connectMockModemService(int simprofile) throws Exception {
         boolean result = false;
         if (!connectMockModemServiceLocally()) return false;
 
         result = checkModemServiceOverridden(getModemService());
         if (result) mIsServiceOverridden = true;
-        else result = switchFrameworkConnectionToMockModemService();
+        else result = switchFrameworkConnectionToMockModemService(simprofile);
 
         return result;
     }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockSimCard.java b/tests/tests/telephony/current/src/android/telephony/cts/MockSimCard.java
deleted file mode 100644
index 280b8d5..0000000
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockSimCard.java
+++ /dev/null
@@ -1,274 +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 android.util.Log;
-
-public class MockSimCard {
-    private static final String TAG = "MockSimCard";
-
-    /* Support SIM card identify */
-    public static final int MOCK_SIM_PROFILE_ID_DEFAULT = 0; // SIM Absent
-    public static final int MOCK_SIM_PROFILE_ID_MAX = 1;
-
-    /* Support SIM slot */
-    private static final int MOCK_SIM_SLOT_1 = 0;
-    private static final int MOCK_SIM_SLOT_2 = 1;
-    private static final int MOCK_SIM_SLOT_3 = 2;
-    private static final int MOCK_SIM_SLOT_MAX = 3;
-
-    /* Default value definition */
-    private static final int MOCK_SIM_DEFAULT_SLOTID = MOCK_SIM_SLOT_1;
-    private static final int DEFAULT_NUM_OF_SIM_PORT_INfO = 1;
-    private static final int DEFAULT_NUM_OF_SIM_APP = 0;
-    private static final int DEFAULT_GSM_APP_IDX = -1;
-    private static final int DEFAULT_CDMA_APP_IDX = -1;
-    private static final int DEFAULT_IMS_APP_IDX = -1;
-    // SIM1 slot status
-    private static final int DEFAULT_SIM1_PROFILE_ID = MOCK_SIM_PROFILE_ID_DEFAULT;
-    private static final boolean DEFAULT_SIM1_CARD_PRESENT = false;
-    private static final String DEFAULT_SIM1_ATR = "";
-    private static final String DEFAULT_SIM1_EID = "";
-    private static final String DEFAULT_SIM1_ICCID = "";
-    private static final boolean DEFAULT_SIM1_PORT_ACTIVE = true;
-    private static final int DEFAULT_SIM1_PORT_ID = 0;
-    private static final int DEFAULT_SIM1_LOGICAL_SLOT_ID = 0;
-    private static final int DEFAULT_SIM1_PHYSICAL_SLOT_ID = 0;
-    private static final int DEFAULT_SIM1_UNIVERSAL_PIN_STATE = 0;
-    // SIM2 slot status
-    private static final int DEFAULT_SIM2_PROFILE_ID = MOCK_SIM_PROFILE_ID_DEFAULT;
-    private static final boolean DEFAULT_SIM2_CARD_PRESENT = false;
-    private static final String DEFAULT_SIM2_ATR =
-            "3B9F97C00A3FC6828031E073FE211F65D002341512810F51";
-    private static final String DEFAULT_SIM2_EID = "89033023426200000000005430099507";
-    private static final String DEFAULT_SIM2_ICCID = "";
-    private static final boolean DEFAULT_SIM2_PORT_ACTIVE = false;
-    private static final int DEFAULT_SIM2_PORT_ID = 0;
-    private static final int DEFAULT_SIM2_LOGICAL_SLOT_ID = -1;
-    private static final int DEFAULT_SIM2_PHYSICAL_SLOT_ID = 0;
-    private static final int DEFAULT_SIM2_UNIVERSAL_PIN_STATE = 0;
-    // SIM3 slot status
-    private static final int DEFAULT_SIM3_PROFILE_ID = MOCK_SIM_PROFILE_ID_DEFAULT;
-    private static final boolean DEFAULT_SIM3_CARD_PRESENT = false;
-    private static final String DEFAULT_SIM3_ATR = "";
-    private static final String DEFAULT_SIM3_EID = "";
-    private static final String DEFAULT_SIM3_ICCID = "";
-    private static final boolean DEFAULT_SIM3_PORT_ACTIVE = false;
-    private static final int DEFAULT_SIM3_PORT_ID = 0;
-    private static final int DEFAULT_SIM3_LOGICAL_SLOT_ID = -1;
-    private static final int DEFAULT_SIM3_PHYSICAL_SLOT_ID = 0;
-    private static final int DEFAULT_SIM3_UNIVERSAL_PIN_STATE = 0;
-
-    // SIM Slot status
-    private int mPhysicalSlotId;
-    private int mLogicalSlotId;
-    private int mSlotPortId;
-    private boolean mIsSlotPortActive;
-    private boolean mIsCardPresent;
-
-    // SIM card data
-    private int mSimProfileId;
-    private String mICCID;
-    private String mEID;
-    private String mATR;
-    private int mUniversalPinState;
-    private int mGsmAppIndex;
-    private int mCdmaAppIndex;
-    private int mImsAppIndex;
-    private int mNumOfSimApp;
-
-    public MockSimCard(int slotId) {
-        int simprofile = DEFAULT_SIM1_PROFILE_ID;
-
-        if (slotId >= MOCK_SIM_SLOT_MAX) {
-            Log.e(
-                    TAG,
-                    "Invalid slot id("
-                            + slotId
-                            + "). Using default slot id("
-                            + MOCK_SIM_DEFAULT_SLOTID
-                            + ").");
-            slotId = MOCK_SIM_DEFAULT_SLOTID;
-        }
-
-        // Init default SIM profile id
-        switch (slotId) {
-            case MOCK_SIM_SLOT_1:
-                simprofile = DEFAULT_SIM1_PROFILE_ID;
-                break;
-            case MOCK_SIM_SLOT_2:
-                simprofile = DEFAULT_SIM2_PROFILE_ID;
-                break;
-            case MOCK_SIM_SLOT_3:
-                simprofile = DEFAULT_SIM3_PROFILE_ID;
-                break;
-        }
-
-        // Initiate SIM card with default profile
-        initMockSimCard(slotId, simprofile);
-    }
-
-    private void initMockSimCard(int slotId, int simProfileId) {
-        if (slotId > MockModemConfigInterface.MAX_NUM_OF_SIM_SLOT) {
-            Log.e(
-                    TAG,
-                    "Physical slot id("
-                            + slotId
-                            + ") is invalid. Using default slot id("
-                            + MOCK_SIM_DEFAULT_SLOTID
-                            + ").");
-            mPhysicalSlotId = MOCK_SIM_DEFAULT_SLOTID;
-        } else {
-            mPhysicalSlotId = slotId;
-        }
-        if (simProfileId >= 0 && simProfileId < MOCK_SIM_PROFILE_ID_MAX) {
-            mSimProfileId = simProfileId;
-            Log.i(
-                    TAG,
-                    "Load SIM profile ID: "
-                            + mSimProfileId
-                            + " into physical slot["
-                            + mPhysicalSlotId
-                            + "]");
-        } else {
-            mSimProfileId = MOCK_SIM_PROFILE_ID_DEFAULT;
-            Log.e(
-                    TAG,
-                    "SIM Absent on physical slot["
-                            + mPhysicalSlotId
-                            + "]. Not support SIM card ID: "
-                            + mSimProfileId);
-        }
-
-        // Initiate slot status
-        initMockSimSlot();
-
-        // Load SIM profile data
-        loadMockSimCard();
-    }
-
-    private void initMockSimSlot() {
-        switch (mPhysicalSlotId) {
-            case MOCK_SIM_SLOT_1:
-                mLogicalSlotId = DEFAULT_SIM1_LOGICAL_SLOT_ID;
-                mSlotPortId = DEFAULT_SIM1_PORT_ID;
-                mIsSlotPortActive = DEFAULT_SIM1_PORT_ACTIVE;
-                mIsCardPresent = DEFAULT_SIM1_CARD_PRESENT;
-                break;
-            case MOCK_SIM_SLOT_2:
-                mLogicalSlotId = DEFAULT_SIM2_LOGICAL_SLOT_ID;
-                mSlotPortId = DEFAULT_SIM2_PORT_ID;
-                mIsSlotPortActive = DEFAULT_SIM2_PORT_ACTIVE;
-                mIsCardPresent = DEFAULT_SIM2_CARD_PRESENT;
-                break;
-            case MOCK_SIM_SLOT_3:
-                mLogicalSlotId = DEFAULT_SIM3_LOGICAL_SLOT_ID;
-                mSlotPortId = DEFAULT_SIM3_PORT_ID;
-                mIsSlotPortActive = DEFAULT_SIM3_PORT_ACTIVE;
-                mIsCardPresent = DEFAULT_SIM3_CARD_PRESENT;
-                break;
-        }
-    }
-
-    private void loadMockSimCard() {
-        // TODO: Read SIM card data from file
-        switch (mSimProfileId) {
-            default: // SIM absent
-                switch (mPhysicalSlotId) {
-                    case MOCK_SIM_SLOT_1:
-                        mICCID = DEFAULT_SIM1_ICCID;
-                        mATR = DEFAULT_SIM1_ATR;
-                        mEID = DEFAULT_SIM1_EID;
-                        mUniversalPinState = DEFAULT_SIM1_UNIVERSAL_PIN_STATE;
-                        break;
-                    case MOCK_SIM_SLOT_2:
-                        mICCID = DEFAULT_SIM2_ICCID;
-                        mATR = DEFAULT_SIM2_ATR;
-                        mEID = DEFAULT_SIM2_EID;
-                        mUniversalPinState = DEFAULT_SIM2_UNIVERSAL_PIN_STATE;
-                        break;
-                    case MOCK_SIM_SLOT_3:
-                        mICCID = DEFAULT_SIM3_ICCID;
-                        mATR = DEFAULT_SIM3_ATR;
-                        mEID = DEFAULT_SIM3_EID;
-                        mUniversalPinState = DEFAULT_SIM3_UNIVERSAL_PIN_STATE;
-                        break;
-                }
-                mGsmAppIndex = DEFAULT_GSM_APP_IDX;
-                mCdmaAppIndex = DEFAULT_CDMA_APP_IDX;
-                mImsAppIndex = DEFAULT_IMS_APP_IDX;
-                mNumOfSimApp = DEFAULT_NUM_OF_SIM_APP;
-                break;
-        }
-    }
-
-    public boolean isSlotPortActive() {
-        return mIsSlotPortActive;
-    }
-
-    public boolean isCardPresent() {
-        return mIsCardPresent;
-    }
-
-    public int getNumOfSimPortInfo() {
-        return DEFAULT_NUM_OF_SIM_PORT_INfO;
-    }
-
-    public int getPhysicalSlotId() {
-        return mPhysicalSlotId;
-    }
-
-    public int getLogicalSlotId() {
-        return mLogicalSlotId;
-    }
-
-    public int getSlotPortId() {
-        return mSlotPortId;
-    }
-
-    public String getEID() {
-        return mEID;
-    }
-
-    public String getATR() {
-        return mATR;
-    }
-
-    public String getICCID() {
-        return mICCID;
-    }
-
-    public int getUniversalPinState() {
-        return mUniversalPinState;
-    }
-
-    public int getGsmAppIndex() {
-        return mGsmAppIndex;
-    }
-
-    public int getCdmaAppIndex() {
-        return mCdmaAppIndex;
-    }
-
-    public int getImsAppIndex() {
-        return mImsAppIndex;
-    }
-
-    public int getNumOfSimApp() {
-        return mNumOfSimApp;
-    }
-}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockSimService.java b/tests/tests/telephony/current/src/android/telephony/cts/MockSimService.java
new file mode 100644
index 0000000..2e43c54
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MockSimService.java
@@ -0,0 +1,827 @@
+/*
+ * 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 android.content.Context;
+import android.hardware.radio.sim.AppStatus;
+import android.hardware.radio.sim.PinState;
+import android.util.Log;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+
+public class MockSimService {
+    private static final String TAG = "MockSimService";
+
+    /* 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;
+
+    /* SIM profile XML TAG definition */
+    private static final String MOCK_SIM_TAG = "MockSim";
+    private static final String MOCK_SIM_PROFILE_TAG = "MockSimProfile";
+    private static final String MOCK_PIN_PROFILE_TAG = "PinProfile";
+    private static final String MOCK_PIN1_STATE_TAG = "Pin1State";
+    private static final String MOCK_PIN2_STATE_TAG = "Pin2State";
+    private static final String MOCK_FACILITY_LOCK_TAG = "FacilityLock";
+    private static final String MOCK_FACILITY_LOCK_FD_TAG = "FD";
+    private static final String MOCK_FACILITY_LOCK_SC_TAG = "SC";
+    private static final String MOCK_MF_TAG = "MF";
+    private static final String MOCK_EF_TAG = "EF";
+    private static final String MOCK_EF_DIR_TAG = "EFDIR";
+    private static final String MOCK_ADF_TAG = "ADF";
+
+    /* Support SIM slot */
+    private static final int MOCK_SIM_SLOT_1 = 0;
+    private static final int MOCK_SIM_SLOT_2 = 1;
+    private static final int MOCK_SIM_SLOT_3 = 2;
+    public static final int MOCK_SIM_SLOT_MAX = 3;
+
+    /* Default value definition */
+    private static final int MOCK_SIM_DEFAULT_SLOTID = MOCK_SIM_SLOT_1;
+    private static final int DEFAULT_NUM_OF_SIM_PORT_INfO = 1;
+    private static final int DEFAULT_NUM_OF_SIM_APP = 0;
+    private static final int DEFAULT_GSM_APP_IDX = -1;
+    private static final int DEFAULT_CDMA_APP_IDX = -1;
+    private static final int DEFAULT_IMS_APP_IDX = -1;
+    // SIM1 slot status
+    private static final int DEFAULT_SIM1_PROFILE_ID = MOCK_SIM_PROFILE_ID_DEFAULT;
+    private static final boolean DEFAULT_SIM1_CARD_PRESENT = false;
+    private static final String DEFAULT_SIM1_ATR = "";
+    private static final String DEFAULT_SIM1_EID = "";
+    private static final String DEFAULT_SIM1_ICCID = "";
+    private static final boolean DEFAULT_SIM1_PORT_ACTIVE = true;
+    private static final int DEFAULT_SIM1_PORT_ID = 0;
+    private static final int DEFAULT_SIM1_LOGICAL_SLOT_ID = 0;
+    private static final int DEFAULT_SIM1_PHYSICAL_SLOT_ID = 0;
+    private static final int DEFAULT_SIM1_UNIVERSAL_PIN_STATE = 0;
+    // SIM2 slot status
+    private static final int DEFAULT_SIM2_PROFILE_ID = MOCK_SIM_PROFILE_ID_DEFAULT;
+    private static final boolean DEFAULT_SIM2_CARD_PRESENT = false;
+    private static final String DEFAULT_SIM2_ATR =
+            "3B9F97C00A3FC6828031E073FE211F65D002341512810F51";
+    private static final String DEFAULT_SIM2_EID = "89033023426200000000005430099507";
+    private static final String DEFAULT_SIM2_ICCID = "";
+    private static final boolean DEFAULT_SIM2_PORT_ACTIVE = false;
+    private static final int DEFAULT_SIM2_PORT_ID = 0;
+    private static final int DEFAULT_SIM2_LOGICAL_SLOT_ID = -1;
+    private static final int DEFAULT_SIM2_PHYSICAL_SLOT_ID = 0;
+    private static final int DEFAULT_SIM2_UNIVERSAL_PIN_STATE = 0;
+    // SIM3 slot status
+    private static final int DEFAULT_SIM3_PROFILE_ID = MOCK_SIM_PROFILE_ID_DEFAULT;
+    private static final boolean DEFAULT_SIM3_CARD_PRESENT = false;
+    private static final String DEFAULT_SIM3_ATR = "";
+    private static final String DEFAULT_SIM3_EID = "";
+    private static final String DEFAULT_SIM3_ICCID = "";
+    private static final boolean DEFAULT_SIM3_PORT_ACTIVE = false;
+    private static final int DEFAULT_SIM3_PORT_ID = 0;
+    private static final int DEFAULT_SIM3_LOGICAL_SLOT_ID = -1;
+    private static final int DEFAULT_SIM3_PHYSICAL_SLOT_ID = 0;
+    private static final int DEFAULT_SIM3_UNIVERSAL_PIN_STATE = 0;
+
+    private Context mContext;
+
+    // SIM Slot status
+    private int mPhysicalSlotId;
+    private int mLogicalSlotId;
+    private int mSlotPortId;
+    private boolean mIsSlotPortActive;
+    private boolean mIsCardPresent;
+
+    /* SIM profile info */
+    private SimProfileInfo[] mSimProfileInfoList;
+
+    // SIM card data
+    private int mSimProfileId;
+    private String mICCID;
+    private String mEID;
+    private String mATR;
+    private int mUniversalPinState;
+
+    private AppStatus[] mSimApp;
+    private ArrayList<SimAppData> mSimAppList;
+
+    public class SimAppData {
+        private int mSimAppId;
+        private String mAid;
+        private boolean mIsCurrentActive;
+        private String mPath;
+        private int mFdnStatus;
+        private int mPin1State;
+        private String mImsi;
+
+        public SimAppData(int simappid, String aid, String path) {
+            mSimAppId = simappid;
+            mAid = aid;
+            mIsCurrentActive = false;
+            mPath = path;
+        }
+
+        public int getSimAppId() {
+            return mSimAppId;
+        }
+
+        public String getAid() {
+            return mAid;
+        }
+
+        public boolean isCurrentActive() {
+            return mIsCurrentActive;
+        }
+
+        public String getPath() {
+            return mPath;
+        }
+
+        public int getFdnStatus() {
+            return mFdnStatus;
+        }
+
+        public void setFdnStatus(int status) {
+            mFdnStatus = status;
+        }
+
+        public int getPin1State() {
+            return mPin1State;
+        }
+
+        public void setPin1State(int state) {
+            mPin1State = state;
+        }
+
+        public String getImsi() {
+            return mImsi;
+        }
+
+        public void setImsi(String imsi) {
+            mImsi = imsi;
+        }
+    }
+
+    public class SimProfileInfo {
+        private int mSimProfileId;
+        private int mNumOfSimApp;
+        private int mGsmAppIndex;
+        private int mCdmaAppIndex;
+        private int mImsAppIndex;
+        private String mXmlFile;
+
+        public SimProfileInfo(int profileid) {
+            mSimProfileId = profileid;
+            mNumOfSimApp = DEFAULT_NUM_OF_SIM_APP;
+            mGsmAppIndex = DEFAULT_GSM_APP_IDX;
+            mCdmaAppIndex = DEFAULT_CDMA_APP_IDX;
+            mImsAppIndex = DEFAULT_IMS_APP_IDX;
+            mXmlFile = "";
+        }
+
+        public int getNumOfSimApp() {
+            return mNumOfSimApp;
+        }
+
+        public int getGsmAppIndex() {
+            return mGsmAppIndex;
+        }
+
+        public int getCdmaAppIndex() {
+            return mCdmaAppIndex;
+        }
+
+        public int getImsAppIndex() {
+            return mImsAppIndex;
+        }
+
+        public String getXmlFile() {
+            return mXmlFile;
+        }
+
+        public void setNumOfSimApp(int number) {
+            mNumOfSimApp = number;
+        }
+
+        public void setGsmAppIndex(int index) {
+            mGsmAppIndex = index;
+        }
+
+        public void setCdmaAppIndex(int index) {
+            mCdmaAppIndex = index;
+        }
+
+        public void setImsAppIndex(int index) {
+            mImsAppIndex = index;
+        }
+
+        public void setXmlFile(String file) {
+            mXmlFile = file;
+        }
+    }
+
+    public MockSimService(Context context, int slotId) {
+        mContext = context;
+        int simprofile = DEFAULT_SIM1_PROFILE_ID;
+
+        if (slotId >= MOCK_SIM_SLOT_MAX) {
+            Log.e(
+                    TAG,
+                    "Invalid slot id("
+                            + slotId
+                            + "). Using default slot id("
+                            + MOCK_SIM_DEFAULT_SLOTID
+                            + ").");
+            slotId = MOCK_SIM_DEFAULT_SLOTID;
+        }
+
+        // Init default SIM profile id
+        switch (slotId) {
+            case MOCK_SIM_SLOT_1:
+                simprofile = DEFAULT_SIM1_PROFILE_ID;
+                break;
+            case MOCK_SIM_SLOT_2:
+                simprofile = DEFAULT_SIM2_PROFILE_ID;
+                break;
+            case MOCK_SIM_SLOT_3:
+                simprofile = DEFAULT_SIM3_PROFILE_ID;
+                break;
+        }
+
+        // Initial support SIM profile list
+        mSimProfileInfoList = new SimProfileInfo[MOCK_SIM_PROFILE_ID_MAX];
+        for (int idx = 0; idx < MOCK_SIM_PROFILE_ID_MAX; idx++) {
+            Log.d(TAG, "Create sim profile id = " + idx);
+            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);
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        // Initiate SIM card with default profile
+        initMockSimCard(slotId, simprofile);
+    }
+
+    private void initMockSimCard(int slotId, int simProfileId) {
+        if (slotId > MockModemConfigInterface.MAX_NUM_OF_SIM_SLOT) {
+            Log.e(
+                    TAG,
+                    "Physical slot id("
+                            + slotId
+                            + ") is invalid. Using default slot id("
+                            + MOCK_SIM_DEFAULT_SLOTID
+                            + ").");
+            mPhysicalSlotId = MOCK_SIM_DEFAULT_SLOTID;
+        } else {
+            mPhysicalSlotId = slotId;
+        }
+        if (simProfileId >= 0 && simProfileId < MOCK_SIM_PROFILE_ID_MAX) {
+            mSimProfileId = simProfileId;
+            Log.i(
+                    TAG,
+                    "Load SIM profile ID: "
+                            + mSimProfileId
+                            + " into physical slot["
+                            + mPhysicalSlotId
+                            + "]");
+        } else {
+            mSimProfileId = MOCK_SIM_PROFILE_ID_DEFAULT;
+            Log.e(
+                    TAG,
+                    "SIM Absent on physical slot["
+                            + mPhysicalSlotId
+                            + "]. Not support SIM card ID: "
+                            + mSimProfileId);
+        }
+
+        // Initiate slot status
+        initMockSimSlot();
+
+        // Load SIM profile data
+        loadMockSimCard();
+    }
+
+    private void initMockSimSlot() {
+        switch (mPhysicalSlotId) {
+            case MOCK_SIM_SLOT_1:
+                mLogicalSlotId = DEFAULT_SIM1_LOGICAL_SLOT_ID;
+                mSlotPortId = DEFAULT_SIM1_PORT_ID;
+                mIsSlotPortActive = DEFAULT_SIM1_PORT_ACTIVE;
+                mIsCardPresent = DEFAULT_SIM1_CARD_PRESENT;
+                break;
+            case MOCK_SIM_SLOT_2:
+                mLogicalSlotId = DEFAULT_SIM2_LOGICAL_SLOT_ID;
+                mSlotPortId = DEFAULT_SIM2_PORT_ID;
+                mIsSlotPortActive = DEFAULT_SIM2_PORT_ACTIVE;
+                mIsCardPresent = DEFAULT_SIM2_CARD_PRESENT;
+                break;
+            case MOCK_SIM_SLOT_3:
+                mLogicalSlotId = DEFAULT_SIM3_LOGICAL_SLOT_ID;
+                mSlotPortId = DEFAULT_SIM3_PORT_ID;
+                mIsSlotPortActive = DEFAULT_SIM3_PORT_ACTIVE;
+                mIsCardPresent = DEFAULT_SIM3_CARD_PRESENT;
+                break;
+        }
+    }
+
+    private int convertMockSimPinState(String pinstate) {
+        int mocksim_pinstate = PinState.UNKNOWN;
+        switch (pinstate) {
+            case "PINSTATE_UNKNOWN":
+                mocksim_pinstate = PinState.UNKNOWN;
+                break;
+            case "PINSTATE_ENABLED_NOT_VERIFIED":
+                mocksim_pinstate = PinState.ENABLED_NOT_VERIFIED;
+                break;
+            case "PINSTATE_ENABLED_VERIFIED":
+                mocksim_pinstate = PinState.ENABLED_VERIFIED;
+                break;
+            case "PINSTATE_DISABLED":
+                mocksim_pinstate = PinState.DISABLED;
+                break;
+            case "PINSTATE_ENABLED_BLOCKED":
+                mocksim_pinstate = PinState.ENABLED_BLOCKED;
+                break;
+            case "PINSTATE_ENABLED_PERM_BLOCKED":
+                mocksim_pinstate = PinState.ENABLED_PERM_BLOCKED;
+                break;
+        }
+
+        return mocksim_pinstate;
+    }
+
+    private int convertMockSimAppType(String apptype) {
+        int mocksim_apptype = AppStatus.APP_TYPE_UNKNOWN;
+        switch (apptype) {
+            case "APPTYPE_UNKNOWN":
+                mocksim_apptype = AppStatus.APP_TYPE_UNKNOWN;
+                break;
+            case "APPTYPE_SIM":
+                mocksim_apptype = AppStatus.APP_TYPE_SIM;
+                break;
+            case "APPTYPE_USIM":
+                mocksim_apptype = AppStatus.APP_TYPE_USIM;
+                break;
+            case "APPTYPE_RUIM":
+                mocksim_apptype = AppStatus.APP_TYPE_RUIM;
+                break;
+            case "APPTYPE_CSIM":
+                mocksim_apptype = AppStatus.APP_TYPE_CSIM;
+                break;
+            case "APPTYPE_ISIM":
+                mocksim_apptype = AppStatus.APP_TYPE_ISIM;
+                break;
+        }
+
+        return mocksim_apptype;
+    }
+
+    private int convertMockSimAppState(String appstate) {
+        int mocksim_appstate = AppStatus.APP_STATE_UNKNOWN;
+        switch (appstate) {
+            case "APPSTATE_UNKNOWN":
+                mocksim_appstate = AppStatus.APP_STATE_UNKNOWN;
+                break;
+            case "APPSTATE_DETECTED":
+                mocksim_appstate = AppStatus.APP_STATE_DETECTED;
+                break;
+            case "APPSTATE_PIN":
+                mocksim_appstate = AppStatus.APP_STATE_PIN;
+                break;
+            case "APPSTATE_PUK":
+                mocksim_appstate = AppStatus.APP_STATE_PUK;
+                break;
+            case "APPSTATE_SUBSCRIPTION_PERSO":
+                mocksim_appstate = AppStatus.APP_STATE_SUBSCRIPTION_PERSO;
+                break;
+            case "APPSTATE_READY":
+                mocksim_appstate = AppStatus.APP_STATE_READY;
+                break;
+        }
+        return mocksim_appstate;
+    }
+
+    private int convertMockSimFacilityLock(String lock) {
+        int facilitylock = 0;
+        switch (lock) {
+            case "LOCK_ENABLED":
+                facilitylock = 1;
+                break;
+            case "LOCK_DISABLED":
+                facilitylock = 0;
+                break;
+        }
+        return facilitylock;
+    }
+
+    private int getSimAppDataIndexByAid(String aid) {
+        int idx;
+        for (idx = 0; idx < mSimAppList.size(); idx++) {
+            if (aid.equals(mSimAppList.get(idx).getAid())) {
+                break;
+            }
+        }
+        return idx;
+    }
+
+    private boolean storeEfData(String aid, String name, String id, String value) {
+        boolean result = true;
+        switch (name) {
+            case "EF_IMSI":
+                mSimAppList.get(getSimAppDataIndexByAid(aid)).setImsi(value);
+                break;
+            default:
+                result = false;
+                Log.w(TAG, "Not support EF field - " + name + "(" + id + ")");
+                break;
+        }
+        return result;
+    }
+
+    private boolean loadSimProfileFromXml() {
+        boolean result = true;
+
+        if (mSimProfileInfoList == null) {
+            Log.e(TAG, "No support SIM profile list.");
+            return false;
+        }
+
+        try {
+            String file = mSimProfileInfoList[mSimProfileId].getXmlFile();
+            int event;
+            XmlPullParser parser = Xml.newPullParser();
+            InputStream input;
+            boolean mocksim_validation = false;
+            boolean mocksim_mf_validation = false;
+            int appidx = 0;
+            int fd_lock = 0;
+            int sc_lock = 0;
+            String adf_aid = "";
+
+            input = mContext.getAssets().open(file);
+            parser.setInput(input, null);
+            while (result && (event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+                switch (event) {
+                    case XmlPullParser.START_TAG:
+                        if (MOCK_SIM_TAG.equals(parser.getName())) {
+                            int numofapp = Integer.parseInt(parser.getAttributeValue(0));
+                            String iccid = parser.getAttributeValue(1);
+                            Log.d(
+                                    TAG,
+                                    "Found "
+                                            + MOCK_SIM_TAG
+                                            + ": numofapp = "
+                                            + numofapp
+                                            + " iccid = "
+                                            + iccid);
+                            mICCID = iccid;
+                            mSimApp = new AppStatus[numofapp];
+                            if (mSimApp == null) {
+                                Log.e(TAG, "Create SIM app failed!");
+                                result = false;
+                                break;
+                            }
+                            mocksim_validation = true;
+                        } else if (mocksim_validation
+                                && MOCK_SIM_PROFILE_TAG.equals(parser.getName())) {
+                            int id = Integer.parseInt(parser.getAttributeValue(0));
+                            int type = convertMockSimAppType(parser.getAttributeValue(1));
+                            mSimApp[appidx] = new AppStatus();
+                            mSimApp[appidx].appType = type;
+                            switch (type) {
+                                case AppStatus.APP_TYPE_SIM:
+                                case AppStatus.APP_TYPE_USIM:
+                                    mSimProfileInfoList[mSimProfileId].setGsmAppIndex(id);
+                                    break;
+                                case AppStatus.APP_TYPE_CSIM:
+                                case AppStatus.APP_TYPE_RUIM:
+                                    mSimProfileInfoList[mSimProfileId].setCdmaAppIndex(id);
+                                    break;
+                                case AppStatus.APP_TYPE_ISIM:
+                                    mSimProfileInfoList[mSimProfileId].setImsAppIndex(id);
+                                    break;
+                            }
+                            Log.d(
+                                    TAG,
+                                    "Found ["
+                                            + MOCK_SIM_PROFILE_TAG
+                                            + "]: id = "
+                                            + id
+                                            + " type = "
+                                            + parser.getAttributeValue(1)
+                                            + " ("
+                                            + type
+                                            + ")========");
+                        } else if (mocksim_validation
+                                && MOCK_PIN_PROFILE_TAG.equals(parser.getName())) {
+                            int appstate = convertMockSimAppState(parser.getAttributeValue(0));
+                            mSimApp[appidx].appState = appstate;
+                            Log.d(
+                                    TAG,
+                                    "Found "
+                                            + MOCK_PIN_PROFILE_TAG
+                                            + ": appstate = "
+                                            + parser.getAttributeValue(0)
+                                            + " ("
+                                            + appstate
+                                            + ")");
+                        } else if (mocksim_validation
+                                && MOCK_PIN1_STATE_TAG.equals(parser.getName())) {
+                            String state = parser.nextText();
+                            int pin1state = convertMockSimPinState(state);
+                            mSimApp[appidx].pin1 = pin1state;
+                            Log.d(
+                                    TAG,
+                                    "Found "
+                                            + MOCK_PIN1_STATE_TAG
+                                            + " = "
+                                            + state
+                                            + " ("
+                                            + pin1state
+                                            + ")");
+                        } else if (mocksim_validation
+                                && MOCK_PIN2_STATE_TAG.equals(parser.getName())) {
+                            String state = parser.nextText();
+                            int pin2state = convertMockSimPinState(state);
+                            Log.d(
+                                    TAG,
+                                    "Found "
+                                            + MOCK_PIN2_STATE_TAG
+                                            + " = "
+                                            + state
+                                            + " ("
+                                            + pin2state
+                                            + ")");
+                        } else if (mocksim_validation
+                                && MOCK_FACILITY_LOCK_FD_TAG.equals(parser.getName())) {
+                            fd_lock = convertMockSimFacilityLock(parser.nextText());
+                            Log.d(
+                                    TAG,
+                                    "Found "
+                                            + MOCK_FACILITY_LOCK_FD_TAG
+                                            + ": fd lock = "
+                                            + fd_lock);
+                        } else if (mocksim_validation
+                                && MOCK_FACILITY_LOCK_SC_TAG.equals(parser.getName())) {
+                            sc_lock = convertMockSimFacilityLock(parser.nextText());
+                            Log.d(
+                                    TAG,
+                                    "Found "
+                                            + MOCK_FACILITY_LOCK_SC_TAG
+                                            + ": sc lock = "
+                                            + sc_lock);
+                        } else if (mocksim_validation && MOCK_MF_TAG.equals(parser.getName())) {
+                            SimAppData simAppData;
+                            String name = parser.getAttributeValue(0);
+                            String path = parser.getAttributeValue(1);
+                            simAppData = new SimAppData(appidx, name, path);
+                            if (simAppData == null) {
+                                Log.e(TAG, "Create SIM app data failed!");
+                                result = false;
+                                break;
+                            }
+                            mSimAppList.add(simAppData);
+                            Log.d(
+                                    TAG,
+                                    "Found "
+                                            + MOCK_MF_TAG
+                                            + ": name = "
+                                            + name
+                                            + " path = "
+                                            + path);
+                        } else if (mocksim_validation
+                                && !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);
+                            if (simAppData == null) {
+                                Log.e(TAG, "Create SIM app data failed!");
+                                result = false;
+                                break;
+                            }
+                            simAppData.setFdnStatus(fd_lock);
+                            simAppData.setPin1State(sc_lock);
+                            mSimAppList.add(simAppData);
+                            if (curr_active) {
+                                mSimApp[appidx].aidPtr = aid;
+                            }
+                            Log.d(
+                                    TAG,
+                                    "Found "
+                                            + MOCK_EF_DIR_TAG
+                                            + ": name = "
+                                            + name
+                                            + ": curr_active = "
+                                            + curr_active
+                                            + " aid = "
+                                            + aid);
+                            mocksim_mf_validation = true;
+                        } else if (mocksim_validation
+                                && 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_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);
+                            }
+                        }
+                        break;
+                    case XmlPullParser.END_TAG:
+                        if (mocksim_validation && MOCK_SIM_PROFILE_TAG.equals(parser.getName())) {
+                            appidx++;
+                            mocksim_mf_validation = false;
+                        } else if (mocksim_validation && MOCK_ADF_TAG.equals(parser.getName())) {
+                            adf_aid = "";
+                        }
+                        break;
+                }
+            }
+            Log.d(TAG, "Totally create " + appidx + " SIM profiles");
+            mSimProfileInfoList[mSimProfileId].setNumOfSimApp(appidx);
+            input.close();
+        } catch (Exception e) {
+            Log.e(TAG, "Exception error: " + e);
+            result = false;
+        }
+
+        return result;
+    }
+
+    private boolean loadSimApp() {
+        boolean result = true;
+
+        if (mSimAppList == null) {
+            mSimAppList = new ArrayList<SimAppData>();
+        } else {
+            mSimAppList.clear();
+        }
+
+        if (mSimProfileId == MOCK_SIM_PROFILE_ID_DEFAULT
+                || mSimProfileInfoList[mSimProfileId].getXmlFile().length() == 0) {
+            Log.d(TAG, "SIM absent case");
+            mSimApp = new AppStatus[0];
+            if (mSimApp == null) {
+                Log.e(TAG, "Create SIM app failed!");
+                result = false;
+            }
+        } else {
+            result = loadSimProfileFromXml();
+        }
+
+        return result;
+    }
+
+    private boolean loadMockSimCard() {
+        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:
+                    mATR = DEFAULT_SIM2_ATR;
+                    mEID = DEFAULT_SIM2_EID;
+                    break;
+                case MOCK_SIM_SLOT_3:
+                    mATR = DEFAULT_SIM3_ATR;
+                    mEID = DEFAULT_SIM3_EID;
+                    break;
+            }
+            mUniversalPinState = PinState.DISABLED;
+            mIsCardPresent = true;
+        } else {
+            switch (mPhysicalSlotId) {
+                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;
+            }
+            mIsCardPresent = false;
+        }
+        return loadSimApp();
+    }
+
+    public boolean loadSimCard(int simprofileid) {
+        boolean result = true;
+        mSimProfileId = simprofileid;
+        if (result) {
+            result = loadMockSimCard();
+        }
+        return result;
+    }
+
+    public boolean isSlotPortActive() {
+        return mIsSlotPortActive;
+    }
+
+    public boolean isCardPresent() {
+        return mIsCardPresent;
+    }
+
+    public int getNumOfSimPortInfo() {
+        return DEFAULT_NUM_OF_SIM_PORT_INfO;
+    }
+
+    public int getPhysicalSlotId() {
+        return mPhysicalSlotId;
+    }
+
+    public int getLogicalSlotId() {
+        return mLogicalSlotId;
+    }
+
+    public int getSlotPortId() {
+        return mSlotPortId;
+    }
+
+    public String getEID() {
+        return mEID;
+    }
+
+    public String getATR() {
+        return mATR;
+    }
+
+    public String getICCID() {
+        return mICCID;
+    }
+
+    public int getUniversalPinState() {
+        return mUniversalPinState;
+    }
+
+    public int getGsmAppIndex() {
+        return mSimProfileInfoList[mSimProfileId].getGsmAppIndex();
+    }
+
+    public int getCdmaAppIndex() {
+        return mSimProfileInfoList[mSimProfileId].getCdmaAppIndex();
+    }
+
+    public int getImsAppIndex() {
+        return mSimProfileInfoList[mSimProfileId].getImsAppIndex();
+    }
+
+    public int getNumOfSimApp() {
+        return mSimProfileInfoList[mSimProfileId].getNumOfSimApp();
+    }
+
+    public AppStatus[] getSimApp() {
+        return mSimApp;
+    }
+
+    public ArrayList<SimAppData> getSimAppList() {
+        return mSimAppList;
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/PhoneStateListenerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/PhoneStateListenerTest.java
index dfe41cf..0fbfc5a 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/PhoneStateListenerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/PhoneStateListenerTest.java
@@ -26,6 +26,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -107,6 +108,7 @@
     private static ConnectivityManager mCm;
     private HandlerThread mHandlerThread;
     private Handler mHandler;
+    private PackageManager mPackageManager;
     private static final List<Integer> DATA_CONNECTION_STATE = Arrays.asList(
             TelephonyManager.DATA_CONNECTED,
             TelephonyManager.DATA_DISCONNECTED,
@@ -142,6 +144,7 @@
         mHandlerThread = new HandlerThread("PhoneStateListenerTest");
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
+        mPackageManager = getContext().getPackageManager();
     }
 
     @After
@@ -398,8 +401,8 @@
 
     @Test
     public void testOnPreciseCallStateChanged() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
         assertThat(mOnPreciseCallStateChangedCalled).isFalse();
@@ -433,8 +436,8 @@
 
     @Test
     public void testOnCallDisconnectCauseChanged() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
         assertThat(mOnCallDisconnectCauseChangedCalled).isFalse();
@@ -465,8 +468,8 @@
 
     @Test
     public void testOnImsCallDisconnectCauseChanged() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
         assertThat(mOnImsCallDisconnectCauseChangedCalled).isFalse();
@@ -496,8 +499,8 @@
 
     @Test
     public void testOnPhoneStateListenerExecutorWithSrvccChanged() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
         assertThat(mSrvccStateChangedCalled).isFalse();
@@ -528,8 +531,8 @@
 
     @Test
     public void testOnRadioPowerStateChanged() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
         assertThat(mOnRadioPowerStateChangedCalled).isFalse();
@@ -596,8 +599,8 @@
 
     @Test
     public void testOnPreciseDataConnectionStateChanged() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
         assertThat(mOnCallDisconnectCauseChangedCalled).isFalse();
@@ -906,8 +909,8 @@
 
     @Test
     public void testOnOutgoingSmsEmergencyNumberChanged() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
 
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index 5335f96..074f2037 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -49,7 +49,6 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionPlan;
 import android.telephony.TelephonyManager;
-import android.telephony.cts.util.CarrierPrivilegeUtils;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
@@ -59,6 +58,7 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.CarrierPrivilegeUtils;
 import com.android.compatibility.common.util.ShellIdentityUtils;
 import com.android.compatibility.common.util.SystemUtil;
 import com.android.compatibility.common.util.TestThread;
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 97f44f4..482cd92 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyCallbackTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyCallbackTest.java
@@ -28,6 +28,7 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -116,6 +117,7 @@
     private static ConnectivityManager mCm;
     private HandlerThread mHandlerThread;
     private Handler mHandler;
+    private PackageManager mPackageManager;
     private static final List<Integer> DATA_CONNECTION_STATE = Arrays.asList(
             TelephonyManager.DATA_CONNECTED,
             TelephonyManager.DATA_DISCONNECTED,
@@ -151,6 +153,7 @@
         mHandlerThread = new HandlerThread("TelephonyCallbackTest");
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
+        mPackageManager = getContext().getPackageManager();
     }
 
     @After
@@ -487,8 +490,8 @@
 
     @Test
     public void testOnPreciseCallStateChangedByRegisterTelephonyCallback() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
         assertThat(mOnPreciseCallStateChangedCalled).isFalse();
@@ -531,8 +534,8 @@
 
     @Test
     public void testOnCallDisconnectCauseChangedByRegisterTelephonyCallback() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
         assertThat(mOnCallDisconnectCauseChangedCalled).isFalse();
@@ -570,8 +573,8 @@
 
     @Test
     public void testOnImsCallDisconnectCauseChangedByRegisterTelephonyCallback() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
         assertThat(mOnImsCallDisconnectCauseChangedCalled).isFalse();
@@ -609,8 +612,8 @@
 
     @Test
     public void testOSrvccStateChangedByRegisterTelephonyCallback() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
         assertThat(mSrvccStateChangedCalled).isFalse();
@@ -649,8 +652,8 @@
 
     @Test
     public void testOnRadioPowerStateChangedByRegisterTelephonyCallback() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
         assertThat(mOnRadioPowerStateChangedCalled).isFalse();
@@ -757,8 +760,8 @@
     @Test
     public void testOnPreciseDataConnectionStateChangedByRegisterTelephonyCallback()
             throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
         assertThat(mOnCallDisconnectCauseChangedCalled).isFalse();
@@ -1365,8 +1368,8 @@
 
     @Test
     public void testOnPhysicalChannelConfigChanged() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
 
@@ -1404,8 +1407,8 @@
 
     @Test
     public void testOnDataEnabledChangedByRegisterTelephonyCallback() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
 
@@ -1445,8 +1448,8 @@
 
     @Test
     public void testOnAllowedNetworkTypesChangedByRegisterPhoneStateListener() throws Throwable {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
             return;
         }
         long originalAllowedNetworkTypeUser = ShellIdentityUtils.invokeMethodWithShellPermissions(
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 6f0e3f5..b4d4986 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java
@@ -24,6 +24,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
@@ -42,14 +43,22 @@
 public class TelephonyManagerTestOnMockModem {
     private static final String TAG = "TelephonyManagerTestOnMockModem";
     private static MockModemManager sMockModemManager;
-    private TelephonyManager mTelephonyManager =
-            (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
+    private static TelephonyManager sTelephonyManager;
 
     @BeforeClass
     public static void beforeAllTests() throws Exception {
 
         Log.d(TAG, "TelephonyManagerTestOnMockModem#beforeAllTests()");
 
+        final PackageManager pm = getContext().getPackageManager();
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
+            return;
+        }
+
+        sTelephonyManager =
+                (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
+
         sMockModemManager = new MockModemManager();
         assertNotNull(sMockModemManager);
         assertTrue(sMockModemManager.connectMockModemService());
@@ -73,32 +82,42 @@
     public void testSimStateChange() throws Throwable {
         Log.d(TAG, "TelephonyManagerTestOnMockModem#testSimStateChange");
 
-        int simCardState = mTelephonyManager.getSimCardState();
+        int slotId = 0;
+        int simCardState = sTelephonyManager.getSimCardState();
         Log.d(TAG, "Current SIM card state: " + simCardState);
 
         assertTrue(
                 Arrays.asList(TelephonyManager.SIM_STATE_UNKNOWN, TelephonyManager.SIM_STATE_ABSENT)
                         .contains(simCardState));
 
-        int slotId = 0;
-        sMockModemManager.setSimPresent(slotId);
-
-        simCardState = mTelephonyManager.getSimCardState();
-        Log.d(TAG, "New SIM card state: " + simCardState);
+        // Insert a SIM
+        assertTrue(
+                sMockModemManager.insertSimCard(
+                        slotId, MockSimService.MOCK_SIM_PROFILE_ID_TWN_CHT));
+        simCardState = sTelephonyManager.getSimCardState();
         assertEquals(TelephonyManager.SIM_STATE_PRESENT, simCardState);
+
+        // Check SIM state ready
+        simCardState = sTelephonyManager.getSimState();
+        assertEquals(TelephonyManager.SIM_STATE_READY, simCardState);
+
+        // Remove the SIM
+        assertTrue(sMockModemManager.removeSimCard(slotId));
+        simCardState = sTelephonyManager.getSimCardState();
+        assertEquals(TelephonyManager.SIM_STATE_ABSENT, simCardState);
     }
 
     @Test
     public void testRadioPowerToggle() throws Throwable {
         Log.d(TAG, "TelephonyManagerTestOnMockModem#testRadioPowerToggle");
 
-        int radioState = mTelephonyManager.getRadioPowerState();
+        int radioState = sTelephonyManager.getRadioPowerState();
         Log.d(TAG, "Radio state: " + radioState);
 
         // Toggle radio power
         try {
             ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
-                    mTelephonyManager,
+                    sTelephonyManager,
                     (tm) -> tm.toggleRadioOnOff(),
                     SecurityException.class,
                     "android.permission.MODIFY_PHONE_STATE");
@@ -112,12 +131,12 @@
                 radioState == TelephonyManager.RADIO_POWER_ON
                         ? TelephonyManager.RADIO_POWER_OFF
                         : TelephonyManager.RADIO_POWER_ON;
-        assertEquals(mTelephonyManager.getRadioPowerState(), toggleRadioState);
+        assertEquals(sTelephonyManager.getRadioPowerState(), toggleRadioState);
 
         // Toggle radio power again back to original radio state
         try {
             ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
-                    mTelephonyManager,
+                    sTelephonyManager,
                     (tm) -> tm.toggleRadioOnOff(),
                     SecurityException.class,
                     "android.permission.MODIFY_PHONE_STATE");
@@ -127,7 +146,7 @@
 
         // Wait the radio state update in Framework
         TimeUnit.SECONDS.sleep(1);
-        assertEquals(mTelephonyManager.getRadioPowerState(), radioState);
+        assertEquals(sTelephonyManager.getRadioPowerState(), radioState);
 
         Log.d(TAG, "Test Done ");
     }
@@ -136,7 +155,7 @@
     public void testRadioPowerWithFailureResults() throws Throwable {
         Log.d(TAG, "TelephonyManagerTestOnMockModem#testRadioPowerWithFailureResults");
 
-        int radioState = mTelephonyManager.getRadioPowerState();
+        int radioState = sTelephonyManager.getRadioPowerState();
         Log.d(TAG, "Radio state: " + radioState);
 
         int slotId = 0;
@@ -153,7 +172,7 @@
             boolean state = (toggleRadioState == TelephonyManager.RADIO_POWER_ON) ? true : false;
             result =
                     ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
-                            mTelephonyManager,
+                            sTelephonyManager,
                             (tm) -> tm.setRadioPower(state),
                             SecurityException.class,
                             "android.permission.MODIFY_PHONE_STATE");
@@ -163,7 +182,7 @@
 
         TimeUnit.SECONDS.sleep(1);
         assertTrue(result);
-        assertNotEquals(mTelephonyManager.getRadioPowerState(), toggleRadioState);
+        assertNotEquals(sTelephonyManager.getRadioPowerState(), toggleRadioState);
 
         // Reset the modified error response of RIL_REQUEST_RADIO_POWER to the original behavior
         // and -1 means to disable the modifed mechanism in mock modem
@@ -174,7 +193,7 @@
             boolean state = (radioState == TelephonyManager.RADIO_POWER_ON) ? true : false;
             result =
                     ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
-                            mTelephonyManager,
+                            sTelephonyManager,
                             (tm) -> tm.setRadioPower(state),
                             SecurityException.class,
                             "android.permission.MODIFY_PHONE_STATE");
@@ -183,6 +202,6 @@
         }
         TimeUnit.SECONDS.sleep(1);
         assertTrue(result);
-        assertEquals(mTelephonyManager.getRadioPowerState(), radioState);
+        assertEquals(sTelephonyManager.getRadioPowerState(), radioState);
     }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java
index 71ffeea..f63a47e 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java
@@ -82,6 +82,8 @@
     public static final int WAIT_FOR_CONDITION = 3000;
     public static final int WAIT_FOR_CALL_STATE = 10000;
     public static final int WAIT_FOR_CALL_DISCONNECT = 5000;
+    public static final int WAIT_FOR_CALL_STATE_HOLD = 3000;
+    public static final int WAIT_FOR_CALL_STATE_RESUME = 3000;
     public static final int LATCH_WAIT = 0;
     public static final int LATCH_INCALL_SERVICE_BOUND = 1;
     public static final int LATCH_INCALL_SERVICE_UNBOUND = 2;
@@ -92,7 +94,8 @@
     public static final int LATCH_IS_CALL_DISCONNECTING = 7;
     public static final int LATCH_IS_CALL_DISCONNECTED = 8;
     public static final int LATCH_IS_CALL_RINGING = 9;
-    public static final int LATCH_MAX = 10;
+    public static final int LATCH_IS_CALL_HOLDING = 10;
+    public static final int LATCH_MAX = 11;
 
     private static boolean sIsBound = false;
     private static int sCounter = 5553639;
@@ -318,6 +321,9 @@
             fail("Invalid state found: the test subscription in slot " + sTestSlot + " changed "
                     + "during this test.");
         }
+    }
+
+    public void bindImsService() throws Exception  {
         // Connect to the ImsService with the MmTel feature.
         assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
                 .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
@@ -336,8 +342,8 @@
         MmTelFeature.MmTelCapabilities capabilities = new MmTelFeature.MmTelCapabilities(
                 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE);
         // Set Registered and VoLTE capable
-        sServiceConnector.getCarrierService().getImsService().getRegistration(0).onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        sServiceConnector.getCarrierService().getImsService().getRegistrationForSubscription(
+                sTestSlot, sTestSub).onRegistered(ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
         sServiceConnector.getCarrierService().getMmTelFeature().setCapabilities(capabilities);
         sServiceConnector.getCarrierService().getMmTelFeature()
                 .notifyCapabilitiesStatusChanged(capabilities);
@@ -371,6 +377,8 @@
         if (!ImsUtils.shouldTestImsService()) {
             return;
         }
+
+        bindImsService();
         mServiceCallBack = new ServiceCallBack();
         InCallServiceStateValidator.setCallbacks(mServiceCallBack);
 
@@ -407,6 +415,7 @@
             return;
         }
 
+        bindImsService();
         mServiceCallBack = new ServiceCallBack();
         InCallServiceStateValidator.setCallbacks(mServiceCallBack);
 
@@ -449,11 +458,11 @@
     }
 
     @Test
-    public void testIncomingCall() {
+    public void testIncomingCall() throws Exception {
         if (!ImsUtils.shouldTestImsService()) {
             return;
         }
-
+        bindImsService();
         mServiceCallBack = new ServiceCallBack();
         InCallServiceStateValidator.setCallbacks(mServiceCallBack);
 
@@ -480,6 +489,185 @@
         waitForUnboundService();
     }
 
+    @Test
+    public void testOutGoingCallForExecutor() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        sServiceConnector.setExecutorTestType(true);
+        bindImsService();
+
+        mServiceCallBack = new ServiceCallBack();
+        InCallServiceStateValidator.setCallbacks(mServiceCallBack);
+
+        TelecomManager telecomManager = (TelecomManager) InstrumentationRegistry
+                .getInstrumentation().getContext().getSystemService(Context.TELECOM_SERVICE);
+
+        final Uri imsUri = Uri.fromParts(PhoneAccount.SCHEME_TEL, String.valueOf(++sCounter), null);
+        Bundle extras = new Bundle();
+
+        // Place outgoing call
+        telecomManager.placeCall(imsUri, extras);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_ADDED, WAIT_FOR_CALL_STATE));
+
+        Call call = getCall(mCurrentCallId);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_DIALING, WAIT_FOR_CALL_STATE));
+
+        TestImsCallSessionImpl callSession = sServiceConnector.getCarrierService().getMmTelFeature()
+                .getImsCallsession();
+
+        isCallActive(call, callSession);
+
+        callingTestLatchCountdown(LATCH_WAIT, WAIT_FOR_CALL_DISCONNECT);
+        call.disconnect();
+
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_DISCONNECTING, WAIT_FOR_CALL_STATE));
+        isCallDisconnected(call, callSession);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_REMOVED, WAIT_FOR_CALL_STATE));
+        waitForUnboundService();
+    }
+
+    @Test
+    public void testOutGoingCallHoldResume() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        bindImsService();
+        mServiceCallBack = new ServiceCallBack();
+        InCallServiceStateValidator.setCallbacks(mServiceCallBack);
+
+        TelecomManager telecomManager = (TelecomManager) InstrumentationRegistry
+                .getInstrumentation().getContext().getSystemService(Context.TELECOM_SERVICE);
+
+        final Uri imsUri = Uri.fromParts(PhoneAccount.SCHEME_TEL, String.valueOf(++sCounter), null);
+        Bundle extras = new Bundle();
+
+        // Place outgoing call
+        telecomManager.placeCall(imsUri, extras);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_ADDED, WAIT_FOR_CALL_STATE));
+
+        Call call = getCall(mCurrentCallId);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_DIALING, WAIT_FOR_CALL_STATE));
+
+        TestImsCallSessionImpl callSession = sServiceConnector.getCarrierService().getMmTelFeature()
+                .getImsCallsession();
+
+        isCallActive(call, callSession);
+        callingTestLatchCountdown(LATCH_WAIT, WAIT_FOR_CALL_STATE_HOLD);
+        // Put on hold
+        call.hold();
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_HOLDING, WAIT_FOR_CALL_STATE));
+
+        callingTestLatchCountdown(LATCH_WAIT, WAIT_FOR_CALL_STATE_RESUME);
+        // Put on resume
+        call.unhold();
+        isCallActive(call, callSession);
+
+        callingTestLatchCountdown(LATCH_WAIT, WAIT_FOR_CALL_DISCONNECT);
+        call.disconnect();
+
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_DISCONNECTING, WAIT_FOR_CALL_STATE));
+        isCallDisconnected(call, callSession);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_REMOVED, WAIT_FOR_CALL_STATE));
+        waitForUnboundService();
+    }
+
+    @Test
+    public void testOutGoingCallHoldFailure() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        bindImsService();
+        mServiceCallBack = new ServiceCallBack();
+        InCallServiceStateValidator.setCallbacks(mServiceCallBack);
+
+        TelecomManager telecomManager = (TelecomManager) InstrumentationRegistry
+                .getInstrumentation().getContext().getSystemService(Context.TELECOM_SERVICE);
+
+        final Uri imsUri = Uri.fromParts(PhoneAccount.SCHEME_TEL, String.valueOf(++sCounter), null);
+        Bundle extras = new Bundle();
+
+        // Place outgoing call
+        telecomManager.placeCall(imsUri, extras);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_ADDED, WAIT_FOR_CALL_STATE));
+
+        Call call = getCall(mCurrentCallId);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_DIALING, WAIT_FOR_CALL_STATE));
+
+        TestImsCallSessionImpl callSession = sServiceConnector.getCarrierService().getMmTelFeature()
+                .getImsCallsession();
+
+        isCallActive(call, callSession);
+        callSession.addTestType(TestImsCallSessionImpl.TEST_TYPE_HOLD_FAILED);
+
+        callingTestLatchCountdown(LATCH_WAIT, WAIT_FOR_CALL_STATE_HOLD);
+        call.hold();
+        assertTrue("call is not in Active State", (call.getDetails().getState()
+                == call.STATE_ACTIVE));
+
+        callingTestLatchCountdown(LATCH_WAIT, WAIT_FOR_CALL_DISCONNECT);
+        call.disconnect();
+
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_DISCONNECTING, WAIT_FOR_CALL_STATE));
+        isCallDisconnected(call, callSession);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_REMOVED, WAIT_FOR_CALL_STATE));
+        waitForUnboundService();
+    }
+
+
+    @Test
+    public void testOutGoingCallResumeFailure() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        bindImsService();
+        mServiceCallBack = new ServiceCallBack();
+        InCallServiceStateValidator.setCallbacks(mServiceCallBack);
+
+        TelecomManager telecomManager = (TelecomManager) InstrumentationRegistry
+                .getInstrumentation().getContext().getSystemService(Context.TELECOM_SERVICE);
+
+        final Uri imsUri = Uri.fromParts(PhoneAccount.SCHEME_TEL, String.valueOf(++sCounter), null);
+        Bundle extras = new Bundle();
+
+        // Place outgoing call
+        telecomManager.placeCall(imsUri, extras);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_ADDED, WAIT_FOR_CALL_STATE));
+
+        Call call = getCall(mCurrentCallId);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_DIALING, WAIT_FOR_CALL_STATE));
+
+        TestImsCallSessionImpl callSession = sServiceConnector.getCarrierService().getMmTelFeature()
+                .getImsCallsession();
+
+        isCallActive(call, callSession);
+
+        callingTestLatchCountdown(LATCH_WAIT, WAIT_FOR_CALL_STATE_HOLD);
+        // Put on hold
+        call.hold();
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_HOLDING, WAIT_FOR_CALL_STATE));
+
+        callSession.addTestType(TestImsCallSessionImpl.TEST_TYPE_RESUME_FAILED);
+        callingTestLatchCountdown(LATCH_WAIT, WAIT_FOR_CALL_STATE_RESUME);
+        call.unhold();
+        callingTestLatchCountdown(LATCH_WAIT, WAIT_FOR_CALL_STATE);
+        assertTrue("Call is not in Hold State", (call.getDetails().getState()
+                == call.STATE_HOLDING));
+
+
+        callingTestLatchCountdown(LATCH_WAIT, WAIT_FOR_CALL_DISCONNECT);
+        call.disconnect();
+
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_DISCONNECTING, WAIT_FOR_CALL_STATE));
+        isCallDisconnected(call, callSession);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_REMOVED, WAIT_FOR_CALL_STATE));
+        waitForUnboundService();
+    }
+
     public void waitForUnboundService() {
         waitUntilConditionIsTrueOrTimeout(
                 new Condition() {
@@ -624,6 +812,11 @@
                 }
                 case Call.STATE_RINGING : {
                     countDownLatch(LATCH_IS_CALL_RINGING);
+                    break;
+                }
+                case Call.STATE_HOLDING : {
+                    countDownLatch(LATCH_IS_CALL_HOLDING);
+                    break;
                 }
                 default:
                     break;
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
index ae6306a..a994d988 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
@@ -81,6 +81,12 @@
     private static final String COMMAND_SET_TEST_MODE_ENABLED = "src set-test-enabled ";
     private static final String COMMAND_SET_D2D_ENABLED = "d2d set-device-support ";
 
+    private boolean mIsTestTypeExecutor = false;
+
+    public void setExecutorTestType(boolean type) {
+        mIsTestTypeExecutor = type;
+    }
+
     private class TestCarrierServiceConnection implements ServiceConnection {
 
         private final CountDownLatch mLatch;
@@ -117,7 +123,7 @@
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
-            mCarrierService = null;
+            mExternalService = null;
         }
     }
 
@@ -143,11 +149,13 @@
             mIsServiceOverridden = true;
             switch (mConnectionType) {
                 case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
-                    setCarrierImsService("none");
+                    boolean unbindSent = setCarrierImsService("none");
+                    if (unbindSent) waitForCarrierPackageUnbind();
                     break;
                 }
                 case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
-                    setDeviceImsService("");
+                    boolean unbindSent = setDeviceImsService("");
+                    if (unbindSent) waitForDevicePackageUnbind();
                     break;
                 }
                 case CONNECTION_TYPE_DEFAULT_SMS_APP: {
@@ -157,6 +165,35 @@
             }
         }
 
+        void waitForCarrierPackageUnbind() {
+            TestImsService carrierService = getCarrierService();
+            if (carrierService == null) return;
+            // First unbind the local services
+            removeLocalCarrierServiceConnection();
+            // Then wait for AOSP to unbind if there is still an active binding.
+            boolean isBound = carrierService.isTelephonyBound();
+            if (ImsUtils.VDBG) Log.i(TAG, "waitForCarrierPackageUnbind: isBound=" + isBound);
+            if (isBound) {
+                // Wait for telephony to unbind to local ImsService
+                carrierService.waitForLatchCountdown(TestImsService.LATCH_ON_UNBIND);
+            }
+        }
+
+        void waitForDevicePackageUnbind() throws Exception {
+            // Wait until the ImsService unbinds
+            ITestExternalImsService externalService = getExternalService();
+            if (externalService == null) return;
+            // First unbind the local services
+            removeLocalExternalServiceConnection();
+            // Then wait for AOSP to unbind if there is still an active binding.
+            boolean isBound = externalService.isTelephonyBound();
+            if (ImsUtils.VDBG) Log.i(TAG, "waitForDevicePackageUnbind: isBound=" + isBound);
+            if (isBound) {
+                // Wait for telephony to unbind to external ImsService
+                externalService.waitForLatchCountdown(TestImsService.LATCH_ON_UNBIND);
+            }
+        }
+
         boolean overrideService(ImsFeatureConfiguration config) throws Exception {
             mIsServiceOverridden = true;
             switch (mConnectionType) {
@@ -480,6 +517,11 @@
             return false;
         }
         mCarrierService.resetState();
+        if (mIsTestTypeExecutor) {
+            mCarrierService.setExecutorTestType(mIsTestTypeExecutor);
+            // reset the mIsTestTypeExecutor value
+            mIsTestTypeExecutor = false;
+        }
         return true;
     }
 
@@ -559,17 +601,27 @@
         }
     }
 
-    // Detect and disconnect all active services.
-    void disconnectServices() throws Exception {
-        // Remove local connection
+    void removeLocalCarrierServiceConnection() {
         if (mCarrierServiceConn != null) {
             mInstrumentation.getContext().unbindService(mCarrierServiceConn);
+            mCarrierServiceConn = null;
             mCarrierService = null;
         }
+    }
+
+    void removeLocalExternalServiceConnection() {
         if (mExternalServiceConn != null) {
             mInstrumentation.getContext().unbindService(mExternalServiceConn);
+            mExternalServiceConn = null;
             mExternalService = null;
         }
+    }
+
+    // Detect and disconnect all active services.
+    void disconnectServices() throws Exception {
+        // Remove local connections
+        removeLocalCarrierServiceConnection();
+        removeLocalExternalServiceConnection();
         mDeviceServiceConnection.restoreOriginalPackage();
         mCarrierServiceConnection.restoreOriginalPackage();
         mDefaultSmsAppConnection.restoreOriginalPackage();
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 57dbeed..01361ff 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
@@ -60,6 +60,7 @@
 import android.telephony.ims.SipDelegateManager;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.feature.RcsFeature;
 import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
 import android.telephony.ims.stub.CapabilityExchangeEventListener;
 import android.telephony.ims.stub.ImsConfigImplBase;
@@ -87,6 +88,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
@@ -101,10 +103,36 @@
 
     private static ImsServiceConnector sServiceConnector;
 
+    private static final int KEY_VOLTE_PROVISIONING_STATUS =
+            ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS;
+    private static final int KEY_VT_PROVISIONING_STATUS =
+            ProvisioningManager.KEY_VT_PROVISIONING_STATUS;
+    private static final int KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE =
+            ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE;
+    private static final int KEY_EAB_PROVISIONING_STATUS =
+            ProvisioningManager.KEY_EAB_PROVISIONING_STATUS;
+
+    private static final int MMTEL_CAP_VOICE = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE;
+    private static final int MMTEL_CAP_VIDEO = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO;
+    private static final int MMTEL_CAP_UT = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT;
+    private static final int MMTEL_CAP_SMS = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS;
+    private static final int MMTEL_CAP_COMPOSER =
+            MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER;
+
     private static final int RCS_CAP_NONE = RcsImsCapabilities.CAPABILITY_TYPE_NONE;
     private static final int RCS_CAP_OPTIONS = RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE;
     private static final int RCS_CAP_PRESENCE = RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE;
 
+    private static final int IMS_REGI_TECH_NONE = ImsRegistrationImplBase.REGISTRATION_TECH_NONE;
+    private static final int IMS_REGI_TECH_LTE = ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
+    private static final int IMS_REGI_TECH_IWLAN = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
+    private static final int IMS_REGI_TECH_CROSS_SIM =
+            ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM;
+    private static final int IMS_REGI_TECH_NR = ImsRegistrationImplBase.REGISTRATION_TECH_NR;
+
+    private static final String SUPPORT_PROVISION_STATUS_FOR_CAPABILITY_STRING =
+            "SUPPORT_PROVISION_STATUS_FOR_CAPABILITY";
+
     private static final String MSG_CONTENTS = "hi";
     private static final String EXPECTED_RECEIVED_MESSAGE = "foo5";
     private static final String DEST_NUMBER = "5555554567";
@@ -359,12 +387,14 @@
     @After
     public void afterTest() throws Exception {
         TelephonyUtils.resetCompatCommand(InstrumentationRegistry.getInstrumentation(),
-                TelephonyUtils.CTS_APP_PACKAGE,
-                SUPPORT_PUBLISHING_STATE_STRING);
+                TelephonyUtils.CTS_APP_PACKAGE, SUPPORT_PUBLISHING_STATE_STRING);
+        TelephonyUtils.resetCompatCommand(InstrumentationRegistry.getInstrumentation(),
+                TelephonyUtils.CTS_APP_PACKAGE, SUPPORT_PROVISION_STATUS_FOR_CAPABILITY_STRING);
+
         if (!ImsUtils.shouldTestImsService()) {
             return;
         }
-        // Unbind the GTS ImsService after the test completes.
+        // Unbind the ImsService after the test completes.
         if (sServiceConnector != null) {
             sServiceConnector.setSingleRegistrationTestModeEnabled(false);
             sServiceConnector.disconnectCarrierImsService();
@@ -387,6 +417,26 @@
                 TestImsService.LATCH_CREATE_RCS);
         assertNotNull("ImsService created, but ImsService#createRcsFeature was not called!",
                 sServiceConnector.getCarrierService().getRcsFeature());
+        assertTrue("Not expected subId received!",
+                isExpectedSubId(sServiceConnector.getCarrierService().getSubIDs()));
+    }
+
+    @Test
+    public void testCarrierImsServiceBindRcsFeatureForExecutor() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        sServiceConnector.setExecutorTestType(true);
+        // Connect to the ImsService with the RCS feature.
+        assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+                .build()));
+        // The RcsFeature is created when the ImsService is bound. If it wasn't created, then the
+        // Framework did not call it.
+        sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_RCS);
+        assertNotNull("ImsService created, but ImsService#createRcsFeature was not called!",
+                sServiceConnector.getCarrierService().getRcsFeature());
     }
 
     @Test
@@ -407,6 +457,8 @@
         // Wait for the framework to set the capabilities on the ImsService
         sServiceConnector.getCarrierService().waitForLatchCountdown(
                 TestImsService.LATCH_MMTEL_CAP_SET);
+        assertTrue("Not expected subId received!",
+                isExpectedSubId(sServiceConnector.getCarrierService().getSubIDs()));
     }
 
     @Test
@@ -436,6 +488,8 @@
         assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
                 TestImsService.LATCH_DISABLE_IMS));
         assertFalse(sServiceConnector.getCarrierService().isEnabled());
+        assertTrue("Not expected subId received!",
+                isExpectedSubId(sServiceConnector.getCarrierService().getSubIDs()));
     }
 
     @Test
@@ -464,6 +518,41 @@
         // Wait for the framework to set the capabilities on the ImsService
         sServiceConnector.getCarrierService().waitForLatchCountdown(
                 TestImsService.LATCH_MMTEL_CAP_SET);
+        assertTrue("Not expected subId received!",
+                isExpectedSubId(sServiceConnector.getCarrierService().getSubIDs()));
+    }
+
+    @Test
+    public void testCarrierImsServiceBindRcsChangeToMmtelCompat() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        // Connect to the ImsService with the RCS feature.
+        ImsFeatureConfiguration config = new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+                .build();
+        assertTrue(sServiceConnector.connectCarrierImsServiceLocally());
+        sServiceConnector.getCarrierService().resetState();
+        // Set the flag for ImsService compatibility test.
+        sServiceConnector.getCarrierService().setImsServiceCompat();
+        assertTrue(sServiceConnector.triggerFrameworkConnectionToCarrierImsService(config));
+        // The RcsFeature is created when the ImsService is bound. If it wasn't created, then the
+        // Framework did not call it.
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_RCS));
+
+        // Change the supported feature to MMTEl
+        sServiceConnector.getCarrierService().getImsServiceCompat().onUpdateSupportedImsFeatures(
+                new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL).build());
+
+        // createMmTelFeature should be called.
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_CREATE_MMTEL));
+
+        // Wait for the framework to set the capabilities on the ImsService
+        sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_MMTEL_CAP_SET);
     }
 
     @Test
@@ -501,6 +590,8 @@
         // Wait for the framework to set the capabilities on the ImsService
         sServiceConnector.getCarrierService().waitForLatchCountdown(
                 TestImsService.LATCH_MMTEL_CAP_SET);
+        assertTrue("Not expected subId received!",
+                isExpectedSubId(sServiceConnector.getCarrierService().getSubIDs()));
     }
 
     @Test
@@ -944,28 +1035,28 @@
         assertEquals(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, deregResult.getCode());
 
         // Start registration
-        verifyRegistering(ImsRegistrationImplBase.REGISTRATION_TECH_LTE, featureTags, mRegQueue,
+        verifyRegistering(IMS_REGI_TECH_LTE, featureTags, mRegQueue,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, 0 /*expected flags*/);
 
         // move to NR
-        verifyRegistering(ImsRegistrationImplBase.REGISTRATION_TECH_NR, featureTags, mRegQueue,
+        verifyRegistering(IMS_REGI_TECH_NR, featureTags, mRegQueue,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, 0 /*expected flags*/);
 
         // move to cross sim
-        verifyRegistering(ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM, featureTags,
+        verifyRegistering(IMS_REGI_TECH_CROSS_SIM, featureTags,
                 mRegQueue, AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
                 ImsRegistrationAttributes.ATTR_EPDG_OVER_CELL_INTERNET);
 
         // Complete registration
-        verifyRegistered(ImsRegistrationImplBase.REGISTRATION_TECH_LTE, featureTags, mRegQueue,
+        verifyRegistered(IMS_REGI_TECH_LTE, featureTags, mRegQueue,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, 0 /*expected flags*/);
 
         // move to NR
-        verifyRegistered(ImsRegistrationImplBase.REGISTRATION_TECH_NR, featureTags, mRegQueue,
+        verifyRegistered(IMS_REGI_TECH_NR, featureTags, mRegQueue,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, 0 /*expected flags*/);
 
         // move to cross sim
-        verifyRegistered(ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM, featureTags,
+        verifyRegistered(IMS_REGI_TECH_CROSS_SIM, featureTags,
                 mRegQueue, AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
                 ImsRegistrationAttributes.ATTR_EPDG_OVER_CELL_INTERNET);
 
@@ -1053,17 +1144,17 @@
 
         // Start registration
         sServiceConnector.getCarrierService().getImsRegistration().onRegistering(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
 
         // Complete registration
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
 
         // Fail handover to IWLAN
         sServiceConnector.getCarrierService().getImsRegistration().onTechnologyChangeFailed(
-                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
+                IMS_REGI_TECH_IWLAN,
                 new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE,
                         ImsReasonInfo.CODE_UNSPECIFIED, ""));
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
@@ -1071,7 +1162,7 @@
 
         // Ensure null ImsReasonInfo still results in non-null callback value.
         sServiceConnector.getCarrierService().getImsRegistration().onTechnologyChangeFailed(
-                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN, null);
+                IMS_REGI_TECH_IWLAN, null);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
         assertEquals(ImsReasonInfo.CODE_UNSPECIFIED, waitForIntResult(mQueue));
 
@@ -1193,7 +1284,7 @@
 
         // IMS registers
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
 
         // Framework should not trigger the device capabilities publish when the framework doesn't
         // receive that the RcsUceAdapter.CAPABILITY_TYPE_PRESENCE_UCE is enabled.
@@ -1386,7 +1477,7 @@
         featureTags.add(CHAT_FEATURE_TAG);
         featureTags.add(FILE_TRANSFER_FEATURE_TAG);
         ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE).setFeatureTags(featureTags).build();
+                IMS_REGI_TECH_LTE).setFeatureTags(featureTags).build();
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(attr);
         waitForParam(mQueue, attr);
 
@@ -1500,7 +1591,7 @@
 
         // IMS registers
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
 
         // Notify framework that the RCS capability status is changed and PRESENCE UCE is enabled.
         RcsImsCapabilities capabilities =
@@ -1610,7 +1701,7 @@
 
         // IMS registers
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
 
         // Notify framework that the RCS capability status is changed and PRESENCE UCE is enabled.
         RcsImsCapabilities capabilities =
@@ -1735,7 +1826,7 @@
 
         // IMS registers
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
 
         // Verify the PUBLISH request should not be triggered and the publish state is still
         // NOT_PUBLISHED even the IMS is registered.
@@ -1863,7 +1954,7 @@
 
         // IMS registers
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
 
         // Verify the PUBLISH request should not be triggered and the publish state is still
         // OK even the IMS is registered.
@@ -2002,7 +2093,7 @@
 
         // IMS registers
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
 
         // Notify framework that the RCS capability status is changed and PRESENCE UCE is enabled.
         RcsImsCapabilities capabilities =
@@ -2421,17 +2512,17 @@
 
         // Start registration
         sServiceConnector.getCarrierService().getImsRegistration().onRegistering(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
 
         // Complete registration
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
 
         // Fail handover to IWLAN
         sServiceConnector.getCarrierService().getImsRegistration().onTechnologyChangeFailed(
-                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
+                IMS_REGI_TECH_IWLAN,
                 new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE,
                         ImsReasonInfo.CODE_UNSPECIFIED, ""));
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
@@ -2505,14 +2596,14 @@
 
         // Start registration
         sServiceConnector.getCarrierService().getImsRegistration().onRegistering(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
         verifyRegistrationState(regManager, RegistrationManager.REGISTRATION_STATE_REGISTERING);
         verifyRegistrationTransportType(regManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
 
         // Complete registration
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
         verifyRegistrationState(regManager, RegistrationManager.REGISTRATION_STATE_REGISTERED);
         verifyRegistrationTransportType(regManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
@@ -2520,7 +2611,7 @@
 
         // Fail handover to IWLAN
         sServiceConnector.getCarrierService().getImsRegistration().onTechnologyChangeFailed(
-                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
+                IMS_REGI_TECH_IWLAN,
                 new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE,
                         ImsReasonInfo.CODE_UNSPECIFIED, ""));
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
@@ -2529,7 +2620,7 @@
 
         // handover to IWLAN
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
+                IMS_REGI_TECH_IWLAN);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
         verifyRegistrationTransportType(regManager, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
 
@@ -2620,35 +2711,35 @@
 
         // Start registration
         sServiceConnector.getCarrierService().getImsRegistration().onRegistering(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
         verifyRegistrationState(imsRcsManager, RegistrationManager.REGISTRATION_STATE_REGISTERING);
         verifyRegistrationTransportType(imsRcsManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
 
         // Complete registration
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
         verifyRegistrationState(imsRcsManager, RegistrationManager.REGISTRATION_STATE_REGISTERED);
         verifyRegistrationTransportType(imsRcsManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
 
         // Start registration over NR
         sServiceConnector.getCarrierService().getImsRegistration().onRegistering(
-                ImsRegistrationImplBase.REGISTRATION_TECH_NR);
+                IMS_REGI_TECH_NR);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
         verifyRegistrationState(imsRcsManager, RegistrationManager.REGISTRATION_STATE_REGISTERING);
         verifyRegistrationTransportType(imsRcsManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
 
         // Complete registration over NR
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_NR);
+                IMS_REGI_TECH_NR);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
         verifyRegistrationState(imsRcsManager, RegistrationManager.REGISTRATION_STATE_REGISTERED);
         verifyRegistrationTransportType(imsRcsManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
 
         // Fail handover to IWLAN
         sServiceConnector.getCarrierService().getImsRegistration().onTechnologyChangeFailed(
-                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
+                IMS_REGI_TECH_IWLAN,
                 new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE,
                         ImsReasonInfo.CODE_UNSPECIFIED, ""));
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
@@ -2657,7 +2748,7 @@
 
         // handover to IWLAN
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
+                IMS_REGI_TECH_IWLAN);
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
         verifyRegistrationTransportType(imsRcsManager, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(imsRcsManager,
@@ -2684,7 +2775,7 @@
                 .getMmTelFeature().getCapabilities();
         // Make sure we start off with every capability unavailable
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
         sServiceConnector.getCarrierService().getMmTelFeature()
                 .notifyCapabilitiesStatusChanged(new MmTelFeature.MmTelCapabilities());
 
@@ -2696,7 +2787,7 @@
             // Make sure we are tracking voice capability over LTE properly.
             assertEquals(fwCaps.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE),
                     mmTelManager.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                            ImsRegistrationImplBase.REGISTRATION_TECH_LTE));
+                            IMS_REGI_TECH_LTE));
         } finally {
             automan.dropShellPermissionIdentity();
         }
@@ -2745,7 +2836,7 @@
             automan.adoptShellPermissionIdentity();
             assertTrue(ImsUtils.retryUntilTrue(() -> mmTelManager.isAvailable(
                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE)));
+                    IMS_REGI_TECH_LTE)));
 
             mmTelManager.unregisterMmTelCapabilityCallback(callback);
         } finally {
@@ -2778,7 +2869,7 @@
                 .getMmTelFeature().getCapabilities();
         // Make sure we start off with every capability unavailable
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
         sServiceConnector.getCarrierService().getMmTelFeature()
                 .notifyCapabilitiesStatusChanged(new MmTelFeature.MmTelCapabilities());
 
@@ -2790,7 +2881,7 @@
             // Make sure we are tracking voice capability over LTE properly.
             assertEquals(fwCaps.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE),
                     mmTelManager.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE));
+                    IMS_REGI_TECH_LTE));
         } finally {
             automan.dropShellPermissionIdentity();
         }
@@ -2835,7 +2926,7 @@
             automan.adoptShellPermissionIdentity();
             assertTrue(ImsUtils.retryUntilTrue(() -> mmTelManager.isAvailable(
                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER,
-                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE)));
+                    IMS_REGI_TECH_LTE)));
 
             mmTelManager.unregisterMmTelCapabilityCallback(callback);
         } finally {
@@ -2872,7 +2963,7 @@
 
         // Make sure we start off with every capability unavailable
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
         MmTelFeature.MmTelCapabilities stdCapabilities = new MmTelFeature.MmTelCapabilities();
         sServiceConnector.getCarrierService().getMmTelFeature()
                 .notifyCapabilitiesStatusChanged(stdCapabilities);
@@ -2890,7 +2981,7 @@
                 automan.adoptShellPermissionIdentity();
                 boolean isAvailableBeforeStatusChange = mmTelManager.isAvailable(
                         MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                        ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                        IMS_REGI_TECH_LTE);
                 assertFalse(isAvailableBeforeStatusChange);
             } finally {
                 automan.dropShellPermissionIdentity();
@@ -2907,7 +2998,7 @@
                         automan.adoptShellPermissionIdentity();
                         boolean isVoiceAvailable = mmTelManager
                                 .isAvailable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                                        ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                                        IMS_REGI_TECH_LTE);
 
                         voiceIsAvailable.offer(isVoiceAvailable);
                     } finally {
@@ -2963,12 +3054,12 @@
         // Connect to device ImsService with RcsFeature
         triggerFrameworkConnectToLocalImsServiceBindRcsFeature();
 
-        int registrationTech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
+        int registrationTech = IMS_REGI_TECH_LTE;
         ImsRcsManager imsRcsManager = imsManager.getImsRcsManager(sTestSub);
 
         // Make sure we start off with none-capability
         sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                IMS_REGI_TECH_LTE);
         RcsImsCapabilities noCapabilities = new RcsImsCapabilities(RCS_CAP_NONE);
         sServiceConnector.getCarrierService().getRcsFeature()
                 .notifyCapabilitiesStatusChanged(noCapabilities);
@@ -3030,7 +3121,7 @@
 
         // Verify the callback and the api isAvailable that the capabilities is NONE in the
         // beginning.
-        int radioTechLTE = ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
+        int radioTechLTE = IMS_REGI_TECH_LTE;
         int capCb = waitForResult(availabilityChanged);
         assertEquals(capCb, RCS_CAP_NONE);
         availabilityChanged.clear();
@@ -3145,6 +3236,537 @@
         }
     }
 
+    @Test
+    public void testProvisioningManagerWhenMmtelProvisionIsRequired() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        // test in case provision for mmtel is required
+        PersistableBundle bundle = new PersistableBundle();
+
+        PersistableBundle innerBundle = new PersistableBundle();
+        innerBundle.putIntArray(
+                CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY,
+                new int[]{IMS_REGI_TECH_LTE, IMS_REGI_TECH_IWLAN}
+        );
+        innerBundle.putIntArray(
+                CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY,
+                new int[]{IMS_REGI_TECH_LTE}
+        );
+
+        bundle.putPersistableBundle(
+                CarrierConfigManager.Ims.KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE,
+                innerBundle);
+
+        overrideCarrierConfig(bundle);
+
+        triggerFrameworkConnectToCarrierImsService();
+        ProvisioningManager provisioningManager =
+                ProvisioningManager.createForSubscriptionId(sTestSub);
+
+        LinkedBlockingQueue<Pair<Integer, Integer>> mIntQueue = new LinkedBlockingQueue<>();
+        LinkedBlockingQueue<Pair<Integer, Pair<Integer, Boolean>>> mOnFeatureChangedQueue =
+                new LinkedBlockingQueue<>();
+
+        ProvisioningManager.Callback callback = new ProvisioningManager.Callback() {
+            @Override
+            public void onProvisioningIntChanged(int item, int value) {
+                mIntQueue.offer(new Pair<>(item, value));
+            }
+        };
+
+        ProvisioningManager.FeatureProvisioningCallback featureProvisioningCallback =
+                new ProvisioningManager.FeatureProvisioningCallback() {
+            @Override
+            public void onFeatureProvisioningChanged(
+                    @MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
+                    @ImsRegistrationImplBase.ImsRegistrationTech int tech,
+                    boolean isProvisioned) {
+                mOnFeatureChangedQueue.offer(new Pair<>(capability,
+                        new Pair<>(tech, isProvisioned)));
+            }
+        };
+
+        final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            automan.adoptShellPermissionIdentity();
+            provisioningManager.registerProvisioningChangedCallback(getContext().getMainExecutor(),
+                    callback);
+            provisioningManager.registerFeatureProvisioningChangedCallback(
+                    getContext().getMainExecutor(), featureProvisioningCallback);
+
+            TelephonyUtils.enableCompatCommand(InstrumentationRegistry.getInstrumentation(),
+                    TelephonyUtils.CTS_APP_PACKAGE,
+                    SUPPORT_PROVISION_STATUS_FOR_CAPABILITY_STRING);
+
+            // test get/setProvisioningStatusForCapability for VoLTE
+            assertTrue(provisioningManager.isProvisioningRequiredForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_LTE));
+            boolean isProvisioned = provisioningManager
+                    .getProvisioningStatusForCapability(MMTEL_CAP_VOICE, IMS_REGI_TECH_LTE);
+            provisioningManager.setProvisioningStatusForCapability(MMTEL_CAP_VOICE,
+                    IMS_REGI_TECH_LTE, !isProvisioned);
+            assertTrue(waitForParam(mOnFeatureChangedQueue,
+                    new Pair<>(MMTEL_CAP_VOICE, new Pair<>(IMS_REGI_TECH_LTE, !isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_VOLTE_PROVISIONING_STATUS, !isProvisioned ? 1 : 0)));
+            assertEquals(!isProvisioned, provisioningManager
+                    .getProvisioningStatusForCapability(MMTEL_CAP_VOICE, IMS_REGI_TECH_LTE));
+            mIntQueue.clear();
+            mOnFeatureChangedQueue.clear();
+            provisioningManager.setProvisioningStatusForCapability(MMTEL_CAP_VOICE,
+                    IMS_REGI_TECH_LTE, isProvisioned);
+            assertTrue(waitForParam(mOnFeatureChangedQueue,
+                    new Pair<>(MMTEL_CAP_VOICE, new Pair<>(IMS_REGI_TECH_LTE, isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_VOLTE_PROVISIONING_STATUS, isProvisioned ? 1 : 0)));
+            assertEquals(isProvisioned, provisioningManager
+                    .getProvisioningStatusForCapability(MMTEL_CAP_VOICE, IMS_REGI_TECH_LTE));
+
+            // test get/setProvisioningStatusForCapability for VoWIFI
+            assertTrue(provisioningManager.isProvisioningRequiredForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_IWLAN));
+            isProvisioned = provisioningManager
+                    .getProvisioningStatusForCapability(MMTEL_CAP_VOICE, IMS_REGI_TECH_IWLAN);
+            mIntQueue.clear();
+            mOnFeatureChangedQueue.clear();
+            provisioningManager.setProvisioningStatusForCapability(MMTEL_CAP_VOICE,
+                    IMS_REGI_TECH_IWLAN, !isProvisioned);
+            assertTrue(waitForParam(mOnFeatureChangedQueue,
+                    new Pair<>(MMTEL_CAP_VOICE, new Pair<>(IMS_REGI_TECH_IWLAN, !isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE, !isProvisioned ? 1 : 0)));
+            assertEquals(!isProvisioned, provisioningManager
+                    .getProvisioningStatusForCapability(MMTEL_CAP_VOICE, IMS_REGI_TECH_IWLAN));
+            mIntQueue.clear();
+            mOnFeatureChangedQueue.clear();
+            provisioningManager.setProvisioningStatusForCapability(MMTEL_CAP_VOICE,
+                    IMS_REGI_TECH_IWLAN, isProvisioned);
+            assertTrue(waitForParam(mOnFeatureChangedQueue,
+                    new Pair<>(MMTEL_CAP_VOICE, new Pair<>(IMS_REGI_TECH_IWLAN, isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE, isProvisioned ? 1 : 0)));
+            assertEquals(isProvisioned, provisioningManager
+                    .getProvisioningStatusForCapability(MMTEL_CAP_VOICE, IMS_REGI_TECH_IWLAN));
+
+            // test get/setProvisioningStatusForCapability for VT
+            assertTrue(provisioningManager.isProvisioningRequiredForCapability(
+                    MMTEL_CAP_VIDEO, IMS_REGI_TECH_LTE));
+            isProvisioned = provisioningManager
+                    .getProvisioningStatusForCapability(MMTEL_CAP_VIDEO, IMS_REGI_TECH_LTE);
+            mIntQueue.clear();
+            mOnFeatureChangedQueue.clear();
+            provisioningManager.setProvisioningStatusForCapability(MMTEL_CAP_VIDEO,
+                    IMS_REGI_TECH_LTE, !isProvisioned);
+            assertTrue(waitForParam(mOnFeatureChangedQueue,
+                    new Pair<>(MMTEL_CAP_VIDEO, new Pair<>(IMS_REGI_TECH_LTE, !isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_VT_PROVISIONING_STATUS, !isProvisioned ? 1 : 0)));
+            assertEquals(!isProvisioned, provisioningManager
+                    .getProvisioningStatusForCapability(MMTEL_CAP_VIDEO, IMS_REGI_TECH_LTE));
+            mIntQueue.clear();
+            mOnFeatureChangedQueue.clear();
+            provisioningManager.setProvisioningStatusForCapability(MMTEL_CAP_VIDEO,
+                    IMS_REGI_TECH_LTE, isProvisioned);
+            assertTrue(waitForParam(mOnFeatureChangedQueue,
+                    new Pair<>(MMTEL_CAP_VIDEO, new Pair<>(IMS_REGI_TECH_LTE, isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_VT_PROVISIONING_STATUS, isProvisioned ? 1 : 0)));
+            assertEquals(isProvisioned, provisioningManager
+                    .getProvisioningStatusForCapability(MMTEL_CAP_VIDEO, IMS_REGI_TECH_LTE));
+
+            TelephonyUtils.disableCompatCommand(InstrumentationRegistry.getInstrumentation(),
+                    TelephonyUtils.CTS_APP_PACKAGE,
+                    SUPPORT_PROVISION_STATUS_FOR_CAPABILITY_STRING);
+
+            // test get/setProvisioningStatusForCapability with lower bounding parameters
+            // when callback is not supported
+
+            isProvisioned = provisioningManager.getProvisioningStatusForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_LTE);
+            mIntQueue.clear();
+            mOnFeatureChangedQueue.clear();
+            provisioningManager.setProvisioningStatusForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_LTE, !isProvisioned);
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_VOLTE_PROVISIONING_STATUS, !isProvisioned ? 1 : 0)));
+            assertEquals(!isProvisioned,
+                    provisioningManager.getProvisioningStatusForCapability(
+                            MMTEL_CAP_VOICE, IMS_REGI_TECH_LTE));
+            isProvisioned = provisioningManager.getProvisioningStatusForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_IWLAN);
+            mIntQueue.clear();
+            mOnFeatureChangedQueue.clear();
+            provisioningManager.setProvisioningStatusForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_IWLAN, !isProvisioned);
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE, !isProvisioned ? 1 : 0)));
+            assertEquals(!isProvisioned,
+                    provisioningManager.getProvisioningStatusForCapability(
+                            MMTEL_CAP_VOICE, IMS_REGI_TECH_IWLAN));
+
+            isProvisioned = provisioningManager.getProvisioningStatusForCapability(
+                    MMTEL_CAP_VIDEO, IMS_REGI_TECH_LTE);
+            mIntQueue.clear();
+            mOnFeatureChangedQueue.clear();
+            provisioningManager.setProvisioningStatusForCapability(
+                    MMTEL_CAP_VIDEO, IMS_REGI_TECH_LTE, !isProvisioned);
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_VT_PROVISIONING_STATUS, !isProvisioned ? 1 : 0)));
+            assertEquals(!isProvisioned,
+                    provisioningManager.getProvisioningStatusForCapability(
+                            MMTEL_CAP_VIDEO, IMS_REGI_TECH_LTE));
+
+            automan.adoptShellPermissionIdentity();
+            provisioningManager.unregisterProvisioningChangedCallback(callback);
+            provisioningManager.unregisterFeatureProvisioningChangedCallback(
+                    featureProvisioningCallback);
+        } finally {
+            TelephonyUtils.resetCompatCommand(InstrumentationRegistry.getInstrumentation(),
+                    TelephonyUtils.CTS_APP_PACKAGE,
+                    SUPPORT_PROVISION_STATUS_FOR_CAPABILITY_STRING);
+            automan.dropShellPermissionIdentity();
+        }
+    }
+
+    @Test
+    public void testProvisioningManagerWhenMmtelProvisionIsNotRequired() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        // test in case provision for mmtel is required
+        PersistableBundle bundle = new PersistableBundle();
+        PersistableBundle innerBundle = new PersistableBundle();
+
+        bundle.putPersistableBundle(
+                CarrierConfigManager.Ims.KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE,
+                innerBundle);
+        overrideCarrierConfig(bundle);
+
+        triggerFrameworkConnectToCarrierImsService();
+        ProvisioningManager provisioningManager =
+                ProvisioningManager.createForSubscriptionId(sTestSub);
+
+        LinkedBlockingQueue<Pair<Integer, Integer>> mIntQueue = new LinkedBlockingQueue<>();
+        LinkedBlockingQueue<Pair<Integer, Pair<Integer, Boolean>>> mOnFeatureChangedQueue =
+                new LinkedBlockingQueue<>();
+
+
+        ProvisioningManager.Callback callback = new ProvisioningManager.Callback() {};
+
+        ProvisioningManager.FeatureProvisioningCallback featureProvisioningCallback =
+                new ProvisioningManager.FeatureProvisioningCallback() {};
+
+        final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            automan.adoptShellPermissionIdentity();
+            provisioningManager.registerProvisioningChangedCallback(getContext().getMainExecutor(),
+                    callback);
+            provisioningManager.registerFeatureProvisioningChangedCallback(
+                    getContext().getMainExecutor(), featureProvisioningCallback);
+
+            // In case provisioning is not required
+            // true will be returned regardless of stored value
+            // ignore set value whatever value is set by app
+            // therefore set different value from current then check if the value has changed
+            // test get/setProvisioningStatusForCapability for VoLTE
+
+            // isProvisioningRequiredForCapability should return false because provision is not
+            // required
+            assertTrue(!provisioningManager.isProvisioningRequiredForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_LTE));
+            // However, getProvisioningStatusForCapability() should return true because it does not
+            // require provision
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_LTE));
+            // put opposite value to check if the key is changed or not
+            provisioningManager.setProvisioningStatusForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_LTE, false);
+            // key value should not be changed whatever value is set
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_LTE));
+
+            // test case for VoWIFI
+            assertTrue(!provisioningManager.isProvisioningRequiredForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_IWLAN));
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_IWLAN));
+            provisioningManager.setProvisioningStatusForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_IWLAN, false);
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    MMTEL_CAP_VOICE, IMS_REGI_TECH_IWLAN));
+
+            // test case for VT
+            assertTrue(!provisioningManager.isProvisioningRequiredForCapability(
+                    MMTEL_CAP_VIDEO, IMS_REGI_TECH_LTE));
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    MMTEL_CAP_VIDEO, IMS_REGI_TECH_LTE));
+            provisioningManager.setProvisioningStatusForCapability(
+                    MMTEL_CAP_VIDEO, IMS_REGI_TECH_LTE, false);
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    MMTEL_CAP_VIDEO, IMS_REGI_TECH_LTE));
+
+            automan.adoptShellPermissionIdentity();
+            provisioningManager.unregisterProvisioningChangedCallback(callback);
+            provisioningManager.unregisterFeatureProvisioningChangedCallback(
+                    featureProvisioningCallback);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+    }
+
+    @Test
+    public void testProvisioningManagerWhenRcsProvisionIsRequired() throws Exception {
+        if (!ImsUtils.shouldTestImsSingleRegistration()) {
+            return;
+        }
+
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putBoolean(CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL,
+                true);
+
+        PersistableBundle innerBundle = new PersistableBundle();
+        innerBundle.putIntArray(
+                CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY,
+                new int[]{IMS_REGI_TECH_LTE, IMS_REGI_TECH_IWLAN, IMS_REGI_TECH_CROSS_SIM,
+                        IMS_REGI_TECH_NR}
+        );
+        bundle.putPersistableBundle(
+                CarrierConfigManager.Ims.KEY_RCS_REQUIRES_PROVISIONING_BUNDLE,
+                innerBundle);
+
+        overrideCarrierConfig(bundle);
+
+        triggerFrameworkConnectToImsServiceBindMmTelAndRcsFeature();
+
+        ProvisioningManager provisioningManager =
+                ProvisioningManager.createForSubscriptionId(sTestSub);
+
+        LinkedBlockingQueue<Pair<Integer, Integer>> mIntQueue = new LinkedBlockingQueue<>();
+        LinkedBlockingQueue<Pair<Integer, Pair<Integer, Boolean>>> mOnRcsFeatureChangedQueue =
+                new LinkedBlockingQueue<>();
+
+        ProvisioningManager.Callback callback = new ProvisioningManager.Callback() {
+            @Override
+            public void onProvisioningIntChanged(int item, int value) {
+                mIntQueue.offer(new Pair<>(item, value));
+            }
+
+        };
+
+        ProvisioningManager.FeatureProvisioningCallback featureProvisioningCallback =
+                new ProvisioningManager.FeatureProvisioningCallback() {
+            @Override
+            public void onRcsFeatureProvisioningChanged(
+                    @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+                    @ImsRegistrationImplBase.ImsRegistrationTech int tech,
+                    boolean isProvisioned) {
+                mOnRcsFeatureChangedQueue.offer(new Pair<>(capability,
+                        new Pair<>(tech, isProvisioned)));
+            }
+        };
+
+        final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            automan.adoptShellPermissionIdentity();
+            provisioningManager.registerProvisioningChangedCallback(getContext().getMainExecutor(),
+                    callback);
+            provisioningManager.registerFeatureProvisioningChangedCallback(
+                    getContext().getMainExecutor(), featureProvisioningCallback);
+
+            TelephonyUtils.enableCompatCommand(InstrumentationRegistry.getInstrumentation(),
+                    TelephonyUtils.CTS_APP_PACKAGE,
+                    SUPPORT_PROVISION_STATUS_FOR_CAPABILITY_STRING);
+
+            assertTrue(provisioningManager.isRcsProvisioningRequiredForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_LTE));
+            assertTrue(provisioningManager.isRcsProvisioningRequiredForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_IWLAN));
+            assertTrue(provisioningManager.isRcsProvisioningRequiredForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_CROSS_SIM));
+            assertTrue(provisioningManager.isRcsProvisioningRequiredForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_NR));
+
+            // test get/setRcsProvisioningStatusForCapability for PRESENCE over LTE
+            boolean isProvisioned = provisioningManager.getRcsProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_LTE);
+            provisioningManager.setRcsProvisioningStatusForCapability(RCS_CAP_PRESENCE,
+                    IMS_REGI_TECH_LTE, !isProvisioned);
+            assertTrue(waitForParam(mOnRcsFeatureChangedQueue,
+                    new Pair<>(RCS_CAP_PRESENCE, new Pair<>(IMS_REGI_TECH_LTE, !isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_EAB_PROVISIONING_STATUS, !isProvisioned ? 1 : 0)));
+
+            provisioningManager.setRcsProvisioningStatusForCapability(RCS_CAP_PRESENCE,
+                    IMS_REGI_TECH_LTE, isProvisioned);
+            assertTrue(waitForParam(mOnRcsFeatureChangedQueue,
+                    new Pair<>(RCS_CAP_PRESENCE, new Pair<>(IMS_REGI_TECH_LTE, isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_EAB_PROVISIONING_STATUS, isProvisioned ? 1 : 0)));
+
+            // test get/setRcsProvisioningStatusForCapability for PRESENCE over IWLAN
+            isProvisioned = provisioningManager.getRcsProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_IWLAN);
+            provisioningManager.setRcsProvisioningStatusForCapability(RCS_CAP_PRESENCE,
+                    IMS_REGI_TECH_IWLAN, !isProvisioned);
+            assertTrue(waitForParam(mOnRcsFeatureChangedQueue,
+                    new Pair<>(RCS_CAP_PRESENCE, new Pair<>(IMS_REGI_TECH_IWLAN, !isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_EAB_PROVISIONING_STATUS, !isProvisioned ? 1 : 0)));
+
+            provisioningManager.setRcsProvisioningStatusForCapability(RCS_CAP_PRESENCE,
+                    IMS_REGI_TECH_IWLAN, isProvisioned);
+            assertTrue(waitForParam(mOnRcsFeatureChangedQueue,
+                    new Pair<>(RCS_CAP_PRESENCE, new Pair<>(IMS_REGI_TECH_IWLAN, isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_EAB_PROVISIONING_STATUS, isProvisioned ? 1 : 0)));
+
+            // test get/setRcsProvisioningStatusForCapability for PRESENCE over CROSS SIM
+            isProvisioned = provisioningManager.getRcsProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_CROSS_SIM);
+            provisioningManager.setRcsProvisioningStatusForCapability(RCS_CAP_PRESENCE,
+                    IMS_REGI_TECH_CROSS_SIM, !isProvisioned);
+            assertTrue(waitForParam(mOnRcsFeatureChangedQueue,
+                    new Pair<>(RCS_CAP_PRESENCE,
+                            new Pair<>(IMS_REGI_TECH_CROSS_SIM, !isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_EAB_PROVISIONING_STATUS, !isProvisioned ? 1 : 0)));
+
+            provisioningManager.setRcsProvisioningStatusForCapability(RCS_CAP_PRESENCE,
+                    IMS_REGI_TECH_CROSS_SIM, isProvisioned);
+            assertTrue(waitForParam(mOnRcsFeatureChangedQueue,
+                    new Pair<>(RCS_CAP_PRESENCE,
+                            new Pair<>(IMS_REGI_TECH_CROSS_SIM, isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_EAB_PROVISIONING_STATUS, isProvisioned ? 1 : 0)));
+
+            // test get/setRcsProvisioningStatusForCapability for PRESENCE over NR
+            isProvisioned = provisioningManager.getRcsProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_NR);
+            provisioningManager.setRcsProvisioningStatusForCapability(RCS_CAP_PRESENCE,
+                    IMS_REGI_TECH_NR, !isProvisioned);
+            assertTrue(waitForParam(mOnRcsFeatureChangedQueue,
+                    new Pair<>(RCS_CAP_PRESENCE, new Pair<>(IMS_REGI_TECH_NR, !isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_EAB_PROVISIONING_STATUS, !isProvisioned ? 1 : 0)));
+
+            provisioningManager.setRcsProvisioningStatusForCapability(RCS_CAP_PRESENCE,
+                    IMS_REGI_TECH_NR, isProvisioned);
+            assertTrue(waitForParam(mOnRcsFeatureChangedQueue,
+                    new Pair<>(RCS_CAP_PRESENCE, new Pair<>(IMS_REGI_TECH_NR, isProvisioned))));
+            assertTrue(waitForParam(mIntQueue,
+                    new Pair<>(KEY_EAB_PROVISIONING_STATUS, isProvisioned ? 1 : 0)));
+
+            // TODO : work for OPTIONS case
+
+            automan.adoptShellPermissionIdentity();
+            provisioningManager.unregisterProvisioningChangedCallback(callback);
+            provisioningManager.unregisterFeatureProvisioningChangedCallback(
+                    featureProvisioningCallback);
+        } finally {
+            TelephonyUtils.resetCompatCommand(InstrumentationRegistry.getInstrumentation(),
+                    TelephonyUtils.CTS_APP_PACKAGE,
+                    SUPPORT_PROVISION_STATUS_FOR_CAPABILITY_STRING);
+
+            automan.dropShellPermissionIdentity();
+        }
+    }
+
+    @Test
+    public void testProvisioningManagerWhenRcsProvisionIsNotRequired() throws Exception {
+        if (!ImsUtils.shouldTestImsSingleRegistration()) {
+            return;
+        }
+
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putBoolean(CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL,
+                true);
+
+        PersistableBundle innerBundle = new PersistableBundle();
+        bundle.putPersistableBundle(
+                CarrierConfigManager.Ims.KEY_RCS_REQUIRES_PROVISIONING_BUNDLE,
+                innerBundle);
+
+        overrideCarrierConfig(bundle);
+
+        triggerFrameworkConnectToImsServiceBindMmTelAndRcsFeature();
+
+        ProvisioningManager provisioningManager =
+                ProvisioningManager.createForSubscriptionId(sTestSub);
+        ProvisioningManager.Callback callback = new ProvisioningManager.Callback() {};
+        ProvisioningManager.FeatureProvisioningCallback featureProvisioningCallback =
+                new ProvisioningManager.FeatureProvisioningCallback() {};
+
+        final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            automan.adoptShellPermissionIdentity();
+            provisioningManager.registerProvisioningChangedCallback(getContext().getMainExecutor(),
+                    callback);
+            provisioningManager.registerFeatureProvisioningChangedCallback(
+                    getContext().getMainExecutor(), featureProvisioningCallback);
+
+            TelephonyUtils.enableCompatCommand(InstrumentationRegistry.getInstrumentation(),
+                    TelephonyUtils.CTS_APP_PACKAGE,
+                    SUPPORT_PROVISION_STATUS_FOR_CAPABILITY_STRING);
+
+            assertTrue(!provisioningManager.isRcsProvisioningRequiredForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_LTE));
+            assertTrue(!provisioningManager.isRcsProvisioningRequiredForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_IWLAN));
+            assertTrue(!provisioningManager.isRcsProvisioningRequiredForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_CROSS_SIM));
+            assertTrue(!provisioningManager.isRcsProvisioningRequiredForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_NR));
+
+            // However, getProvisioningStatusForCapability() should return true because it does not
+            // require provision
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_LTE));
+            // put opposite value to check if the key is changed or not
+            provisioningManager.setProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_LTE, false);
+            // key value should not be changed whatever value is set
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_LTE));
+
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_IWLAN));
+            provisioningManager.setProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_IWLAN, false);
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_IWLAN));
+
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_CROSS_SIM));
+            provisioningManager.setProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_CROSS_SIM, false);
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_CROSS_SIM));
+
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_NR));
+            provisioningManager.setProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_NR, false);
+            assertTrue(provisioningManager.getProvisioningStatusForCapability(
+                    RCS_CAP_PRESENCE, IMS_REGI_TECH_NR));
+
+            // TODO : work for OPTIONS case
+
+            automan.adoptShellPermissionIdentity();
+            provisioningManager.unregisterProvisioningChangedCallback(callback);
+            provisioningManager.unregisterFeatureProvisioningChangedCallback(
+                    featureProvisioningCallback);
+        } finally {
+            TelephonyUtils.resetCompatCommand(InstrumentationRegistry.getInstrumentation(),
+                    TelephonyUtils.CTS_APP_PACKAGE,
+                    SUPPORT_PROVISION_STATUS_FOR_CAPABILITY_STRING);
+
+            automan.dropShellPermissionIdentity();
+        }
+    }
+
     @Ignore("The ProvisioningManager constants were moved back to @hide for now, don't want to "
             + "completely remove test.")
     @Test
@@ -3342,7 +3964,15 @@
 
         PersistableBundle bundle = new PersistableBundle();
         bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL, true);
-        bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL, true);
+
+        PersistableBundle innerBundle = new PersistableBundle();
+        innerBundle.putIntArray(
+                CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_UT_INT_ARRAY,
+                new int[]{IMS_REGI_TECH_LTE}); // UT/LTE
+        bundle.putPersistableBundle(
+                CarrierConfigManager.Ims.KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE,
+                innerBundle);
+
         overrideCarrierConfig(bundle);
 
         ProvisioningManager provisioningManager =
@@ -3353,22 +3983,22 @@
             automan.adoptShellPermissionIdentity();
             boolean provisioningStatus = provisioningManager.getProvisioningStatusForCapability(
                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
-                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+                    IMS_REGI_TECH_LTE);
             provisioningManager.setProvisioningStatusForCapability(
                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
-                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE, !provisioningStatus);
+                    IMS_REGI_TECH_LTE, !provisioningStatus);
             // Make sure the change in provisioning status is correctly returned.
             assertEquals(!provisioningStatus,
                     provisioningManager.getProvisioningStatusForCapability(
                             MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
-                            ImsRegistrationImplBase.REGISTRATION_TECH_LTE));
+                            IMS_REGI_TECH_LTE));
             // TODO: Enhance test to make sure the provisioning change is also sent to the
             // ImsService
 
             // set back to current status
             provisioningManager.setProvisioningStatusForCapability(
                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
-                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE, provisioningStatus);
+                    IMS_REGI_TECH_LTE, provisioningStatus);
         } finally {
             automan.dropShellPermissionIdentity();
         }
@@ -3378,7 +4008,7 @@
 
     @Test
     public void testProvisioningManagerRcsProvisioningCaps() throws Exception {
-        if (!ImsUtils.shouldTestImsService()) {
+        if (!ImsUtils.shouldTestImsSingleRegistration()) {
             return;
         }
 
@@ -3390,8 +4020,20 @@
                 true);
         bundle.putBoolean(CarrierConfigManager.Ims.KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, true);
         bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL, true);
+        bundle.putBoolean(CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL,
+                true);
+        PersistableBundle innerBundle = new PersistableBundle();
+        innerBundle.putIntArray(
+                CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY,
+                new int[]{IMS_REGI_TECH_LTE, IMS_REGI_TECH_IWLAN, IMS_REGI_TECH_CROSS_SIM,
+                        IMS_REGI_TECH_NR}
+        );
+        bundle.putPersistableBundle(
+                CarrierConfigManager.Ims.KEY_RCS_REQUIRES_PROVISIONING_BUNDLE,
+                innerBundle);
         overrideCarrierConfig(bundle);
 
+
         ProvisioningManager provisioningManager =
                 ProvisioningManager.createForSubscriptionId(sTestSub);
 
@@ -3406,7 +4048,7 @@
             assertEquals(!provisioningStatus,
                     provisioningManager.getRcsProvisioningStatusForCapability(RCS_CAP_PRESENCE));
             // TODO: Enhance test to make sure the provisioning change is also sent to the
-            // ImsService
+            //  ImsService
 
             // set back to current status
             provisioningManager.setRcsProvisioningStatusForCapability(RCS_CAP_PRESENCE,
@@ -4393,4 +5035,8 @@
 
         throw new RuntimeException("Invalid hex char '" + c + "'");
     }
+
+    private boolean isExpectedSubId(HashSet<Integer> subIDs) {
+        return (subIDs.size() == 1) && subIDs.contains(sTestSub);
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsContactUceCapabilityTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsContactUceCapabilityTest.java
index cf1b2fe..34abd36 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsContactUceCapabilityTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsContactUceCapabilityTest.java
@@ -73,6 +73,7 @@
                 RcsContactUceCapability.REQUEST_RESULT_FOUND);
         presenceBuilder.addCapabilityTuple(mmtelTuple);
         presenceBuilder.addCapabilityTuples(Collections.singletonList(ftTuple));
+        presenceBuilder.setEntityUri(TEST_CONTACT);
 
         final RcsContactUceCapability testCapability = presenceBuilder.build();
 
@@ -87,6 +88,7 @@
         assertEquals(unparceledCapability.getContactUri(), testCapability.getContactUri());
         assertEquals(unparceledCapability.getSourceType(), testCapability.getSourceType());
         assertEquals(unparceledCapability.getRequestResult(), testCapability.getRequestResult());
+        assertEquals(unparceledCapability.getEntityUri(), testCapability.getEntityUri());
         assertEquals(unparceledCapability.getCapabilityMechanism(),
                 testCapability.getCapabilityMechanism());
 
@@ -224,6 +226,7 @@
         assertEquals(expectedCap.getContactUri(), unparceledCapability.getContactUri());
         assertEquals(expectedCap.getSourceType(), unparceledCapability.getSourceType());
         assertEquals(expectedCap.getRequestResult(), unparceledCapability.getRequestResult());
+        assertEquals(expectedCap.getEntityUri(), unparceledCapability.getEntityUri());
         assertEquals(expectedCap.getCapabilityMechanism(),
                 unparceledCapability.getCapabilityMechanism());
 
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
index 91a4bd9..6491b67 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
@@ -1069,6 +1069,149 @@
         overrideCarrierConfig(null);
     }
 
+    /**
+     * Tests the case when contact1 has had a successful network query, but a query for contact2
+     * has resulted in the carrier network not responding with a NOTIFY. If contact1 caps are
+     * queried again, the query to the cache for contact1 should not be blocked in a queue behind
+     * the pending network query. Eventually, request for contact2 will timeout with onTimeout
+     * response from vendor, which will result in ERROR_REQUEST_TIMEOUT result back to app.
+     */
+    @Test
+    public void testCacheQuerySuccessWhenNetworkBlocked() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+        assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+        // Remove the test contact capabilities
+        removeTestContactFromEab();
+
+        // Connect to the ImsService
+        setupTestImsService(uceAdapter, true, true /* presence cap */, false /* OPTIONS */);
+
+        TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+                .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+        BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+        RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+            @Override
+            public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+                capabilities.forEach(capabilityQueue::offer);
+            }
+            @Override
+            public void onComplete() {
+                completeQueue.offer(true);
+            }
+            @Override
+            public void onError(int errorCode, long retryAfterMilliseconds) {
+                errorQueue.offer(errorCode);
+            }
+        };
+
+        // Prepare two contacts
+        final Uri contact1 = sTestNumberUri;
+        final Uri contact2 = sTestContact2Uri;
+
+        Collection<Uri> contacts = new ArrayList<>(1);
+        contacts.add(contact1);
+
+        ArrayList<String> pidfXmlList = new ArrayList<>(1);
+        pidfXmlList.add(getPidfXmlData(contact1, true, true));
+
+        // Setup the network response is 200 OK and notify capabilities update
+        int networkRespCode = 200;
+        String networkRespReason = "OK";
+        capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+            cb.onNetworkResponse(networkRespCode, networkRespReason);
+            cb.onNotifyCapabilitiesUpdate(pidfXmlList);
+            cb.onTerminated("", 0L);
+        });
+
+        requestCapabilities(uceAdapter, contacts, callback);
+
+        List<RcsContactUceCapability> resultCapList = new ArrayList<>();
+
+        // Verify that the first contact is updated
+        RcsContactUceCapability capability = waitForResult(capabilityQueue);
+        assertNotNull("Cannot receive the first capabilities result.", capability);
+        resultCapList.add(capability);
+
+        // Verify contact1's capabilities from the received capabilities list
+        RcsContactUceCapability resultCapability = getContactCapability(resultCapList, contact1);
+        assertNotNull("Cannot find the contact: " + contact1, resultCapability);
+        verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, true, true);
+
+        // Verify the onCompleted is called
+        waitForResult(completeQueue);
+
+        completeQueue.clear();
+        capabilityQueue.clear();
+        resultCapList.clear();
+
+        // Now hold the second contact and do not return a response until after contact1 is queried
+        //again
+        CountDownLatch latch = new CountDownLatch(1);
+        capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+            try {
+                cb.onNetworkResponse(networkRespCode, networkRespReason);
+                assertTrue("Timed out waiting for latch", latch.await(10, TimeUnit.SECONDS));
+                // We didn't receive any NOTIFY
+                cb.onTerminated("timeout", 0L);
+            } catch (InterruptedException e) {
+                fail("Waiting for cap response resulted in unexpected exception: " + e);
+            }
+        });
+
+        contacts.clear();
+        contacts.add(contact2);
+
+        pidfXmlList.clear();
+        pidfXmlList.add(getPidfXmlData(contact2, true, true));
+
+        requestCapabilities(uceAdapter, contacts, callback);
+
+        // Send another request for contact1's caps. Although the request queue is blocked due to
+        // pending network request, contact1 has valid caps, so system should return those.
+        contacts.clear();
+        contacts.add(contact1);
+
+        pidfXmlList.clear();
+        pidfXmlList.add(getPidfXmlData(contact1, true, true));
+
+        requestCapabilities(uceAdapter, contacts, callback);
+
+        capability = waitForResult(capabilityQueue);
+        assertNotNull("Cannot receive the cached capabilities result.", capability);
+        resultCapList.add(capability);
+
+        // Verify contact1's capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact1);
+        assertNotNull("Cannot find the contact: " + contact1, resultCapability);
+        verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
+                true, true);
+
+        // Now contact2's query finishes and it timed out without a NOTIFY
+        latch.countDown();
+
+        Integer error = waitForResult(errorQueue);
+        assertNotNull("Cannot receive the expected error result.", capability);
+        assertEquals("Timeout without NOTIFY should result in ERROR_REQUEST_TIMEOUT",
+                RcsUceAdapter.ERROR_REQUEST_TIMEOUT, error.intValue());
+
+        errorQueue.clear();
+        completeQueue.clear();
+        capabilityQueue.clear();
+        resultCapList.clear();
+        removeTestContactFromEab();
+
+        overrideCarrierConfig(null);
+    }
+
     @Test
     public void testRequestCapabilitiesFromCacheWithPresenceMechanism() throws Exception {
         if (!ImsUtils.shouldTestImsService()) {
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsCallSessionImpl.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsCallSessionImpl.java
index 3ded179..1dba231 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsCallSessionImpl.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsCallSessionImpl.java
@@ -63,6 +63,8 @@
     public static final int TEST_TYPE_NONE = 0x00000000;
     public static final int TEST_TYPE_MO_ANSWER = 0x00000001;
     public static final int TEST_TYPE_MO_FAILED = 0x00000002;
+    public static final int TEST_TYPE_HOLD_FAILED = 0x00000004;
+    public static final int TEST_TYPE_RESUME_FAILED = 0x00000008;
 
     private int mTestType = TEST_TYPE_NONE;
 
@@ -324,6 +326,132 @@
         }
     }
 
+    @Override
+    public void hold(ImsStreamMediaProfile profile) {
+        if (isTestType(TEST_TYPE_HOLD_FAILED)) {
+            holdFailed(profile);
+        } else {
+            int audioDirection = profile.getAudioDirection();
+            if (audioDirection == ImsStreamMediaProfile.DIRECTION_SEND) {
+                ImsStreamMediaProfile mediaProfile = new ImsStreamMediaProfile(
+                        ImsStreamMediaProfile.AUDIO_QUALITY_AMR,
+                        ImsStreamMediaProfile.DIRECTION_RECEIVE,
+                        ImsStreamMediaProfile.VIDEO_QUALITY_NONE,
+                        ImsStreamMediaProfile.DIRECTION_INVALID,
+                        ImsStreamMediaProfile.RTT_MODE_DISABLED);
+                ImsCallProfile mprofile = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                        ImsCallProfile.CALL_TYPE_VOICE, new Bundle(), mediaProfile);
+                mCallProfile.updateMediaProfile(mprofile);
+            }
+            setState(ImsCallSessionImplBase.State.RENEGOTIATING);
+
+            postAndRunTask(() -> {
+                imsCallSessionLatchCountdown(LATCH_WAIT, WAIT_FOR_ESTABLISHING);
+                try {
+                    if (mListener == null) {
+                        return;
+                    }
+                    Log.d(LOG_TAG, "invokeHeld mCallId = " + mCallId);
+                    mListener.callSessionHeld(mCallProfile);
+                } catch (Throwable t) {
+                    Throwable cause = t.getCause();
+                    if (t instanceof DeadObjectException
+                            || (cause != null && cause instanceof DeadObjectException)) {
+                        fail("starting cause Throwable to be thrown: " + t);
+                    }
+                }
+            });
+            setState(ImsCallSessionImplBase.State.ESTABLISHED);
+        }
+    }
+
+    @Override
+    public void resume(ImsStreamMediaProfile profile) {
+        if (isTestType(TEST_TYPE_RESUME_FAILED)) {
+            resumeFailed(profile);
+        } else {
+            int audioDirection = profile.getAudioDirection();
+            if (audioDirection == ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE) {
+                ImsStreamMediaProfile mediaProfile = new ImsStreamMediaProfile(
+                        ImsStreamMediaProfile.AUDIO_QUALITY_AMR,
+                        ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE,
+                        ImsStreamMediaProfile.VIDEO_QUALITY_NONE,
+                        ImsStreamMediaProfile.DIRECTION_INVALID,
+                        ImsStreamMediaProfile.RTT_MODE_DISABLED);
+                ImsCallProfile mprofile = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+                        ImsCallProfile.CALL_TYPE_VOICE, new Bundle(), mediaProfile);
+                mCallProfile.updateMediaProfile(mprofile);
+            }
+            setState(ImsCallSessionImplBase.State.RENEGOTIATING);
+
+            postAndRunTask(() -> {
+                imsCallSessionLatchCountdown(LATCH_WAIT, WAIT_FOR_ESTABLISHING);
+                try {
+                    if (mListener == null) {
+                        return;
+                    }
+                    Log.d(LOG_TAG, "invokeResume mCallId = " + mCallId);
+                    mListener.callSessionResumed(mCallProfile);
+                } catch (Throwable t) {
+                    Throwable cause = t.getCause();
+                    if (t instanceof DeadObjectException
+                            || (cause != null && cause instanceof DeadObjectException)) {
+                        fail("starting cause Throwable to be thrown: " + t);
+                    }
+                }
+            });
+            setState(ImsCallSessionImplBase.State.ESTABLISHED);
+        }
+    }
+
+    private void holdFailed(ImsStreamMediaProfile profile) {
+        int audioDirection = profile.getAudioDirection();
+        if (audioDirection == ImsStreamMediaProfile.DIRECTION_SEND) {
+            postAndRunTask(() -> {
+                imsCallSessionLatchCountdown(LATCH_WAIT, WAIT_FOR_ESTABLISHING);
+                try {
+                    if (mListener == null) {
+                        return;
+                    }
+                    Log.d(LOG_TAG, "invokeHoldFailed mCallId = " + mCallId);
+                    mListener.callSessionHoldFailed(getReasonInfo(ImsReasonInfo
+                            .CODE_SESSION_MODIFICATION_FAILED, ImsReasonInfo.CODE_UNSPECIFIED));
+                } catch (Throwable t) {
+                    Throwable cause = t.getCause();
+                    if (t instanceof DeadObjectException
+                            || (cause != null && cause instanceof DeadObjectException)) {
+                        fail("starting cause Throwable to be thrown: " + t);
+                    }
+                }
+            });
+            setState(ImsCallSessionImplBase.State.ESTABLISHED);
+        }
+    }
+
+    private void resumeFailed(ImsStreamMediaProfile profile) {
+        int audioDirection = profile.getAudioDirection();
+        if (audioDirection == ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE) {
+            postAndRunTask(() -> {
+                imsCallSessionLatchCountdown(LATCH_WAIT, WAIT_FOR_ESTABLISHING);
+                try {
+                    if (mListener == null) {
+                        return;
+                    }
+                    Log.d(LOG_TAG, "invokeResumeFailed mCallId = " + mCallId);
+                    mListener.callSessionResumeFailed(getReasonInfo(ImsReasonInfo
+                            .CODE_SESSION_MODIFICATION_FAILED, ImsReasonInfo.CODE_UNSPECIFIED));
+                } catch (Throwable t) {
+                    Throwable cause = t.getCause();
+                    if (t instanceof DeadObjectException
+                            || (cause != null && cause instanceof DeadObjectException)) {
+                        fail("starting cause Throwable to be thrown: " + t);
+                    }
+                }
+            });
+            setState(ImsCallSessionImplBase.State.ESTABLISHED);
+        }
+    }
+
     private void setState(int state) {
         if (mState != state) {
             Log.d(LOG_TAG, "ImsCallSession :: " + mState + " >> " + state);
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java
index 10a39d3..3e3b331 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java
@@ -18,15 +18,25 @@
 
 import android.telephony.ims.RcsClientConfiguration;
 import android.telephony.ims.stub.ImsConfigImplBase;
+import android.util.Log;
 
 import java.util.HashMap;
+import java.util.concurrent.Executor;
 
 public class TestImsConfig extends ImsConfigImplBase {
 
+    private static final String TAG = "TestImsConfig";
     private HashMap<Integer, Integer> mIntHashMap = new HashMap<>();
     private HashMap<Integer, String> mStringHashMap = new HashMap<>();
 
     TestImsConfig() {
+        Log.d(TAG, "TestImsConfig with default constructor");
+        TestAcsClient.getInstance().setImsConfigImpl(this);
+    }
+
+    TestImsConfig(Executor executor) {
+        super(executor);
+        Log.d(TAG, "TestImsConfig with Executor constructor");
         TestAcsClient.getInstance().setImsConfigImpl(this);
     }
 
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsRegistration.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsRegistration.java
index afdd3d1..cb3a4d9 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsRegistration.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsRegistration.java
@@ -17,13 +17,26 @@
 package android.telephony.ims.cts;
 
 import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
 public class TestImsRegistration extends ImsRegistrationImplBase {
 
+    private static final String TAG = "TestImsRegistration";
+
+    public TestImsRegistration() {
+        Log.d(TAG, "TestImsRegistration with default constructor");
+    }
+
+    public TestImsRegistration(Executor executor) {
+        super(executor);
+        Log.d(TAG, "TestImsRegistration with Executor constructor");
+    }
+
     public static class NetworkRegistrationInfo {
         public final int sipCode;
         public final String sipReason;
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
index a012513..97fa8f2 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
@@ -20,7 +20,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
 import android.telephony.ims.ImsService;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.feature.RcsFeature;
@@ -30,10 +34,12 @@
 import android.telephony.ims.stub.SipTransportImplBase;
 import android.util.Log;
 
-
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import java.util.HashSet;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -41,22 +47,27 @@
  */
 public class TestImsService extends Service {
 
-    private static final String TAG = "GtsImsTestImsService";
+    private static final String TAG = "CtsImsTestImsService";
+    private static MessageExecutor sMessageExecutor = null;
 
-    private static final TestImsRegistration sImsRegistrationImplBase =
-            new TestImsRegistration();
-
+    private TestImsRegistration mImsRegistrationImplBase;
     private TestRcsFeature mTestRcsFeature;
     private TestMmTelFeature mTestMmTelFeature;
     private TestImsConfig mTestImsConfig;
     private TestSipTransport mTestSipTransport;
     private ImsService mTestImsService;
+    private ImsService mTestImsServiceCompat;
+    private Executor mExecutor = Runnable::run;
     private boolean mIsEnabled = false;
     private boolean mSetNullRcsBinding = false;
     private boolean mIsSipTransportImplemented = false;
+    private boolean mIsTestTypeExecutor = false;
+    private boolean mIsImsServiceCompat = false;
     private long mCapabilities = 0;
     private ImsFeatureConfiguration mFeatureConfig;
-    private final Object mLock = new Object();
+    protected boolean mIsTelephonyBound = false;
+    private HashSet<Integer> mSubIDs = new HashSet<Integer>();
+    protected final Object mLock = new Object();
 
     public static final int LATCH_FEATURES_READY = 0;
     public static final int LATCH_ENABLE_IMS = 1;
@@ -71,7 +82,8 @@
     public static final int LATCH_RCS_CAP_SET = 10;
     public static final int LATCH_UCE_LISTENER_SET = 11;
     public static final int LATCH_UCE_REQUEST_PUBLISH = 12;
-    private static final int LATCH_MAX = 13;
+    public static final int LATCH_ON_UNBIND = 13;
+    private static final int LATCH_MAX = 14;
     protected static final CountDownLatch[] sLatches = new CountDownLatch[LATCH_MAX];
     static {
         for (int i = 0; i < LATCH_MAX; i++) {
@@ -106,9 +118,193 @@
             if (getBaseContext() == null) {
                 attachBaseContext(context);
             }
-            mTestImsConfig = new TestImsConfig();
-            // For testing, just run on binder thread until required otherwise.
-            mTestSipTransport = new TestSipTransport(Runnable::run);
+
+            if (mIsTestTypeExecutor) {
+                mImsRegistrationImplBase = new TestImsRegistration(mExecutor);
+                mTestSipTransport = new TestSipTransport(mExecutor);
+                mTestImsConfig = new TestImsConfig(mExecutor);
+            } else {
+                mImsRegistrationImplBase = new TestImsRegistration();
+                mTestImsConfig = new TestImsConfig();
+                mTestSipTransport = new TestSipTransport();
+            }
+        }
+
+        @Override
+        public ImsFeatureConfiguration querySupportedImsFeatures() {
+            return getFeatureConfig();
+        }
+
+        @Override
+        public long getImsServiceCapabilities() {
+            return mCapabilities;
+        }
+
+        @Override
+        public void readyForFeatureCreation() {
+            synchronized (mLock) {
+                countDownLatch(LATCH_FEATURES_READY);
+            }
+        }
+
+        @Override
+        public void enableImsForSubscription(int slotId, int subId) {
+            synchronized (mLock) {
+                countDownLatch(LATCH_ENABLE_IMS);
+                mSubIDs.add(subId);
+                setIsEnabled(true);
+            }
+        }
+
+        @Override
+        public void disableImsForSubscription(int slotId, int subId) {
+            synchronized (mLock) {
+                countDownLatch(LATCH_DISABLE_IMS);
+                mSubIDs.add(subId);
+                setIsEnabled(false);
+            }
+        }
+
+        @Override
+        public RcsFeature createRcsFeatureForSubscription(int slotId, int subId) {
+            TestImsService.ReadyListener readyListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_RCS_READY);
+                }
+            };
+
+            TestImsService.RemovedListener removedListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_REMOVE_RCS);
+                    mTestRcsFeature = null;
+                }
+            };
+
+            TestImsService.CapabilitiesSetListener setListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_RCS_CAP_SET);
+                }
+            };
+
+            TestImsService.RcsCapabilityExchangeEventListener capExchangeEventListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_UCE_LISTENER_SET);
+                }
+            };
+
+            synchronized (mLock) {
+                countDownLatch(LATCH_CREATE_RCS);
+                mSubIDs.add(subId);
+
+                if (mIsTestTypeExecutor) {
+                    mTestRcsFeature = new TestRcsFeature(readyListener, removedListener,
+                            setListener, capExchangeEventListener, mExecutor);
+                } else {
+                    mTestRcsFeature = new TestRcsFeature(readyListener, removedListener,
+                            setListener, capExchangeEventListener);
+                }
+
+                // Setup UCE request listener
+                mTestRcsFeature.setDeviceCapPublishListener(() -> {
+                    synchronized (mLock) {
+                        countDownLatch(LATCH_UCE_REQUEST_PUBLISH);
+                    }
+                });
+
+                if (mSetNullRcsBinding) {
+                    return null;
+                }
+                return mTestRcsFeature;
+            }
+        }
+
+        @Override
+        public ImsConfigImplBase getConfigForSubscription(int slotId, int subId) {
+            mSubIDs.add(subId);
+            return mTestImsConfig;
+        }
+
+        @Override
+        public MmTelFeature createMmTelFeatureForSubscription(int slotId, int subId) {
+            TestImsService.ReadyListener readyListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_MMTEL_READY);
+                }
+            };
+
+            TestImsService.RemovedListener removedListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_REMOVE_MMTEL);
+                    mTestMmTelFeature = null;
+                }
+            };
+
+            TestImsService.CapabilitiesSetListener capSetListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_MMTEL_CAP_SET);
+                }
+            };
+
+            synchronized (mLock) {
+                countDownLatch(LATCH_CREATE_MMTEL);
+                mSubIDs.add(subId);
+                if (mIsTestTypeExecutor) {
+                    mTestMmTelFeature = new TestMmTelFeature(readyListener, removedListener,
+                            capSetListener, mExecutor);
+                } else {
+                    mTestMmTelFeature = new TestMmTelFeature(readyListener, removedListener,
+                            capSetListener);
+                }
+
+                return mTestMmTelFeature;
+            }
+        }
+
+        @Override
+        public ImsRegistrationImplBase getRegistrationForSubscription(int slotId, int subId) {
+            mSubIDs.add(subId);
+            return mImsRegistrationImplBase;
+        }
+
+        @Nullable
+        @Override
+        public SipTransportImplBase getSipTransport(int slotId) {
+            if (mIsSipTransportImplemented) {
+                return mTestSipTransport;
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public @NonNull Executor getExecutor() {
+            if (mIsTestTypeExecutor) {
+                return mExecutor;
+            } else {
+                mExecutor = Runnable::run;
+                return mExecutor;
+            }
+        }
+    }
+
+    private class ImsServiceUT_compat extends ImsService {
+
+        ImsServiceUT_compat(Context context) {
+            // As explained above, ImsServiceUT is created in order to get around classloader
+            // restrictions. Attach the base context from the wrapper ImsService.
+            if (getBaseContext() == null) {
+                attachBaseContext(context);
+            }
+
+            if (mIsTestTypeExecutor) {
+                mImsRegistrationImplBase = new TestImsRegistration(mExecutor);
+                mTestSipTransport = new TestSipTransport(mExecutor);
+                mTestImsConfig = new TestImsConfig(mExecutor);
+            } else {
+                mImsRegistrationImplBase = new TestImsRegistration();
+                mTestImsConfig = new TestImsConfig();
+                mTestSipTransport = new TestSipTransport();
+            }
         }
 
         @Override
@@ -146,33 +342,42 @@
 
         @Override
         public RcsFeature createRcsFeature(int slotId) {
+
+            TestImsService.ReadyListener readyListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_RCS_READY);
+                }
+            };
+
+            TestImsService.RemovedListener removedListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_REMOVE_RCS);
+                    mTestRcsFeature = null;
+                }
+            };
+
+            TestImsService.CapabilitiesSetListener setListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_RCS_CAP_SET);
+                }
+            };
+
+            TestImsService.RcsCapabilityExchangeEventListener capExchangeEventListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_UCE_LISTENER_SET);
+                }
+            };
+
             synchronized (mLock) {
                 countDownLatch(LATCH_CREATE_RCS);
-                mTestRcsFeature = new TestRcsFeature(getBaseContext(),
-                        //onReady
-                        () -> {
-                            synchronized (mLock) {
-                                countDownLatch(LATCH_RCS_READY);
-                            }
-                        },
-                        //onRemoved
-                        () -> {
-                            synchronized (mLock) {
-                                countDownLatch(LATCH_REMOVE_RCS);
-                                mTestRcsFeature = null;
-                            }
-                        },
-                        //onCapabilitiesSet
-                        () -> {
-                            synchronized (mLock) {
-                                countDownLatch(LATCH_RCS_CAP_SET);
-                            }
-                        },
-                        () -> {
-                            synchronized (mLock) {
-                                countDownLatch(LATCH_UCE_LISTENER_SET);
-                        }
-                        });
+
+                if (mIsTestTypeExecutor) {
+                    mTestRcsFeature = new TestRcsFeature(readyListener, removedListener,
+                            setListener, capExchangeEventListener, mExecutor);
+                } else {
+                    mTestRcsFeature = new TestRcsFeature(readyListener, removedListener,
+                            setListener, capExchangeEventListener);
+                }
 
                 // Setup UCE request listener
                 mTestRcsFeature.setDeviceCapPublishListener(() -> {
@@ -195,36 +400,42 @@
 
         @Override
         public MmTelFeature createMmTelFeature(int slotId) {
+            TestImsService.ReadyListener readyListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_MMTEL_READY);
+                }
+            };
+
+            TestImsService.RemovedListener removedListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_REMOVE_MMTEL);
+                    mTestMmTelFeature = null;
+                }
+            };
+
+            TestImsService.CapabilitiesSetListener capSetListener = () -> {
+                synchronized (mLock) {
+                    countDownLatch(LATCH_MMTEL_CAP_SET);
+                }
+            };
+
             synchronized (mLock) {
                 countDownLatch(LATCH_CREATE_MMTEL);
-                mTestMmTelFeature = new TestMmTelFeature(
-                        //onReady
-                        () -> {
-                            synchronized (mLock) {
-                                countDownLatch(LATCH_MMTEL_READY);
-                            }
-                        },
-                        //onRemoved
-                        () -> {
-                            synchronized (mLock) {
-                                countDownLatch(LATCH_REMOVE_MMTEL);
-                                mTestMmTelFeature = null;
-                            }
-                        },
-                        //onCapabilitiesSet
-                        () -> {
-                            synchronized (mLock) {
-                                countDownLatch(LATCH_MMTEL_CAP_SET);
-                            }
-                        }
-                        );
+                if (mIsTestTypeExecutor) {
+                    mTestMmTelFeature = new TestMmTelFeature(readyListener, removedListener,
+                            capSetListener, mExecutor);
+                } else {
+                    mTestMmTelFeature = new TestMmTelFeature(readyListener, removedListener,
+                            capSetListener);
+                }
+
                 return mTestMmTelFeature;
             }
         }
 
         @Override
         public ImsRegistrationImplBase getRegistration(int slotId) {
-            return sImsRegistrationImplBase;
+            return mImsRegistrationImplBase;
         }
 
         @Nullable
@@ -236,6 +447,62 @@
                 return null;
             }
         }
+
+        @Override
+        public @NonNull Executor getExecutor() {
+            if (mIsTestTypeExecutor) {
+                return mExecutor;
+            } else {
+                mExecutor = Runnable::run;
+                return mExecutor;
+            }
+        }
+    }
+
+    private static Looper createLooper(String name) {
+        HandlerThread thread = new HandlerThread(name);
+        thread.start();
+
+        Looper looper = thread.getLooper();
+
+        if (looper == null) {
+            return Looper.getMainLooper();
+        }
+        return looper;
+    }
+
+    /**
+     * Executes the tasks in the other thread rather than the calling thread.
+     */
+    public class MessageExecutor extends Handler implements Executor {
+        public MessageExecutor(String name) {
+            super(createLooper(name));
+        }
+
+        @Override
+        public void execute(Runnable r) {
+            Message m = Message.obtain(this, 0, r);
+            m.sendToTarget();
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.obj instanceof Runnable) {
+                executeInternal((Runnable) msg.obj);
+            } else {
+                Log.d(TAG, "[MessageExecutor] handleMessage :: "
+                        + "Not runnable object; ignore the msg=" + msg);
+            }
+        }
+
+        private void executeInternal(Runnable r) {
+            try {
+                r.run();
+            } catch (Throwable t) {
+                Log.d(TAG, "[MessageExecutor] executeInternal :: run task=" + r);
+                t.printStackTrace();
+            }
+        }
     }
 
     private final LocalBinder mBinder = new LocalBinder();
@@ -256,18 +523,53 @@
         }
     }
 
+    protected ImsService getImsServiceCompat() {
+        synchronized (mLock) {
+            if (mTestImsServiceCompat != null) {
+                return mTestImsServiceCompat;
+            }
+            mTestImsServiceCompat = new ImsServiceUT_compat(this);
+            return mTestImsServiceCompat;
+        }
+    }
+
     @Override
     public IBinder onBind(Intent intent) {
-        if ("android.telephony.ims.ImsService".equals(intent.getAction())) {
-            if (ImsUtils.VDBG) {
-                Log.d(TAG, "onBind-Remote");
+        synchronized (mLock) {
+            if ("android.telephony.ims.ImsService".equals(intent.getAction())) {
+                mIsTelephonyBound = true;
+                if (mIsImsServiceCompat) {
+                    if (ImsUtils.VDBG) {
+                        Log.d(TAG, "onBind-Remote-Compat");
+                    }
+                    return getImsServiceCompat().onBind(intent);
+                } else {
+                    if (ImsUtils.VDBG) {
+                        Log.d(TAG, "onBind-Remote");
+                    }
+                    return getImsService().onBind(intent);
+                }
             }
-            return getImsService().onBind(intent);
+            if (ImsUtils.VDBG) {
+                Log.i(TAG, "onBind-Local");
+            }
+            return mBinder;
         }
-        if (ImsUtils.VDBG) {
-            Log.i(TAG, "onBind-Local");
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        synchronized (mLock) {
+            if ("android.telephony.ims.ImsService".equals(intent.getAction())) {
+                if (ImsUtils.VDBG)  Log.i(TAG, "onUnbind-Remote");
+                mIsTelephonyBound = false;
+                countDownLatch(LATCH_ON_UNBIND);
+            } else {
+                if (ImsUtils.VDBG)  Log.i(TAG, "onUnbind-Local");
+            }
+            // return false so that onBind is called next time.
+            return false;
         }
-        return mBinder;
     }
 
     public void resetState() {
@@ -277,10 +579,38 @@
             mIsEnabled = false;
             mSetNullRcsBinding = false;
             mIsSipTransportImplemented = false;
+            mIsTestTypeExecutor = false;
+            mIsImsServiceCompat = false;
             mCapabilities = 0;
             for (int i = 0; i < LATCH_MAX; i++) {
                 sLatches[i] = new CountDownLatch(1);
             }
+
+            if (sMessageExecutor != null) {
+                sMessageExecutor.getLooper().quit();
+                sMessageExecutor = null;
+            }
+            mSubIDs.clear();
+        }
+    }
+
+    public boolean isTelephonyBound() {
+        return mIsTelephonyBound;
+    }
+
+    public void setExecutorTestType(boolean type) {
+        mIsTestTypeExecutor = type;
+        if (mIsTestTypeExecutor) {
+            if (sMessageExecutor == null) {
+                sMessageExecutor = new MessageExecutor("TestImsService");
+            }
+            mExecutor = sMessageExecutor;
+        }
+    }
+
+    public void setImsServiceCompat() {
+        synchronized (mLock) {
+            mIsImsServiceCompat = true;
         }
     }
 
@@ -329,20 +659,7 @@
     }
 
     public boolean waitForLatchCountdown(int latchIndex) {
-        boolean complete = false;
-        try {
-            CountDownLatch latch;
-            synchronized (mLock) {
-                latch = sLatches[latchIndex];
-            }
-            complete = latch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        } catch (InterruptedException e) {
-            // complete == false
-        }
-        synchronized (mLock) {
-            sLatches[latchIndex] = new CountDownLatch(1);
-        }
-        return complete;
+        return waitForLatchCountdown(latchIndex, ImsUtils.TEST_TIMEOUT_MS);
     }
 
     public boolean waitForLatchCountdown(int latchIndex, long waitMs) {
@@ -352,7 +669,12 @@
             synchronized (mLock) {
                 latch = sLatches[latchIndex];
             }
+            long startTime = System.currentTimeMillis();
             complete = latch.await(waitMs, TimeUnit.MILLISECONDS);
+            if (ImsUtils.VDBG) {
+                Log.i(TAG, "Latch " + latchIndex + " took "
+                        + (System.currentTimeMillis() - startTime) + " ms to count down.");
+            }
         } catch (InterruptedException e) {
             // complete == false
         }
@@ -388,11 +710,15 @@
 
     public TestImsRegistration getImsRegistration() {
         synchronized (mLock) {
-            return sImsRegistrationImplBase;
+            return mImsRegistrationImplBase;
         }
     }
 
     public ImsConfigImplBase getConfig() {
         return mTestImsConfig;
     }
+
+    public HashSet<Integer> getSubIDs() {
+        return mSubIDs;
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java
index d38a63a..d300b71 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java
@@ -16,7 +16,6 @@
 
 package android.telephony.ims.cts;
 
-import android.app.UiAutomation;
 import android.os.Bundle;
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsStreamMediaProfile;
@@ -27,8 +26,6 @@
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.util.Log;
 
-import androidx.test.platform.app.InstrumentationRegistry;
-
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
@@ -52,6 +49,21 @@
     TestMmTelFeature(TestImsService.ReadyListener readyListener,
             TestImsService.RemovedListener removedListener,
             TestImsService.CapabilitiesSetListener setListener) {
+        Log.d(TAG, "TestMmTelFeature with default constructor");
+        mReadyListener = readyListener;
+        mRemovedListener = removedListener;
+        mCapSetListener = setListener;
+        mSmsImpl = new TestImsSmsImpl();
+        // Must set the state to READY in the constructor - onFeatureReady depends on the state
+        // being ready.
+        setFeatureState(STATE_READY);
+    }
+
+    TestMmTelFeature(TestImsService.ReadyListener readyListener,
+            TestImsService.RemovedListener removedListener,
+            TestImsService.CapabilitiesSetListener setListener, Executor executor) {
+        super(executor);
+        Log.d(TAG, "TestMmTelFeature with Executor constructor");
         mReadyListener = readyListener;
         mRemovedListener = removedListener;
         mCapSetListener = setListener;
@@ -154,7 +166,7 @@
     }
 
     public boolean isCallSessionCreated() {
-        return (mCallSession != null) ? true : false;
+        return (mCallSession != null);
     }
 
     public void onIncomingCallReceived(Bundle extras) {
@@ -175,13 +187,7 @@
 
         Executor executor = incomingSession.getExecutor();
         executor.execute(() -> {
-            UiAutomation ui = InstrumentationRegistry.getInstrumentation().getUiAutomation();
-            try {
-                ui.adoptShellPermissionIdentity();
-                notifyIncomingCall(incomingSession, extras);
-            } finally {
-                ui.dropShellPermissionIdentity();
-            }
+            notifyIncomingCall(incomingSession, extras);
         });
     }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
index 08eaa85..3915fc5 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
@@ -16,7 +16,6 @@
 
 package android.telephony.ims.cts;
 
-import android.content.Context;
 import android.telephony.ims.feature.CapabilityChangeRequest;
 import android.telephony.ims.feature.RcsFeature;
 import android.telephony.ims.stub.CapabilityExchangeEventListener;
@@ -43,13 +42,30 @@
     private CapabilityExchangeEventListener mCapEventListener;
     private TestImsService.DeviceCapPublishListener mDeviceCapPublishListener;
 
-    TestRcsFeature(Context context,
-            TestImsService.ReadyListener readyListener,
+    TestRcsFeature(TestImsService.ReadyListener readyListener,
             TestImsService.RemovedListener removedListener,
             TestImsService.CapabilitiesSetListener setListener,
             TestImsService.RcsCapabilityExchangeEventListener capExchangeEventListener) {
-        super(context.getMainExecutor());
+        super();
+        Log.d(TAG, "TestRcsFeature with default constructor");
+        mReadyListener = readyListener;
+        mRemovedListener = removedListener;
+        mCapExchangeEventListener = capExchangeEventListener;
 
+        mRcsCapabilityChangedListener = setListener;
+        mRcsCapabilitiesLte = new RcsImsCapabilities(RcsImsCapabilities.CAPABILITY_TYPE_NONE);
+        mRcsCapabilitiesIWan = new RcsImsCapabilities(RcsImsCapabilities.CAPABILITY_TYPE_NONE);
+
+        setFeatureState(STATE_READY);
+    }
+
+    TestRcsFeature(TestImsService.ReadyListener readyListener,
+            TestImsService.RemovedListener removedListener,
+            TestImsService.CapabilitiesSetListener setListener,
+            TestImsService.RcsCapabilityExchangeEventListener capExchangeEventListener,
+            Executor executor) {
+        super(executor);
+        Log.d(TAG, "TestRcsFeature with Executor constructor");
         mReadyListener = readyListener;
         mRemovedListener = removedListener;
         mCapExchangeEventListener = capExchangeEventListener;
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipTransport.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipTransport.java
index 0ea195c..88dcc2a 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipTransport.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipTransport.java
@@ -23,6 +23,7 @@
 import android.telephony.ims.DelegateStateCallback;
 import android.telephony.ims.stub.SipDelegate;
 import android.telephony.ims.stub.SipTransportImplBase;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
 
@@ -34,6 +35,7 @@
 
 public class TestSipTransport extends SipTransportImplBase {
 
+    private static final String TAG = "TestSipTransport";
     public static final String ONE_TO_ONE_CHAT_TAG =
             "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gppservice.ims.icsi.oma.cpm.msg\"";
     public static final String GROUP_CHAT_TAG =
@@ -54,8 +56,13 @@
     private final ArrayList<TestSipDelegate> mDelegates = new ArrayList<>();
     private final Object mLock = new Object();
 
+    public TestSipTransport() {
+        Log.d(TAG, "TestSipTransport with default constructor");
+    }
+
     public TestSipTransport(Executor executor) {
         super(executor);
+        Log.d(TAG, "TestSipTransport with Executor constructor");
     }
 
     @Override
diff --git a/tests/tests/textclassifier/OWNERS b/tests/tests/textclassifier/OWNERS
index 3e84e0b..3da8126 100644
--- a/tests/tests/textclassifier/OWNERS
+++ b/tests/tests/textclassifier/OWNERS
@@ -1,2 +1,3 @@
 # Bug component: 709498
+
 include platform/frameworks/base:/core/java/android/view/textclassifier/OWNERS
diff --git a/tests/tests/vcn/AndroidTest.xml b/tests/tests/vcn/AndroidTest.xml
index 519b88a..4b431b3 100644
--- a/tests/tests/vcn/AndroidTest.xml
+++ b/tests/tests/vcn/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
 
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java b/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
index f3703d9..028c6b7 100644
--- a/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
+++ b/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
@@ -59,12 +59,13 @@
 import android.os.SystemClock;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.telephony.cts.util.CarrierPrivilegeUtils;
 import android.telephony.cts.util.SubscriptionGroupUtils;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.compatibility.common.util.CarrierPrivilegeUtils;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/tests/tests/voiceRecognition/OWNERS b/tests/tests/voiceRecognition/OWNERS
index 88d73a9..fac43c0 100644
--- a/tests/tests/voiceRecognition/OWNERS
+++ b/tests/tests/voiceRecognition/OWNERS
@@ -1,7 +1,8 @@
 # Bug component: 533220
-adamhe@google.com
-augale@google.com
-joannechung@google.com
-lpeter@google.com
-svetoslavganov@google.com
-tymtsai@google.com
+volnov@google.com
+andreaambu@google.com
+eugeniom@google.com
+schfan@google.com
+
+# Framework team as backup
+include platform/frameworks/base:/core/java/android/service/voice/OWNERS
diff --git a/tests/tests/voiceinteraction/OWNERS b/tests/tests/voiceinteraction/OWNERS
index 88d73a9..8352b6f 100644
--- a/tests/tests/voiceinteraction/OWNERS
+++ b/tests/tests/voiceinteraction/OWNERS
@@ -1,7 +1,3 @@
 # Bug component: 533220
-adamhe@google.com
-augale@google.com
-joannechung@google.com
-lpeter@google.com
-svetoslavganov@google.com
-tymtsai@google.com
+
+include platform/frameworks/base:/core/java/android/service/voice/OWNERS
diff --git a/tests/tests/voicesettings/OWNERS b/tests/tests/voicesettings/OWNERS
index 88d73a9..8352b6f 100644
--- a/tests/tests/voicesettings/OWNERS
+++ b/tests/tests/voicesettings/OWNERS
@@ -1,7 +1,3 @@
 # Bug component: 533220
-adamhe@google.com
-augale@google.com
-joannechung@google.com
-lpeter@google.com
-svetoslavganov@google.com
-tymtsai@google.com
+
+include platform/frameworks/base:/core/java/android/service/voice/OWNERS
diff --git a/tests/translation/OWNERS b/tests/translation/OWNERS
index a1e663a..6344b5e 100644
--- a/tests/translation/OWNERS
+++ b/tests/translation/OWNERS
@@ -1,8 +1,3 @@
 # Bug component: 994311
 
-adamhe@google.com
-augale@google.com
-joannechung@google.com
-lpeter@google.com
-svetoslavganov@google.com
-tymtsai@google.com
+include platform/frameworks/base:/core/java/android/view/translation/OWNERS
diff --git a/tools/cts-tradefed/res/config/cts-developer.xml b/tools/cts-tradefed/res/config/cts-developer.xml
index a74c1a8..62c39d8 100644
--- a/tools/cts-tradefed/res/config/cts-developer.xml
+++ b/tools/cts-tradefed/res/config/cts-developer.xml
@@ -16,7 +16,7 @@
   -->
 <configuration description="Runs the CTS developer added tests">
 
-    <include name="cts" />
+    <include name="cts-common" />
 
     <option name="plan" value="cts-developer" />
 
diff --git a/tools/release-parser/tests/resources/platform.xml b/tools/release-parser/tests/resources/platform.xml
index 5895f77..878cf1a 100644
--- a/tools/release-parser/tests/resources/platform.xml
+++ b/tools/release-parser/tests/resources/platform.xml
@@ -192,11 +192,11 @@
     <library name="org.apache.http.legacy"
             file="/system/framework/org.apache.http.legacy.boot.jar" />
 
-    <!-- These are the standard packages that are white-listed to always have internet
+    <!-- These are the standard packages that are allow-listed to always have internet
          access while in power save mode, even if they aren't in the foreground. -->
     <allow-in-power-save package="com.android.providers.downloads" />
 
-    <!-- These are the standard packages that are white-listed to always have internet
+    <!-- These are the standard packages that are allow-listed to always have internet
          access while in data mode, even if they aren't in the foreground. -->
     <allow-in-data-usage-save package="com.android.providers.downloads" />
 
@@ -204,7 +204,7 @@
     <allow-in-power-save package="com.android.cellbroadcastreceiver" />
     <allow-in-power-save package="com.android.shell" />
 
-    <!-- Whitelist system providers -->
+    <!-- Allowlist system providers -->
     <allow-in-power-save-except-idle package="com.android.providers.calendar" />
     <allow-in-power-save-except-idle package="com.android.providers.contacts" />
 </permissions>