Snap for 8892598 from 4173cce4c7643b053010a001feeada41b4316fcd to mainline-os-statsd-release

Change-Id: Idca1baa81ce7dd0c073ef2ef5fbaa4508da67c43
diff --git a/apps/CameraITS/tests/its_base_test.py b/apps/CameraITS/tests/its_base_test.py
index 9b29ab7..daa55c6 100644
--- a/apps/CameraITS/tests/its_base_test.py
+++ b/apps/CameraITS/tests/its_base_test.py
@@ -52,6 +52,8 @@
     'sensor_fusion': [],
 }
 
+logging.getLogger('matplotlib.font_manager').disabled = True
+
 
 class ItsBaseTest(base_test.BaseTestClass):
   """Base test for CameraITS tests.
diff --git a/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py b/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
index 7d8b9f2..e407fd6 100644
--- a/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
+++ b/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
@@ -71,7 +71,6 @@
       props = cam.get_camera_properties()
       props = cam.override_with_hidden_physical_camera_props(props)
       log_path = self.log_path
-      debug = self.debug_mode
       test_name_w_path = os.path.join(log_path, NAME)
 
       # check SKIP conditions
@@ -113,11 +112,6 @@
         caps = cam.do_capture([req]*THRESH_CONVERGE_FOR_EV, fmt)
         luma_locked = []
         for i, cap in enumerate(caps):
-          if debug:
-            img = image_processing_utils.convert_capture_to_rgb_image(
-                cap, props)
-            image_processing_utils.write_image(
-                img, f'{test_name_w_path}_ev{ev}_frame{i}.jpg')
           if cap['metadata']['android.control.aeState'] == LOCKED:
             ev_meta = cap['metadata']['android.control.aeExposureCompensation']
             logging.debug('cap EV compensation: %d', ev_meta)
@@ -132,7 +126,8 @@
                                   rel_tol=luma_locked_rtol):
                 raise AssertionError(f'AE locked lumas: {luma_locked}, '
                                      f'RTOL: {luma_locked_rtol}')
-      logging.debug('lumas in AE locked captures: %s', str(lumas))
+        logging.debug('lumas per frame ev %d: %s', ev, str(luma_locked))
+      logging.debug('mean lumas in AE locked captures: %s', str(lumas))
       if caps[THRESH_CONVERGE_FOR_EV-1]['metadata'][
           'android.control.aeState'] != LOCKED:
         raise AssertionError(f'No AE lock by {THRESH_CONVERGE_FOR_EV} frame.')
diff --git a/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py b/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py
index e3143f4..7fffa72 100644
--- a/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py
+++ b/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py
@@ -32,6 +32,7 @@
 _SHADING_MODES = {0: 'LSC_OFF', 1: 'LSC_FAST', 2: 'LSC_HQ'}
 _NUM_SHADING_MODES = len(_SHADING_MODES)
 _THRESHOLD_DIFF_RATIO = 0.15
+_VGA_W, _VGA_H = 640, 480
 
 
 def create_plots(shading_maps, reference_maps, num_map_gains, log_path):
@@ -76,9 +77,8 @@
 
   Lens shading correction modes are OFF=0, FAST=1, and HQ=2.
 
-  Uses smallest yuv size matching the aspect ratio of largest yuv size to
-  reduce some USB bandwidth overhead since we are only looking at output
-  metadata in this test.
+  Uses VGA sized captures to reduce some USB bandwidth overhead since we are
+  only looking at output metadata in this test.
 
   First asserts all modes are supported. Then runs 2 captures.
 
@@ -118,13 +118,11 @@
                        % str(props.get('android.shading.availableModes')),
                        [*_SHADING_MODES])
 
-      # get smallest matching fmt
+      # define fmt
       mono_camera = camera_properties_utils.mono_camera(props)
       cam.do_3a(mono_camera=mono_camera)
-      largest_yuv_fmt = capture_request_utils.get_largest_yuv_format(props)
-      largest_yuv_size = (largest_yuv_fmt['width'], largest_yuv_fmt['height'])
-      cap_fmt = capture_request_utils.get_smallest_yuv_format(
-          props, match_ar=largest_yuv_size)
+      cap_fmt = {'format': 'yuv', 'width': _VGA_W, 'height': _VGA_H}
+      logging.debug('Capture format: %s', str(cap_fmt))
 
       # cap1
       reference_maps = [[] for mode in range(_NUM_SHADING_MODES)]
diff --git a/apps/CameraITS/tests/scene2_a/test_auto_flash.py b/apps/CameraITS/tests/scene2_a/test_auto_flash.py
index b20da2d..c00cd5c 100644
--- a/apps/CameraITS/tests/scene2_a/test_auto_flash.py
+++ b/apps/CameraITS/tests/scene2_a/test_auto_flash.py
@@ -107,10 +107,10 @@
       test_name = os.path.join(self.log_path, _TEST_NAME)
 
       # check SKIP conditions
-      first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
+      vendor_api_level = its_session_utils.get_vendor_api_level(self.dut.serial)
       camera_properties_utils.skip_unless(
           camera_properties_utils.flash(props) and
-          first_api_level >= its_session_utils.ANDROID13_API_LEVEL)
+          vendor_api_level >= its_session_utils.ANDROID13_API_LEVEL)
 
       # establish connection with lighting controller
       arduino_serial_port = lighting_control_utils.lighting_control(
diff --git a/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py b/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
index 658ec8b..cb5be2a 100644
--- a/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
+++ b/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
@@ -27,7 +27,7 @@
 class CameraLaunchSPerfClassTest(its_base_test.ItsBaseTest):
   """Test camera launch latency for S performance class as specified in CDD.
 
-  [7.5/H-1-6] MUST have camera2 startup latency (open camera to first preview
+  [2.2.7.2/7.5/H-1-6] MUST have camera2 startup latency (open camera to first preview
   frame) < 600ms as measured by the CTS camera PerformanceTest under ITS
   lighting conditions (3000K) for both primary cameras.
   """
diff --git a/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py b/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
index f56d34c..fb19f2f 100644
--- a/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
+++ b/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
@@ -27,7 +27,7 @@
 class JpegCaptureSPerfClassTest(its_base_test.ItsBaseTest):
   """Test jpeg capture latency for S performance class as specified in CDD.
 
-  [7.5/H-1-5] MUST have camera2 JPEG capture latency < 1000ms for 1080p
+  [2.2.7.2/7.5/H-1-5] MUST have camera2 JPEG capture latency < 1000ms for 1080p
   resolution as measured by the CTS camera PerformanceTest under ITS lighting
   conditions (3000K) for both primary cameras.
   """
diff --git a/apps/CameraITS/tests/scene3/test_edge_enhancement.py b/apps/CameraITS/tests/scene3/test_edge_enhancement.py
index c6a3bcb..c1b63c7 100644
--- a/apps/CameraITS/tests/scene3/test_edge_enhancement.py
+++ b/apps/CameraITS/tests/scene3/test_edge_enhancement.py
@@ -67,17 +67,17 @@
   for n in range(NUM_SAMPLES):
     cap = cam.do_capture(req, out_surface, repeat_request=req)
     y, _, _ = image_processing_utils.convert_capture_to_planes(cap)
-    chart.img = image_processing_utils.normalize_img(
-        image_processing_utils.get_image_patch(
-            y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+    chart.img = image_processing_utils.get_image_patch(
+        y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm)
     if n == 0:
       image_processing_utils.write_image(
           chart.img, '%s_edge=%d.jpg' % (
               os.path.join(log_path, NAME), edge_mode))
       edge_mode_res = cap['metadata']['android.edge.mode']
     sharpness_list.append(
-        image_processing_utils.compute_image_sharpness(chart.img))
-
+        image_processing_utils.compute_image_sharpness(chart.img)*255)
+  logging.debug('edge mode: %d, sharpness values: %s',
+                edge_mode_res, sharpness_list)
   return {'edge_mode': edge_mode_res, 'sharpness': np.mean(sharpness_list)}
 
 
@@ -89,7 +89,6 @@
   """
 
   def test_edge_enhancement(self):
-    logging.debug('Starting %s', NAME)
     with its_session_utils.ItsSession(
         device_id=self.dut.serial,
         camera_id=self.camera_id,
diff --git a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
index c5e9b19..d67ebe4 100644
--- a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
+++ b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
@@ -107,16 +107,15 @@
   caps = cam.do_capture([req]*NUM_SAMPLES, [out_surface], reprocess_format)
   for n in range(NUM_SAMPLES):
     y, _, _ = image_processing_utils.convert_capture_to_planes(caps[n])
-    chart.img = image_processing_utils.normalize_img(
-        image_processing_utils.get_image_patch(
-            y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+    chart.img = image_processing_utils.get_image_patch(
+        y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm)
     if n == 0:
       image_processing_utils.write_image(
           chart.img, '%s_reprocess_fmt_%s_edge=%d.jpg' % (
               os.path.join(log_path, NAME), reprocess_format, edge_mode))
       edge_mode_res = caps[n]['metadata']['android.edge.mode']
     sharpness_list.append(
-        image_processing_utils.compute_image_sharpness(chart.img))
+        image_processing_utils.compute_image_sharpness(chart.img)*255)
   logging.debug('Sharpness list for edge mode %d: %s',
                 edge_mode, str(sharpness_list))
   return {'edge_mode': edge_mode_res, 'sharpness': np.mean(sharpness_list)}
@@ -134,7 +133,6 @@
   """
 
   def test_reprocess_edge_enhancement(self):
-    logging.debug('Starting %s', NAME)
     logging.debug('Edge modes: %s', str(EDGE_MODES))
     with its_session_utils.ItsSession(
         device_id=self.dut.serial,
@@ -179,9 +177,10 @@
 
       # Initialize plot
       pylab.figure('reprocess_result')
-      pylab.title(NAME)
-      pylab.xlabel('Edge Enhance Mode')
-      pylab.ylabel('Sharpness')
+      pylab.suptitle(NAME)
+      pylab.title(str(EDGE_MODES))
+      pylab.xlabel('Edge Enhancement Mode')
+      pylab.ylabel('Image Sharpness')
       pylab.xticks(EDGE_MODES_VALUES)
 
       # Get the sharpness for each edge mode for regular requests
@@ -244,6 +243,7 @@
         logging.debug('Check reprocess format: %s', reprocess_format)
         check_edge_modes(sharpnesses_reprocess[reprocess_format])
 
+        # Check reprocessing doesn't make everyting worse
         hq_div_off_reprocess = (
             sharpnesses_reprocess[reprocess_format][EDGE_MODES['HQ']] /
             sharpnesses_reprocess[reprocess_format][EDGE_MODES['OFF']])
@@ -251,11 +251,10 @@
             sharpness_regular[EDGE_MODES['HQ']] /
             sharpness_regular[EDGE_MODES['OFF']])
         logging.debug('Verify reprocess HQ ~= reg HQ relative to OFF')
-        if not math.isclose(hq_div_off_reprocess, hq_div_off_regular,
-                            rel_tol=SHARPNESS_RTOL):
-          raise AssertionError(f'HQ/OFF_reprocess: {hq_div_off_reprocess:.4f}, '
-                               f'HQ/OFF_reg: {hq_div_off_regular:.4f}, '
-                               f'RTOL: {SHARPNESS_RTOL}')
+        if hq_div_off_reprocess < hq_div_off_regular*(1-SHARPNESS_RTOL):
+          raise AssertionError(
+              f'HQ/OFF_{reprocess_format}: {hq_div_off_reprocess:.4f}, '
+              f'HQ/OFF_reg: {hq_div_off_regular:.4f}, RTOL: {SHARPNESS_RTOL}')
 
 
 if __name__ == '__main__':
diff --git a/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py b/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
index 1f5b7c0..2781f18 100644
--- a/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
+++ b/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
@@ -35,9 +35,9 @@
 _ROUNDESS_DELTA_THRESHOLD = 0.05
 
 _MAX_CENTER_THRESHOLD_PERCENT = 0.075
-_MAX_DIMENSION_SIZE = (1920, 1440)  # max mandatory preview stream resolution
+_MAX_AREA = 1920 * 1440  # max mandatory preview stream resolution
 _MIN_CENTER_THRESHOLD_PERCENT = 0.02
-_MIN_DIMENSION_SIZE = (176, 144)  # assume QCIF to be min preview size
+_MIN_AREA = 176 * 144  # assume QCIF to be min preview size
 
 
 def _collect_data(cam, video_size, stabilize):
@@ -93,23 +93,19 @@
     threshold value ratio between which the circle centers can differ
   """
 
-  max_diagonal = _point_distance(0, 0,
-                                 _MAX_DIMENSION_SIZE[0], _MAX_DIMENSION_SIZE[1])
-  min_diagonal = _point_distance(0, 0,
-                                 _MIN_DIMENSION_SIZE[0], _MIN_DIMENSION_SIZE[1])
+  img_area = image_size[0] * image_size[1]
 
-  img_diagonal = _point_distance(0, 0, image_size[0], image_size[1])
+  normalized_area = ((img_area - _MIN_AREA) /
+                         (_MAX_AREA - _MIN_AREA))
 
-  normalized_diagonal = ((img_diagonal - min_diagonal) /
-                         (max_diagonal - min_diagonal))
-
-  if normalized_diagonal > 1 or normalized_diagonal < 0:
-    raise AssertionError(f'normalized diagonal > 1 or < 0!'
-                         f' img_diag: {img_diagonal}, '
-                         f' normalized_diagonal: {normalized_diagonal}')
+  if normalized_area > 1 or normalized_area < 0:
+    raise AssertionError(f'normalized area > 1 or < 0! '
+                         f'image_size[0]: {image_size[0]}, '
+                         f'image_size[1]: {image_size[1]}, '
+                         f'normalized_area: {normalized_area}')
 
   # Threshold should be larger for images with smaller resolution
-  normalized_threshold_percent = ((1 - normalized_diagonal) *
+  normalized_threshold_percent = ((1 - normalized_area) *
                                   (_MAX_CENTER_THRESHOLD_PERCENT -
                                    _MIN_CENTER_THRESHOLD_PERCENT))
 
@@ -144,7 +140,7 @@
 
       # Load scene.
       its_session_utils.load_scene(cam, props, self.scene,
-                                   self.tablet, chart_distance=0)
+                                   self.tablet, self.chart_distance)
 
       # Check skip condition
       first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
@@ -253,7 +249,8 @@
                              f'{_ROUNDESS_DELTA_THRESHOLD}, '
                              f'actual ratio difference: {roundness_diff}. ')
 
-        # Distance between centers
+        # Distance between centers, x_offset and y_offset are relative to the
+        # radius of the circle, so they're normalized. Not pixel values.
         unstab_center = (ustab_circle['x_offset'], ustab_circle['y_offset'])
         logging.debug('unstabilized center: %s', unstab_center)
         stab_center = (stab_circle['x_offset'], stab_circle['y_offset'])
diff --git a/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py b/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
index 6eaca19..bb71367 100644
--- a/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
+++ b/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
@@ -137,13 +137,13 @@
       logging.debug('physical available focal lengths: %s', str(fls_physical))
 
       # Check SKIP conditions.
-      first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
+      vendor_api_level = its_session_utils.get_vendor_api_level(self.dut.serial)
       camera_properties_utils.skip_unless(
-          first_api_level >= its_session_utils.ANDROID13_API_LEVEL)
+          vendor_api_level >= its_session_utils.ANDROID13_API_LEVEL)
 
       # Load scene.
       its_session_utils.load_scene(cam, props, self.scene,
-                                   self.tablet, chart_distance=0)
+                                   self.tablet, self.chart_distance)
 
       # Determine camera capabilities.
       supported_video_qualities = cam.get_supported_video_qualities(
diff --git a/apps/CameraITS/tests/scene6/test_zoom.py b/apps/CameraITS/tests/scene6/test_zoom.py
index d4fa21c..c1f4dff 100644
--- a/apps/CameraITS/tests/scene6/test_zoom.py
+++ b/apps/CameraITS/tests/scene6/test_zoom.py
@@ -78,10 +78,6 @@
   test_tols = {}
   test_yuv_sizes = []
   for i in physical_ids:
-    min_fd = physical_props[i]['android.lens.info.minimumFocusDistance']
-    focal_l = physical_props[i]['android.lens.info.availableFocalLengths'][0]
-    logging.debug('cam[%s] min_fd: %.3f (diopters), fl: %.2f',
-                  i, min_fd, focal_l)
     yuv_sizes = capture_request_utils.get_available_output_sizes(
         'yuv', physical_props[i])
     test_yuv_sizes.append(yuv_sizes)
@@ -89,13 +85,16 @@
       logging.debug('cam[%s] yuv sizes: %s', i, str(yuv_sizes))
 
     # determine if minimum focus distance is less than rig depth
-    if (math.isclose(min_fd, 0.0, rel_tol=1E-6) or  # fixed focus
-        1.0/min_fd < chart_distance_m*MIN_FOCUS_DIST_TOL):
-      test_tols[focal_l] = (RADIUS_RTOL, OFFSET_RTOL)
-    else:
-      test_tols[focal_l] = (RADIUS_RTOL_MIN_FD, OFFSET_RTOL_MIN_FD)
-      logging.debug('loosening RTOL for cam[%s]: '
-                    'min focus distance too large.', i)
+    min_fd = physical_props[i]['android.lens.info.minimumFocusDistance']
+    for fl in physical_props[i]['android.lens.info.availableFocalLengths']:
+      logging.debug('cam[%s] min_fd: %.3f (diopters), fl: %.2f', i, min_fd, fl)
+      if (math.isclose(min_fd, 0.0, rel_tol=1E-6) or  # fixed focus
+          (1.0/min_fd < chart_distance_m*MIN_FOCUS_DIST_TOL)):
+        test_tols[fl] = (RADIUS_RTOL, OFFSET_RTOL)
+      else:
+        test_tols[fl] = (RADIUS_RTOL_MIN_FD, OFFSET_RTOL_MIN_FD)
+        logging.debug('loosening RTOL for cam[%s]: '
+                      'min focus distance too large.', i)
   # find intersection of formats for max common format
   common_sizes = list(set.intersection(*[set(list) for list in test_yuv_sizes]))
   if debug:
diff --git a/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py b/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
index 0be38b5..195d567 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
@@ -129,7 +129,7 @@
   in gyroscope movement. Test is a PASS if rotation is reduced in video.
   """
 
-  def test_video_stability(self):
+  def test_video_stabilization(self):
     rot_rig = {}
     log_path = self.log_path
 
@@ -139,12 +139,12 @@
         hidden_physical_id=self.hidden_physical_id) as cam:
       props = cam.get_camera_properties()
       props = cam.override_with_hidden_physical_camera_props(props)
-      first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
+      vendor_api_level = its_session_utils.get_vendor_api_level(self.dut.serial)
       supported_stabilization_modes = props[
           'android.control.availableVideoStabilizationModes']
 
       camera_properties_utils.skip_unless(
-          first_api_level >= its_session_utils.ANDROID13_API_LEVEL and
+          vendor_api_level >= its_session_utils.ANDROID13_API_LEVEL and
           _VIDEO_STABILIZATION_MODE in supported_stabilization_modes)
 
       # Raise error if not FRONT or REAR facing camera
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index 9bf89bd..dae63c3 100755
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -240,7 +240,7 @@
       img_name = os.path.join(out_path, f'test_{scene}.jpg')
       logging.info('Please check scene setup in %s', img_name)
       image_processing_utils.write_image(img, img_name)
-      choice = input('Is the image okay for ITS {scene}? (Y/N)').lower()
+      choice = input(f'Is the image okay for ITS {scene}? (Y/N)').lower()
       if choice == 'y':
         break
 
diff --git a/apps/CameraITS/utils/its_session_utils.py b/apps/CameraITS/utils/its_session_utils.py
index e91565e..c2065ba 100644
--- a/apps/CameraITS/utils/its_session_utils.py
+++ b/apps/CameraITS/utils/its_session_utils.py
@@ -1612,6 +1612,18 @@
   return first_api_level
 
 
+def get_vendor_api_level(device_id):
+  """Return the int value for the vendor API level of the device."""
+  cmd = 'adb -s %s shell getprop ro.vendor.api_level' % device_id
+  try:
+    vendor_api_level = int(subprocess.check_output(cmd.split()).rstrip())
+    logging.debug('First vendor API level: %d', vendor_api_level)
+  except (subprocess.CalledProcessError, ValueError):
+    logging.error('No vendor_api_level. Setting to build version.')
+    vendor_api_level = get_build_sdk_version(device_id)
+  return vendor_api_level
+
+
 class ItsSessionUtilsTests(unittest.TestCase):
   """Run a suite of unit tests on this module."""
 
diff --git a/apps/CtsVerifier/Android.bp b/apps/CtsVerifier/Android.bp
index b4485d1..024e038 100644
--- a/apps/CtsVerifier/Android.bp
+++ b/apps/CtsVerifier/Android.bp
@@ -91,6 +91,7 @@
         "CtsForceStopHelper-constants",
         "ctsmediautil",
         "DpmWrapper",
+        "MediaPerformanceClassCommon",
     ],
 
     libs: ["telephony-common"] + ["android.test.runner.stubs"] + ["android.test.base.stubs"] + ["android.test.mock.stubs"] + ["android.car-test-stubs"] + ["voip-common"] + ["truth-prebuilt"],
@@ -114,7 +115,7 @@
 
     compile_multilib: "both",
 
-    manifest: "AndroidManifest-verifierConfig.xml",
+    additional_manifests: ["AndroidManifest-verifierConfig.xml"],
 
     jni_libs: [
         "libctsverifier_jni",
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 5a257de..6e7f4ac 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -248,6 +248,7 @@
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
+            <meta-data android:name="CddTest" android:value="3.8.17/C-1-1,C-2-1" />
             <meta-data android:name="test_category" android:value="@string/test_category_features" />
             <meta-data android:name="test_excluded_features"
                        android:value="android.hardware.type.watch:android.software.leanback:android.hardware.type.automotive" />
@@ -2052,6 +2053,9 @@
             <meta-data android:name="test_required_features" android:value="android.hardware.wifi" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="CddTest" android:value="7.4.5.2" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.ConnectivityManager#registerNetworkCallback|android.net.ConnectivityManager#unregisterNetworkCallback|android.net.ConnectivityManager#getLinkProperties" />
         </activity>
 
         <activity android:name=".net.MultiNetworkConnectivityTestActivity"
@@ -2068,6 +2072,8 @@
                        android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.ConnectivityManager#getNetworkCapabilities|android.net.ConnectivityManager#getAllNetworks|android.net.ConnectivityManager#requestNetwork|android.net.ConnectivityManager#unregisterNetworkCallback|android.net.ConnectivityManager#getActiveNetwork|android.net.ConnectivityManager#getNetworkInfo|android.net.ConnectivityManager#reportNetworkConnectivity" />
         </activity>
 
         <activity android:name=".nfc.NfcTestActivity"
@@ -2827,6 +2833,16 @@
                        android:value="android.hardware.type.automotive"/>
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.hardware.Camera#getNumberOfCameras|
+                               android.hardware.Camera#open|
+                               android.hardware.Camera#startPreview|
+                               android.hardware.Camera#stopPreview|
+                               android.hardware.Camera#takePicture|
+                               android.hardware.Camera#setParameters|
+                               android.hardware.Camera#setDisplayOrientation|
+                               android.hardware.Camera.Parameters#setHorizontalViewAngle|
+                               android.hardware.Camera.Parameters#setVerticalViewAngle" />
         </activity>
         <activity
             android:name=".camera.fov.DetermineFovActivity"
@@ -2836,6 +2852,11 @@
                        android:value="android.hardware.type.automotive"/>
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.media.ExifInterface#TAG_ORIENTATION|
+                               android.media.ExifInterface#ORIENTATION_ROTATE_90|
+                               android.media.ExifInterface#ORIENTATION_ROTATE_180|
+                               android.media.ExifInterface#ORIENTATION_ROTATE_270" />
         </activity>
         <activity
             android:name=".camera.fov.CalibrationPreferenceActivity"
@@ -2861,6 +2882,32 @@
                        android:value="android.hardware.type.automotive"/>
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.hardware.Camera#getParameters|
+                               android.hardware.Camera#lock|
+                               android.hardware.Camera#setDisplayOrientation|
+                               android.hardware.Camera#setPreviewCallback|
+                               android.hardware.Camera#setParameters|
+                               android.hardware.Camera#setPreviewTexture|
+                               android.hardware.Camera#startPreview|
+                               android.hardware.Camera#stopPreview|
+                               android.hardware.Camera#unlock|
+                               android.media.MediaRecorder#prepare|
+                               android.media.MediaRecorder#release|
+                               android.media.MediaRecorder#reset|
+                               android.media.MediaRecorder#setAudioEncoder|
+                               android.media.MediaRecorder#setAudioSource|
+                               android.media.MediaRecorder#setCamera|
+                               android.media.MediaRecorder#setOnErrorListener|
+                               android.media.MediaRecorder#setOutputFormat|
+                               android.media.MediaRecorder#setOutputFile|
+                               android.media.MediaRecorder#setProfile|
+                               android.media.MediaRecorder#setVideoEncoder|
+                               android.media.MediaRecorder#setVideoEncodingBitRate|
+                               android.media.MediaRecorder#setVideoSize|
+                               android.media.MediaRecorder#setVideoSource|
+                               android.media.MediaRecorder#start|
+                               android.media.MediaRecorder#stop" />
         </activity>
 
         <activity android:name=".camera.its.ItsTestActivity"
@@ -3901,174 +3948,6 @@
                        android:value="single_display_mode" />
         </activity>
 
-        <!--            CTS Verifier Presence Test Top Screen -->
-        <activity
-            android:name=".presence.PresenceTestActivity"
-            android:configChanges="keyboardHidden|orientation|screenSize"
-            android:exported="true"
-            android:label="@string/presence_test" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-
-            <meta-data
-                android:name="test_category"
-                android:value="@string/test_category_networking" />
-            <meta-data android:name="display_mode"
-                       android:value="single_display_mode" />
-        </activity>
-
-        <!--
-             CTS Verifier Uwb Precision Test Screen
-                 test category : uwb
-                 test parent : PresenceTestActivity
-        -->
-        <activity
-            android:name=".presence.UwbPrecisionActivity"
-            android:configChanges="keyboardHidden|orientation|screenSize"
-            android:exported="true"
-            android:label="@string/uwb_precision" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-
-            <meta-data
-                android:name="test_category"
-                android:value="@string/uwb" />
-            <meta-data
-                android:name="test_parent"
-                android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
-            <meta-data android:name="display_mode"
-                       android:value="single_display_mode" />
-            <meta-data android:name="CddTest"
-                       android:value="7.4.9/C-1-1" />
-        </activity>
-
-        <!--
-             CTS Verifier Uwb Short Range Test Screen
-                 test category : uwb
-                 test parent : PresenceTestActivity
-        -->
-        <activity
-            android:name=".presence.UwbShortRangeActivity"
-            android:configChanges="keyboardHidden|orientation|screenSize"
-            android:exported="true"
-            android:label="@string/uwb_short_range" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-
-            <meta-data
-                android:name="test_category"
-                android:value="@string/uwb" />
-            <meta-data
-                android:name="test_parent"
-                android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
-            <meta-data
-                android:name="display_mode"
-                android:value="single_display_mode" />
-            <meta-data
-                android:name="CddTest"
-                android:value="7.4.9/C-1-2" />
-        </activity>
-
-        <!--
-            CTS Verifier BLE RSSI Precision Test Screen
-                test category : BLE
-                test parent : PresenceTestActivity
-        -->
-        <activity
-            android:name=".presence.BleRssiPrecisionActivity"
-            android:exported="true"
-            android:label="@string/ble_rssi_precision_name">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-
-            <meta-data
-                android:name="test_category"
-                android:value="@string/ble" />
-            <meta-data
-                android:name="test_parent"
-                android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
-            <meta-data
-                android:name="test_required_features"
-                android:value="android.hardware.bluetooth_le" />
-            <meta-data
-                android:name="display_mode"
-                android:value="single_display_mode" />
-            <meta-data
-                android:name="CddText"
-                android:value="7.4.3/C-7-1" />
-        </activity>
-
-        <!--
-            CTS Verifier BLE Rx/Tx Calibration Test Screen
-                test category : BLE
-                test parent : PresenceTestActivity
-        -->
-        <activity
-            android:name=".presence.BleRxTxCalibrationActivity"
-            android:exported="true"
-            android:label="@string/ble_rx_tx_calibration_name">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-
-            <meta-data
-                android:name="test_category"
-                android:value="@string/ble" />
-            <meta-data
-                android:name="test_parent"
-                android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
-            <meta-data
-                android:name="test_required_features"
-                android:value="android.hardware.bluetooth_le" />
-            <meta-data
-                android:name="display_mode"
-                android:value="single_display_mode" />
-            <meta-data
-                android:name="CddText"
-                android:value="7.4.3/C-7-2" />
-        </activity>
-
-        <!-- CTS Verifier Nan Precision and Bias Test Screen
-                 test category : wifi_nan
-                 test parent : PresenceTestActivity
-        -->
-        <activity
-            android:name=".presence.NanPrecisionTestActivity"
-            android:configChanges="keyboardHidden|orientation|screenSize"
-            android:exported="true"
-            android:label="@string/nan_precision" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-
-            <meta-data
-                android:name="test_category"
-                android:value="@string/wifi_nan" />
-            <meta-data
-                android:name="test_parent"
-                android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
-            <meta-data android:name="display_mode"
-                       android:value="single_display_mode" />
-            <meta-data android:name="CddTest"
-                       android:value="7.4.2.5/H-1-1|7.4.2.5/H-1-2" />
-        </activity>
-
         <activity-alias
             android:name=".CtsVerifierActivity"
             android:label="@string/app_name"
@@ -4975,6 +4854,8 @@
                        android:value="android.hardware.type.automotive" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback" />
         </activity>
 
         <activity android:name=".tv.TvInputDiscoveryTestActivity"
@@ -6159,6 +6040,7 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_logcat" />
+            <meta-data android:name="test_excluded_features" android:value="android.hardware.type.automotive" />
         </activity>
 
         <activity android:name=".displaycutout.DisplayCutoutTestActivity"
diff --git a/apps/CtsVerifier/res/layout/ble_rssi_precision.xml b/apps/CtsVerifier/res/layout/ble_rssi_precision.xml
deleted file mode 100644
index 5f01e1f..0000000
--- a/apps/CtsVerifier/res/layout/ble_rssi_precision.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    style="@style/RootLayoutPadding"
-    tools:ignore="Autofill">
-
-    <ScrollView
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content">
-
-        <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-
-            <TextView
-                android:text="@string/ble_rssi_precision_test_instructions"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:scrollbars="vertical" />
-
-            <EditText
-                android:id="@+id/report_rssi_range"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:hint="@string/report_ble_rssi_range"
-                android:inputType="number" />
-
-            <EditText
-                android:id="@+id/report_reference_device"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:hint="@string/report_reference_device"
-                android:inputType="text" />
-
-            <include
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                layout="@layout/pass_fail_buttons" />
-        </LinearLayout>
-    </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_rx_tx_calibration.xml b/apps/CtsVerifier/res/layout/ble_rx_tx_calibration.xml
deleted file mode 100644
index 3ca955b..0000000
--- a/apps/CtsVerifier/res/layout/ble_rx_tx_calibration.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    style="@style/RootLayoutPadding"
-    tools:ignore="Autofill">
-
-    <ScrollView
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content">
-
-        <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-
-            <TextView
-                android:text="@string/ble_rx_tx_calibration_test_instructions"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:scrollbars="vertical" />
-
-            <EditText
-                android:id="@+id/report_channels_rssi_range"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:hint="@string/report_channels_ble_rssi_range"
-                android:inputType="number" />
-
-            <EditText
-                android:id="@+id/report_cores_rssi_range"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:hint="@string/report_cores_ble_rssi_range"
-                android:inputType="number" />
-
-            <EditText
-                android:id="@+id/report_reference_device"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:hint="@string/report_reference_device"
-                android:inputType="text" />
-
-            <include
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                layout="@layout/pass_fail_buttons" />
-        </LinearLayout>
-    </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/clipboard_preview.xml b/apps/CtsVerifier/res/layout/clipboard_preview.xml
index 85f38c8..efec118 100644
--- a/apps/CtsVerifier/res/layout/clipboard_preview.xml
+++ b/apps/CtsVerifier/res/layout/clipboard_preview.xml
@@ -31,86 +31,6 @@
         android:layout_marginBottom="100dp"
         android:layout_marginTop="30dp"
         android:text="@string/clipboard_preview_test_copy_button"/>
-
-    <TableLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
-        <TableRow
-            android:layout_width="match_parent"
-            android:layout_height="50dp">
-            <View android:layout_weight="3"
-                  android:layout_height="50dp"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b1"
-                    android:layout_width="50dp"
-                    android:layout_height="50dp"
-                    android:text="1"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b2"
-                    android:layout_width="50dp"
-                    android:layout_height="50dp"
-                    android:text="2"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b3"
-                    android:layout_width="50dp"
-                    android:layout_height="50dp"
-                    android:text="3"/>
-            <View android:layout_weight="3"
-                  android:layout_height="50dp"/>
-        </TableRow>
-        <TableRow
-            android:layout_width="match_parent"
-            android:layout_height="50dp">
-            <View android:layout_weight="3"
-                  android:layout_height="50dp"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b4"
-                    android:layout_width="50dp"
-                    android:layout_height="50dp"
-                    android:text="4"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b5"
-                    android:layout_width="50dp"
-                    android:layout_height="50dp"
-                    android:text="5"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b6"
-                    android:layout_width="50dp"
-                    android:layout_height="50dp"
-                    android:text="6"/>
-            <View android:layout_weight="3"
-                  android:layout_height="50dp"/>
-        </TableRow>
-        <TableRow
-            android:layout_width="match_parent"
-            android:layout_height="50dp">
-            <View android:layout_weight="3"
-                  android:layout_height="match_parent"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b7"
-                    android:layout_width="50dp"
-                    android:layout_height="match_parent"
-                    android:text="7"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b8"
-                    android:layout_width="50dp"
-                    android:layout_height="match_parent"
-                    android:text="8"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b9"
-                    android:layout_width="50dp"
-                    android:layout_height="match_parent"
-                    android:text="9"/>
-            <View android:layout_weight="3"
-                  android:layout_height="50dp"/>
-        </TableRow>
-    </TableLayout>
-    <Button
-        android:id="@+id/clipboard_preview_test_b0"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:text="0"/>
     <include
         android:id="@+id/clipboard_preview_test_pass_fail"
         android:layout_width="match_parent"
diff --git a/apps/CtsVerifier/res/layout/nan_precision.xml b/apps/CtsVerifier/res/layout/nan_precision.xml
deleted file mode 100644
index c81a9c4..0000000
--- a/apps/CtsVerifier/res/layout/nan_precision.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:orientation="vertical"
-                style="@style/RootLayoutPadding">
-    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content">
-        <LinearLayout android:orientation="vertical"
-                      android:layout_width="match_parent"
-                      android:layout_height="wrap_content">
-            <TextView android:text="@string/nan_precision_instruction"
-                      android:id="@+id/nan_precision_instruction"
-                      android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:scrollbars="vertical"/>
-            <LinearLayout android:orientation="vertical"
-                          android:layout_width="match_parent"
-                          android:layout_height="wrap_content">
-                <EditText android:id="@+id/nan_bandwidth"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="number"
-                          android:hint="@string/report_nan_bandwidth_mhz"/>
-                <EditText android:id="@+id/distance_range_10cm_gt_68p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_10cm_gt_68p"/>
-                <EditText android:id="@+id/distance_range_1m_gt_68p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_1m_gt_68p"/>
-                <EditText android:id="@+id/distance_range_3m_gt_68p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_3m_gt_68p"/>
-                <EditText android:id="@+id/distance_range_5m_gt_68p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_5m_gt_68p"/>
-                <EditText android:id="@+id/distance_range_10cm_gt_90p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_10cm_gt_90p"/>
-                <EditText android:id="@+id/distance_range_1m_gt_90p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_1m_gt_90p"/>
-                <EditText android:id="@+id/distance_range_3m_gt_90p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_3m_gt_90p"/>
-                <EditText android:id="@+id/distance_range_5m_gt_90p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_5m_gt_90p"/>
-                <EditText android:id="@+id/reference_device"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:hint="@string/report_reference_device"/>
-            </LinearLayout>
-
-            <include android:layout_width="match_parent"
-                     android:layout_height="wrap_content"
-                     layout="@layout/pass_fail_buttons"/>
-        </LinearLayout>
-    </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/uwb_precision.xml b/apps/CtsVerifier/res/layout/uwb_precision.xml
deleted file mode 100644
index 14e996d..0000000
--- a/apps/CtsVerifier/res/layout/uwb_precision.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:orientation="vertical"
-                style="@style/RootLayoutPadding">
-    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content">
-        <LinearLayout android:orientation="vertical"
-                      android:layout_width="match_parent"
-                      android:layout_height="wrap_content">
-            <TextView android:text="@string/uwb_precision_instruction"
-                      android:id="@+id/uwb_precision_instruction"
-                      android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:scrollbars="vertical"/>
-            <LinearLayout android:orientation="vertical"
-                          android:layout_width="match_parent"
-                          android:layout_height="wrap_content">
-                <EditText android:id="@+id/distance_range_cm"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_cm"/>
-                <EditText android:id="@+id/reference_device"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:hint="@string/report_reference_device"/>
-            </LinearLayout>
-
-            <include android:layout_width="match_parent"
-                     android:layout_height="wrap_content"
-                     layout="@layout/pass_fail_buttons"/>
-        </LinearLayout>
-    </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/uwb_short_range.xml b/apps/CtsVerifier/res/layout/uwb_short_range.xml
deleted file mode 100644
index 9afc6e5..0000000
--- a/apps/CtsVerifier/res/layout/uwb_short_range.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        style="@style/RootLayoutPadding">
-    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content">
-        <LinearLayout android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-            <TextView android:text="@string/uwb_short_range_instruction"
-                    android:id="@+id/uwb_short_range_instruction"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:scrollbars="vertical"/>
-            <LinearLayout android:orientation="vertical"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content">
-                <EditText android:id="@+id/distance_median_meters"
-                        android:layout_width="wrap_content"
-                          android:inputType="numberDecimal"
-                        android:layout_height="wrap_content"
-                        android:hint="@string/report_distance_median_meters"/>
-                <EditText android:id="@+id/reference_device"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:hint="@string/report_reference_device"/>
-            </LinearLayout>
-
-            <include android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    layout="@layout/pass_fail_buttons"/>
-        </LinearLayout>
-    </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 4862965..0f32b34 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -32,6 +32,16 @@
     <string name="finish_button_text">Finish</string>
     <string name="fail_and_next_button_text">Fail and Next</string>
 
+    <!-- Strings for CtsReportLog warning -->
+    <string name="reportlog_warning_title">CTS-Verifier Report Log</string>
+    <string name="reportlog_warning_body">Can\'t create folder for CTS-Verifier Report Logs.
+        \n\nPlease enable Report Log creation by exiting CTS Verifier and running the following commands:
+        \n\n<code>adb shell appops set com.android.cts.verifier android:read_device_identifiers allow</code>
+        \n\n<code>adb shell appops set com.android.cts.verifier MANAGE_EXTERNAL_STORAGE 0</code>
+        \n\nTest instructions are found in the \"Using CTS Verifier\" document found at
+        <a href="https://source.android.com/compatibility/cts/verifier">https://source.android.com/compatibility/cts/verifier</a>
+    </string>
+
     <!-- Strings for TestListActivity -->
     <string name="test_category_audio">Audio</string>
     <string name="test_category_camera">Camera</string>
@@ -301,9 +311,11 @@
     </string>
     <string name="clipboard_preview_test_instructions">
         Press the \'Copy\' button to copy the secret code to the clipboard.
-        \n\nUse the clipboard preview UI, or the clipboard editor component to view the secret code.
-        \n\nEnter the secret code using the buttons below.
+        \n\n If nothing happens, press Fail.
+        \n\n If you see the word "FAIL" appear on screen, press Fail.
+        \n\n If you see a confirmation that content has been copied to the clipboard, press Pass.
     </string>
+    <string name="clipboard_preview_test_secret">FAIL</string>
     <string name="clipboard_preview_test_copy_button">Copy</string>
 
 
@@ -778,7 +790,7 @@
     <!-- BLE Advertising Set test strings -->
     <string name="ble_advertising_set_test_name">Bluetooth LE Advertising Set Test</string>
     <string name="ble_advertising_set_test_info">Bluetooth LE Advertising Set tests AdvertisingSet and AdvertisingSetCallback APIs.</string>
-    <string name="ble_advertising_set_test_instruction">Press the \"Set Up\" button first, then start the test by pressing the \"Start Test\" button. UI thread may freeze for a few seconds while enabling/disabling bluetooth adapter.</string>
+    <string name="ble_advertising_set_test_instruction">Press the \"Start Test\" button. UI thread may freeze for a few seconds while enabling/disabling bluetooth adapter.</string>
     <string name="ble_advertising_set_start_test">Start Test</string>
     <string name="ble_advertising_set_running_test">Running Test...</string>
     <string name="ble_advertising_set_finished_test">Finished Test</string>
@@ -5480,6 +5492,7 @@
     <string name="audio_general_test_not_run">Test Not Run</string>
     <string name="audio_general_testnotcompleted">Test not completed.</string>
 
+    <string name="audio_general_reportlogtest">[Can\'t Write ReportLog]</string>
 
     <!-- Audio Loopback Latency Test -->
     <string name="audio_loopback_latency_test">Audio Loopback Latency Test</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/CtsVerifierReportLog.java b/apps/CtsVerifier/src/com/android/cts/verifier/CtsVerifierReportLog.java
index b013bb7..a93e3b5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/CtsVerifierReportLog.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/CtsVerifierReportLog.java
@@ -74,6 +74,10 @@
         }
     }
 
+    public boolean isOpen() {
+        return mStore != null;
+    }
+
     /**
      * Closes report file. Static functions that do not have access to instrumentation can
      * use this to close report logs. Summary, if present, is not reported to instrumentation, hence
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
index 0294ff7..36975c2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
@@ -32,7 +32,6 @@
 import android.os.Bundle;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.View;
@@ -143,11 +142,13 @@
 
     public static class Activity extends android.app.Activity implements PassFailActivity {
         private WakeLock mWakeLock;
-        private final CtsVerifierReportLog mReportLog;
+        private CtsVerifierReportLog mReportLog;
         private final TestResultHistoryCollection mHistoryCollection;
 
+        protected boolean mRequireReportLogToPass;
+
         public Activity() {
-            this.mReportLog = new CtsVerifierReportLog(getReportFileName(), getReportSectionName());
+            newReportLog();
             this.mHistoryCollection = new TestResultHistoryCollection();
         }
 
@@ -159,6 +160,10 @@
                         .newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "PassFailButtons");
                 mWakeLock.acquire();
             }
+
+            if (!this.mReportLog.isOpen()) {
+                showReportLogWarningDialog(this);
+            }
         }
 
         @Override
@@ -206,12 +211,25 @@
                     getHistoryCollection());
         }
 
+        protected CtsVerifierReportLog newReportLog() {
+            return mReportLog = new CtsVerifierReportLog(
+                    getReportFileName(), getReportSectionName());
+        }
+
         @Override
         public CtsVerifierReportLog getReportLog() {
             return mReportLog;
         }
 
         /**
+         * A mechanism to block tests from passing if no ReportLog data has been collected.
+         * @return true if the ReportLog is open OR if the test does not require that.
+         */
+        public boolean isReportLogOkToPass() {
+            return !mRequireReportLogToPass || mReportLog.isOpen();
+        }
+
+        /**
          * @return The name of the file to store the (suite of) ReportLog information.
          */
         @Override
@@ -527,6 +545,12 @@
         activity.showDialog(INFO_DIALOG_ID, args);
     }
 
+    protected static void showReportLogWarningDialog(final android.app.Activity activity) {
+        showInfoDialog(activity,
+                R.string.reportlog_warning_title, R.string.reportlog_warning_body, -1);
+    }
+
+
     protected static Dialog createDialog(final android.app.Activity activity, int id, Bundle args) {
         switch (id) {
             case INFO_DIALOG_ID:
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
index 528d914..83b32de 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
@@ -182,12 +182,15 @@
             mResultsTxt.setText(getResources().getString(R.string.analog_headset_pass_noheadset));
             return true;
         } else {
-            boolean pass = mPlugIntentReceived &&
-                    mHeadsetDeviceInfo != null &&
-                    mPlaybackSuccess &&
-                    (mHasHeadsetHook || mHasPlayPause) && mHasVolUp && mHasVolDown;
+            boolean pass = isReportLogOkToPass()
+                    && mPlugIntentReceived
+                    && mHeadsetDeviceInfo != null
+                    && mPlaybackSuccess
+                    && (mHasHeadsetHook || mHasPlayPause) && mHasVolUp && mHasVolDown;
             if (pass) {
                 mResultsTxt.setText(getResources().getString(R.string.analog_headset_pass));
+            } else if (!isReportLogOkToPass()) {
+                mResultsTxt.setText(getResources().getString(R.string.audio_general_reportlogtest));
             }
             return pass;
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
index 48795ef..3c1b8a1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
@@ -542,8 +542,10 @@
             Log.v(TAG, "Test EndedOk. " + testId + " str:"+str);
             showView(mProgress, false);
             mResultTest.setText("test completed. " + str);
-            if (mTestAECPassed) {
-                getPassButton().setEnabled(true);;
+            if (!isReportLogOkToPass()) {
+                mResultTest.setText(getResources().getString(R.string.audio_general_reportlogtest));
+            } else if (mTestAECPassed) {
+                getPassButton().setEnabled(true);
             }
         }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
index a6bd4ad..413734b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
@@ -127,11 +127,11 @@
 
     private TestSpec[] mTestSpecs = new TestSpec[NUM_TEST_ROUTES];
     class TestSpec {
+        private static final String TAG = "AudioLoopbackLatencyActivity.TestSpec";
         // impossibly low latencies (indicating something in the test went wrong).
         protected static final double LOWEST_REASONABLE_LATENCY_MILLIS = 1.0;
 
         final int mRouteId;
-        // final double mMustLatencyMS;
 
         // runtime assigned device ID
         static final int DEVICEID_NONE = -1;
@@ -151,7 +151,6 @@
         boolean mRouteAvailable; // Have we seen this route/device at any time
         boolean mRouteConnected; // is the route available NOW
         boolean mTestRun;
-        // boolean mTestPass;
 
         TestSpec(int routeId, double requiredConfidence) {
             mRouteId = routeId;
@@ -181,14 +180,6 @@
             mMeanConfidence = StatUtils.calculateMean(mConfidence);
         }
 
-        boolean getRouteAvailable() {
-            return mRouteAvailable;
-        }
-
-        boolean getTestRun() {
-            return mTestRun;
-        }
-
         boolean isMeasurementValid() {
             return mTestRun && mMeanLatencyMS > 1.0 && mMeanConfidence >= mRequiredConfidence;
         }
@@ -224,60 +215,42 @@
         }
 
         // ReportLog Schema (per route)
-        private static final String KEY_ROUTEAVAILABLE = "route_available";
-        private static final String KEY_ROUTECONNECTED = "route_connected";
-        private static final String KEY_ROUTERUN = "route_run";
-        private static final String KEY_LATENCY = "route_latency";
-        private static final String KEY_CONFIDENCE = "route_confidence";
-        private static final String KEY_MEANABSDEVIATION = "route_mean_absolute_deviation";
-        private static final String KEY_IS_PERIPHERAL_ATTACHED = "route_is_peripheral_attached";
-        private static final String KEY_INPUT_PERIPHERAL_NAME = "route_input_peripheral";
-        private static final String KEY_OUTPUT_PERIPHERAL_NAME = "route_output_peripheral";
-        private static final String KEY_TEST_PERIPHERAL = "route_test_peripheral";
-
-        String makeSectionKey(String key) {
-            return Integer.toString(mRouteId) + "_" + key;
-        }
+        private static final String KEY_ROUTEINDEX = "route_index";
+        private static final String KEY_LATENCY = "latency";
+        private static final String KEY_CONFIDENCE = "confidence";
+        private static final String KEY_MEANABSDEVIATION = "mean_absolute_deviation";
+        private static final String KEY_IS_PERIPHERAL_ATTACHED = "is_peripheral_attached";
+        private static final String KEY_INPUT_PERIPHERAL_NAME = "input_peripheral";
+        private static final String KEY_OUTPUT_PERIPHERAL_NAME = "output_peripheral";
+        private static final String KEY_TEST_PERIPHERAL = "test_peripheral";
 
         void recordTestResults(CtsVerifierReportLog reportLog) {
             reportLog.addValue(
-                    makeSectionKey(KEY_ROUTEAVAILABLE),
-                    mRouteAvailable ? 1 : 0,
+                    KEY_ROUTEINDEX,
+                    mRouteId,
                     ResultType.NEUTRAL,
                     ResultUnit.NONE);
 
             reportLog.addValue(
-                    makeSectionKey(KEY_ROUTECONNECTED),
-                    mRouteConnected ? 1 : 0,
-                    ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-
-            reportLog.addValue(
-                    makeSectionKey(KEY_ROUTERUN),
-                    mTestRun ? 1 : 0,
-                    ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-
-            reportLog.addValue(
-                    makeSectionKey(KEY_LATENCY),
+                    KEY_LATENCY,
                     mMeanLatencyMS,
                     ResultType.LOWER_BETTER,
                     ResultUnit.MS);
 
             reportLog.addValue(
-                    makeSectionKey(KEY_CONFIDENCE),
+                    KEY_CONFIDENCE,
                     mMeanConfidence,
                     ResultType.HIGHER_BETTER,
                     ResultUnit.NONE);
 
             reportLog.addValue(
-                    makeSectionKey(KEY_MEANABSDEVIATION),
+                    KEY_MEANABSDEVIATION,
                     mMeanAbsoluteDeviation,
                     ResultType.NEUTRAL,
                     ResultUnit.NONE);
 
             reportLog.addValue(
-                    makeSectionKey(KEY_TEST_PERIPHERAL),
+                    KEY_TEST_PERIPHERAL,
                     mDeviceName,
                     ResultType.NEUTRAL,
                     ResultUnit.NONE);
@@ -294,6 +267,8 @@
         getPassButton().setEnabled(false);
         setInfoResources(R.string.audio_loopback_latency_test, R.string.audio_loopback_info, -1);
 
+        mRequireReportLogToPass = true;
+
         mClaimsOutput = AudioSystemFlags.claimsOutput(this);
         mClaimsInput = AudioSystemFlags.claimsInput(this);
         mClaimsProAudio = AudioSystemFlags.claimsProAudio(this);
@@ -474,7 +449,6 @@
                     mTestSpecs[TESTROUTE_USB].mDeviceName = devInfo.getProductName().toString();
             }
 
-            // setTestButtonsState();
             enableStartButtons(true);
         }
     }
@@ -533,69 +507,66 @@
         return setTestNameSuffix(sCurrentDisplayMode, "audio_loopback_latency_activity");
     }
 
-    // Schema
+    // Test-Schema
     private static final String KEY_SAMPLE_RATE = "sample_rate";
     private static final String KEY_IS_PRO_AUDIO = "is_pro_audio";
     private static final String KEY_IS_LOW_LATENCY = "is_low_latency";
     private static final String KEY_TEST_MMAP = "supports_mmap";
     private static final String KEY_TEST_MMAPEXCLUSIVE = "supports_mmap_exclusive";
     private static final String KEY_LEVEL = "level";
-    //
-    // Subclasses should call this explicitly. SubClasses should call submit() after their logs
-    //
+
+    private void recordRouteResults(int routeIndex) {
+        if (mTestSpecs[routeIndex].mTestRun) {
+            CtsVerifierReportLog reportLog = newReportLog();
+
+            int audioLevel = mAudioLevelSeekbar.getProgress();
+            reportLog.addValue(
+                    KEY_LEVEL,
+                    audioLevel,
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+
+            reportLog.addValue(
+                    KEY_IS_PRO_AUDIO,
+                    mClaimsProAudio,
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+
+            reportLog.addValue(
+                    KEY_TEST_MMAP,
+                    mSupportsMMAP,
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+
+            reportLog.addValue(
+                    KEY_TEST_MMAPEXCLUSIVE,
+                    mSupportsMMAPExclusive,
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+
+            reportLog.addValue(
+                    KEY_SAMPLE_RATE,
+                    mNativeAnalyzerThread.getSampleRate(),
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+
+            reportLog.addValue(
+                    KEY_IS_LOW_LATENCY,
+                    mNativeAnalyzerThread.isLowLatencyStream(),
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+
+            mTestSpecs[routeIndex].recordTestResults(reportLog);
+
+            reportLog.submit();
+        }
+    }
+
     @Override
     public void recordTestResults() {
-        Log.i(TAG, "recordTestResults() mNativeAnalyzerThread:" + mNativeAnalyzerThread);
-
-        // We need to rework that
-        CtsVerifierReportLog reportLog = getReportLog();
-
-        int audioLevel = mAudioLevelSeekbar.getProgress();
-        reportLog.addValue(
-                KEY_LEVEL,
-                audioLevel,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_IS_PRO_AUDIO,
-                mClaimsProAudio,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_TEST_MMAP,
-                mSupportsMMAP,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_TEST_MMAPEXCLUSIVE ,
-                mSupportsMMAPExclusive,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        if (mNativeAnalyzerThread == null) {
-            return; // no test results to report
+        for (int route = 0; route < NUM_TEST_ROUTES; route++) {
+            recordRouteResults(route);
         }
-
-        reportLog.addValue(
-                KEY_SAMPLE_RATE,
-                mNativeAnalyzerThread.getSampleRate(),
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_IS_LOW_LATENCY,
-                mNativeAnalyzerThread.isLowLatencyStream(),
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        for (TestSpec testSpec : mTestSpecs) {
-            testSpec.recordTestResults(reportLog);
-        }
-
-        reportLog.submit();
     }
 
     private void startAudioTest(Handler messageHandler, int testRouteId) {
@@ -658,6 +629,7 @@
                 e.printStackTrace();
             }
 
+
             mTestPhase++;
             if (mTestPhase >= NUM_TEST_PHASES) {
                 handleTestCompletion();
@@ -683,7 +655,8 @@
         mResultsText[mTestRoute].setText(testSpec.getResultString());
 
         LoopbackLatencyRequirements requirements = new LoopbackLatencyRequirements();
-        boolean pass = requirements.evaluate(mClaimsProAudio,
+        boolean pass = isReportLogOkToPass()
+                && requirements.evaluate(mClaimsProAudio,
                 Build.VERSION.MEDIA_PERFORMANCE_CLASS,
                 mTestSpecs[TESTROUTE_DEVICE].isMeasurementValid()
                         ? mTestSpecs[TESTROUTE_DEVICE].mMeanLatencyMS : 0.0,
@@ -694,8 +667,12 @@
 
         getPassButton().setEnabled(pass);
 
-        String resultText = requirements.getResultsString();
-        mTestStatusText.setText(resultText);
+        StringBuilder sb = new StringBuilder();
+        if (!isReportLogOkToPass()) {
+            sb.append(getResources().getString(R.string.audio_general_reportlogtest) + "\n");
+        }
+        sb.append(requirements.getResultsString());
+        mTestStatusText.setText(sb.toString());
 
         showWait(false);
         enableStartButtons(true);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
index 215d26f..8ff2358 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
@@ -154,6 +154,8 @@
         String yesString = getResources().getString(R.string.audio_general_yes);
         String noString = getResources().getString(R.string.audio_general_no);
 
+        mRequireReportLogToPass = true;
+
         boolean claimsProAudio = AudioSystemFlags.claimsProAudio(this);
         boolean claimsLowLatencyAudio = AudioSystemFlags.claimsLowLatencyAudio(this);
 
@@ -311,11 +313,14 @@
         }
 
         double averageLatency = mLatencyAve[mActiveTestAPI];
-        boolean pass = averageLatency != 0 && averageLatency <= mMaxRequiredLatency;
+        boolean pass = isReportLogOkToPass()
+                && averageLatency != 0 && averageLatency <= mMaxRequiredLatency;
 
         if (pass) {
             mSpecView.setText("Average: " + averageLatency + " ms <= "
                     + mMaxRequiredLatency + " ms -- PASS");
+        } else if (!isReportLogOkToPass()) {
+            mSpecView.setText(getResources().getString(R.string.audio_general_reportlogtest));
         } else {
             mSpecView.setText("Average: " + averageLatency + " ms > "
                     + mMaxRequiredLatency + " ms -- FAIL");
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 126d15f..e93d2b3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
@@ -158,11 +158,9 @@
         boolean usbOK = mClaimsUSBHostMode && mClaimsUSBPeripheralMode;
         boolean hdmiOK = !mClaimsHDMI || isHDMIValid();
 
-        boolean hasPassed = !mClaimsProAudio ||
-                (mClaimsLowLatencyAudio &&
-                mClaimsMIDI &&
-                usbOK &&
-                hdmiOK);
+        boolean hasPassed = isReportLogOkToPass()
+                && !mClaimsProAudio
+                || (mClaimsLowLatencyAudio && mClaimsMIDI && usbOK && hdmiOK);
 
         getPassButton().setEnabled(hasPassed);
         return hasPassed;
@@ -172,7 +170,9 @@
         boolean hasPassed = calculatePass();
 
         Resources strings = getResources();
-        if (hasPassed) {
+        if (!isReportLogOkToPass()) {
+            mTestStatusLbl.setText(getResources().getString(R.string.audio_general_reportlogtest));
+        } else  if (hasPassed) {
             mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_pass));
         } else if (!mClaimsMIDI) {
             mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_midinotreported));
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralNotificationsTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralNotificationsTest.java
index bc23048..6270a5a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralNotificationsTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralNotificationsTest.java
@@ -20,23 +20,17 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-
 import android.media.AudioDeviceCallback;
 import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
-
 import android.os.Bundle;
 import android.os.Handler;
-
 import android.util.Log;
-
 import android.widget.TextView;
 
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.ReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
-
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;  // needed to access resource in CTSVerifier project namespace.
 
@@ -173,9 +167,10 @@
     // Test Status
     //
     private boolean calculatePass() {
-        return mUsbHeadsetInReceived && mUsbHeadsetOutReceived &&
-                mUsbDeviceInReceived && mUsbDeviceOutReceived &&
-                mPlugIntentReceived;
+        return isReportLogOkToPass()
+                && mUsbHeadsetInReceived && mUsbHeadsetOutReceived
+                && mUsbDeviceInReceived && mUsbDeviceOutReceived
+                && mPlugIntentReceived;
     }
 
     //
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index 8855dc7..212f988 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -1847,6 +1847,8 @@
         // s1440p which is the max supported stream size in a combination, when preview
         // stabilization is on.
         Size maxPreviewSize = new Size(1920, 1440);
+        // QCIF, we test only sizes >= this.
+        Size minPreviewSize = new Size(176, 144);
         Size[] outputSizes = configMap.getOutputSizes(ImageFormat.YUV_420_888);
         if (outputSizes == null) {
             mSocketRunnableObj.sendResponse("supportedPreviewSizes", "");
@@ -1857,6 +1859,8 @@
                 .distinct()
                 .filter(s -> s.getWidth() * s.getHeight()
                         <= maxPreviewSize.getWidth() * maxPreviewSize.getHeight())
+                .filter(s -> s.getWidth() * s.getHeight()
+                        >= minPreviewSize.getWidth() * minPreviewSize.getHeight())
                 .sorted(Comparator.comparingInt(s -> s.getWidth() * s.getHeight()))
                 .map(Size::toString)
                 .collect(Collectors.joining(";"));
@@ -2985,6 +2989,8 @@
                                                   CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED ||
                                        result.get(CaptureResult.CONTROL_AE_STATE) ==
                                                   CaptureResult.CONTROL_AE_STATE_LOCKED;
+                        mLockedAE = result.get(CaptureResult.CONTROL_AE_STATE) ==
+                                CaptureResult.CONTROL_AE_STATE_LOCKED;
                         if (!mPrecaptureTriggered) {
                             mPrecaptureTriggered = result.get(CaptureResult.CONTROL_AE_STATE) ==
                                     CaptureResult.CONTROL_AE_STATE_PRECAPTURE;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
index d83464b..692538a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
@@ -21,9 +21,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Configuration;
-import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraManager;
-import android.os.Build;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.os.Bundle;
 import android.text.method.ScrollingMovementMethod;
 import android.util.Log;
@@ -31,6 +30,11 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
@@ -39,17 +43,11 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
 import com.android.cts.verifier.ArrayTestListAdapter;
@@ -59,6 +57,7 @@
 
 import org.json.JSONArray;
 import org.json.JSONObject;
+import org.junit.rules.TestName;
 
 /**
  * Test for Camera features that require that the camera be aimed at a specific test scene.
@@ -81,12 +80,6 @@
             Arrays.asList(new String[] {RESULT_PASS, RESULT_FAIL, RESULT_NOT_EXECUTED}));
     private static final int MAX_SUMMARY_LEN = 200;
 
-    private static final int MPC12_CAMERA_LAUNCH_THRESHOLD = 600; // ms
-    private static final int MPC12_JPEG_CAPTURE_THRESHOLD = 1000; // ms
-
-    private static final String MPC_TESTS_REPORT_LOG_NAME = "MediaPerformanceClassLogs";
-    private static final String MPC_TESTS_REPORT_LOG_SECTION = "CameraIts";
-
     private static final Pattern MPC12_CAMERA_LAUNCH_PATTERN =
             Pattern.compile("camera_launch_time_ms:(\\d+(\\.\\d+)?)");
     private static final Pattern MPC12_JPEG_CAPTURE_PATTERN =
@@ -95,8 +88,12 @@
     private final ResultReceiver mResultsReceiver = new ResultReceiver();
     private boolean mReceiverRegistered = false;
 
+    public final TestName mTestName = new TestName();
+
     // Initialized in onCreate
     List<String> mToBeTestedCameraIds = null;
+    String mPrimaryRearCameraId = null;
+    String mPrimaryFrontCameraId = null;
 
     // Scenes
     private static final ArrayList<String> mSceneIds = new ArrayList<String> () {{
@@ -132,8 +129,15 @@
     private final HashMap<ResultKey, String> mSummaryMap = new HashMap<>();
     // All primary cameras for which MPC level test has run
     private Set<ResultKey> mExecutedMpcTests = null;
-    // Map primary camera id to MPC level
-    private final HashMap<String, Integer> mMpcLevelMap = new HashMap<>();
+    private static final String MPC_LAUNCH_REQ_NUM = "2.2.7.2/7.5/H-1-6";
+    private static final String MPC_JPEG_CAPTURE_REQ_NUM = "2.2.7.2/7.5/H-1-5";
+    // Performance class evaluator used for writing test result
+    PerformanceClassEvaluator mPce = new PerformanceClassEvaluator(mTestName);
+    PerformanceClassEvaluator.CameraLatencyRequirement mJpegLatencyReq =
+            mPce.addR7_5__H_1_5();
+    PerformanceClassEvaluator.CameraLatencyRequirement mLaunchLatencyReq =
+            mPce.addR7_5__H_1_6();
+
 
     final class ResultKey {
         public final String cameraId;
@@ -266,10 +270,7 @@
                         JSONArray metrics = sceneResult.getJSONArray("mpc_metrics");
                         for (int i = 0; i < metrics.length(); i++) {
                             String mpcResult = metrics.getString(i);
-                            if (!matchMpcResult(cameraId, mpcResult, MPC12_CAMERA_LAUNCH_PATTERN,
-                                    "2.2.7.2/7.5/H-1-6", MPC12_CAMERA_LAUNCH_THRESHOLD) &&
-                                    !matchMpcResult(cameraId, mpcResult, MPC12_JPEG_CAPTURE_PATTERN,
-                                    "2.2.7.2/7.5/H-1-5", MPC12_JPEG_CAPTURE_THRESHOLD)) {
+                            if (!matchMpcResult(cameraId, mpcResult)) {
                                 Log.e(TAG, "Error parsing MPC result string:" + mpcResult);
                                 return;
                             }
@@ -294,17 +295,6 @@
                             summary.toString(), 1.0, ResultType.NEUTRAL, ResultUnit.NONE);
                 }
 
-                //  Save MPC info once both front primary and rear primary data are collected.
-                if (mExecutedMpcTests.size() == 4) {
-                    ItsTestActivity.this.getReportLog().addValue(
-                            "Version", "0.0.1", ResultType.NEUTRAL, ResultUnit.NONE);
-                    for (Map.Entry<String, Integer> entry : mMpcLevelMap.entrySet()) {
-                        ItsTestActivity.this.getReportLog().addValue(entry.getKey(),
-                                entry.getValue(), ResultType.NEUTRAL, ResultUnit.NONE);
-                    }
-                    ItsTestActivity.this.getReportLog().submit();
-                }
-
                 // Display current progress
                 StringBuilder progress = new StringBuilder();
                 for (ResultKey k : mAllScenes) {
@@ -367,28 +357,44 @@
             }
         }
 
-        private boolean matchMpcResult(String cameraId, String mpcResult, Pattern pattern,
-                String reqNum, float threshold) {
-            Matcher matcher = pattern.matcher(mpcResult);
-            boolean match = matcher.matches();
-            final int LATEST_MPC_LEVEL = Build.VERSION_CODES.TIRAMISU;
+        private boolean matchMpcResult(String cameraId, String mpcResult) {
+            Matcher launchMatcher = MPC12_CAMERA_LAUNCH_PATTERN.matcher(mpcResult);
+            boolean launchMatches = launchMatcher.matches();
 
-            if (match) {
-                // Store test result
-                ItsTestActivity.this.getReportLog().addValue("Cam" + cameraId,
-                        mpcResult, ResultType.NEUTRAL, ResultUnit.NONE);
+            Matcher jpegMatcher = MPC12_JPEG_CAPTURE_PATTERN.matcher(mpcResult);
+            boolean jpegMatches = jpegMatcher.matches();
 
-                float latency = Float.parseFloat(matcher.group(1));
-                int mpcLevel = latency < threshold ? LATEST_MPC_LEVEL : 0;
-                mExecutedMpcTests.add(new ResultKey(cameraId, reqNum));
-
-                if (mMpcLevelMap.containsKey(reqNum)) {
-                    mpcLevel = Math.min(mpcLevel, mMpcLevelMap.get(reqNum));
-                }
-                mMpcLevelMap.put(reqNum, mpcLevel);
+            if (!launchMatches && !jpegMatches) {
+                return false;
+            }
+            if (!cameraId.equals(mPrimaryRearCameraId) &&
+                    !cameraId.equals(mPrimaryFrontCameraId)) {
+                return false;
             }
 
-            return match;
+            if (launchMatches) {
+                float latency = Float.parseFloat(launchMatcher.group(1));
+                if (cameraId.equals(mPrimaryRearCameraId)) {
+                    mLaunchLatencyReq.setRearCameraLatency(latency);
+                } else {
+                    mLaunchLatencyReq.setFrontCameraLatency(latency);
+                }
+                mExecutedMpcTests.add(new ResultKey(cameraId, MPC_LAUNCH_REQ_NUM));
+            } else {
+                float latency = Float.parseFloat(jpegMatcher.group(1));
+                if (cameraId.equals(mPrimaryRearCameraId)) {
+                    mJpegLatencyReq.setRearCameraLatency(latency);
+                } else {
+                    mJpegLatencyReq.setFrontCameraLatency(latency);
+                }
+                mExecutedMpcTests.add(new ResultKey(cameraId, MPC_JPEG_CAPTURE_REQ_NUM));
+            }
+
+            // Save MPC info once both front primary and rear primary data are collected.
+            if (mExecutedMpcTests.size() == 4) {
+                mPce.submit();
+            }
+            return true;
         }
     }
 
@@ -397,8 +403,11 @@
         // Hide the test if all camera devices are legacy
         CameraManager manager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
         try {
-            ItsUtils.ItsCameraIdList cameraIdList = ItsUtils.getItsCompatibleCameraIds(manager);
+            ItsUtils.ItsCameraIdList cameraIdList =
+                    ItsUtils.getItsCompatibleCameraIds(manager);
             mToBeTestedCameraIds = cameraIdList.mCameraIdCombos;
+            mPrimaryRearCameraId = cameraIdList.mPrimaryRearCameraId;
+            mPrimaryFrontCameraId = cameraIdList.mPrimaryFrontCameraId;
         } catch (ItsException e) {
             Toast.makeText(ItsTestActivity.this,
                     "Received error from camera service while checking device capabilities: "
@@ -499,14 +508,4 @@
         setInfoResources(R.string.camera_its_test, R.string.camera_its_test_info, -1);
         setPassFailButtonClickListeners();
     }
-
-    @Override
-    public String getReportFileName() {
-        return MPC_TESTS_REPORT_LOG_NAME;
-    }
-
-    @Override
-    public String getReportSectionName() {
-        return MPC_TESTS_REPORT_LOG_SECTION;
-    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
index c648e8e..734b4a2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
@@ -16,28 +16,24 @@
 
 package com.android.cts.verifier.camera.its;
 
-import android.content.Context;
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.media.Image;
 import android.media.Image.Plane;
-import android.net.Uri;
-import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.util.Log;
 import android.util.Size;
 
 import com.android.ex.camera2.blocking.BlockingCameraManager;
-import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException;
 import com.android.ex.camera2.blocking.BlockingStateCallback;
 
 import org.json.JSONArray;
@@ -322,6 +318,9 @@
         // Camera Id combos (ids from CameraIdList, and hidden physical camera Ids
         // in the form of [logical camera id]:[hidden physical camera id]
         public List<String> mCameraIdCombos;
+        // Primary rear and front camera Ids (as defined in MPC)
+        public String mPrimaryRearCameraId;
+        public String mPrimaryFrontCameraId;
     }
 
     public static ItsCameraIdList getItsCompatibleCameraIds(CameraManager manager)
@@ -345,6 +344,18 @@
                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE;
                 final int LOGICAL_MULTI_CAMERA =
                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA;
+
+                final Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
+                if (facing != null) {
+                    if (facing == CameraMetadata.LENS_FACING_BACK
+                            && outList.mPrimaryRearCameraId == null) {
+                        outList.mPrimaryRearCameraId = id;
+                    } else if (facing == CameraMetadata.LENS_FACING_FRONT
+                            && outList.mPrimaryFrontCameraId == null) {
+                        outList.mPrimaryFrontCameraId = id;
+                    }
+                }
+
                 for (int capability : actualCapabilities) {
                     if (capability == BACKWARD_COMPAT) {
                         haveBC = true;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/ClipboardPreviewTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/ClipboardPreviewTestActivity.java
index 3587e6f..63b8904 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/ClipboardPreviewTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/ClipboardPreviewTestActivity.java
@@ -18,49 +18,22 @@
 
 
 import android.content.ClipData;
+import android.content.ClipDescription;
 import android.content.ClipboardManager;
-import android.graphics.Color;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.view.View;
 import android.widget.Button;
 
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 
-import java.util.concurrent.ThreadLocalRandom;
-
 
 /**
- * A CTS Verifier test case for validating the user-visible clipboard preview.
- *
- * This test assumes bluetooth is turned on and the device is already paired with a second device.
- * Note: the second device need not be an Android device; it could be a laptop or desktop.
+ * A CTS Verifier test case for validating the user-visible clipboard confirmation.
  */
 public class ClipboardPreviewTestActivity extends PassFailButtons.Activity {
 
-    /**
-     * The content of the test file being transferred.
-     */
-    private static final String TEST_STRING = "Sample Test String";
-    /**
-     * The name of the test file being transferred.
-     */
-    private final int[] mSecretCode = new int[4];
-    private final int[] mSecretGuess = new int[4];
-    private final int[] mButtons = {
-            R.id.clipboard_preview_test_b0,
-            R.id.clipboard_preview_test_b1,
-            R.id.clipboard_preview_test_b2,
-            R.id.clipboard_preview_test_b3,
-            R.id.clipboard_preview_test_b4,
-            R.id.clipboard_preview_test_b5,
-            R.id.clipboard_preview_test_b6,
-            R.id.clipboard_preview_test_b7,
-            R.id.clipboard_preview_test_b8,
-            R.id.clipboard_preview_test_b9
-    };
-    private int mGuessIndex = 0;
-
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -74,87 +47,29 @@
         copyButton.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                generateAndCopySecret();
+                setClipboardData();
             }
         });
-        disableKeypad();
+        disablePassFail();
     }
 
-    private void generateAndCopySecret() {
-        String s = "";
-        resetState();
-        for (int i = 0; i < mSecretCode.length; ++i) {
-            mSecretCode[i] = ThreadLocalRandom.current().nextInt(0, 10);
-            s += mSecretCode[i];
-        }
+    private void setClipboardData() {
         ClipboardManager cm = this.getSystemService(ClipboardManager.class);
-        cm.setPrimaryClip(ClipData.newPlainText("Secret", s));
-        enableKeypad();
+
+        ClipData cd = ClipData.newPlainText("",
+                getString(R.string.clipboard_preview_test_secret));
+        PersistableBundle pb = new PersistableBundle(1);
+        pb.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
+        cd.getDescription().setExtras(pb);
+        cm.setPrimaryClip(cd);
+        enablePassFail();
     }
 
-    private void enableKeypad() {
-        for (int i = 0; i < mButtons.length; ++i) {
-            Button numButton = findViewById(mButtons[i]);
-            numButton.setBackgroundColor(Color.GREEN);
-            int finalI = i;
-            numButton.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    buttonClicked(finalI);
-                }
-            });
-        }
-    }
-
-    private void disableKeypad() {
-        for (int i = 0; i < mButtons.length; ++i) {
-            Button numButton = findViewById(mButtons[i]);
-            numButton.setOnClickListener(null);
-            numButton.setBackgroundColor(Color.LTGRAY);
-        }
-    }
-
-    private void resetState() {
-        for (int i = 0; i < mSecretGuess.length; ++i) {
-            mSecretGuess[i] = -1;
-        }
-        mGuessIndex = 0;
-        View v = findViewById(R.id.clipboard_preview_test_pass_fail);
+    private void disablePassFail() {
         findViewById(R.id.clipboard_preview_test_pass_fail).setVisibility(View.INVISIBLE);
-        findViewById(R.id.fail_button).setVisibility(View.VISIBLE);
-        findViewById(R.id.pass_button).setVisibility(View.VISIBLE);
     }
 
-    private void buttonClicked(int i) {
-        if (mGuessIndex < mSecretGuess.length) {
-            mSecretGuess[mGuessIndex] = i;
-            ++mGuessIndex;
-        }
-        checkSolution();
-    }
-
-    private void checkSolution() {
-        boolean testPassed = true;
-        if (mGuessIndex == mSecretGuess.length) {
-            for (int i = 0; i < mSecretGuess.length && i < mSecretCode.length; ++i) {
-                if (mSecretGuess[i] != mSecretCode[i]) {
-                    testPassed = false;
-                }
-            }
-            markPassed(testPassed);
-            disableKeypad();
-        }
-    }
-
-    private void markPassed(boolean passed) {
+    private void enablePassFail() {
         findViewById(R.id.clipboard_preview_test_pass_fail).setVisibility(View.VISIBLE);
-        if (passed) {
-            findViewById(R.id.fail_button).setVisibility(View.INVISIBLE);
-        } else {
-            findViewById(R.id.pass_button).setVisibility(View.INVISIBLE);
-        }
-
     }
-
-
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java
index b8b9602..97ec07a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java
@@ -118,7 +118,7 @@
 
     /** Stop observing to associated device and then disassociate. */
     private void disassociate(AssociationInfo association) {
-        String deviceAddress = association.getDeviceMacAddressAsString();
+        String deviceAddress = association.getDeviceMacAddress().toString();
         mCompanionDeviceManager.stopObservingDevicePresence(deviceAddress);
         mCompanionDeviceManager.disassociate(association.getId());
         Log.d(LOG_TAG, "Disassociated with device: " + deviceAddress);
@@ -142,11 +142,14 @@
             AssociationInfo association =
                     data.getParcelableExtra(CompanionDeviceManager.EXTRA_ASSOCIATION,
                     AssociationInfo.class);
-            String deviceAddress = association.getDeviceMacAddressAsString();
 
             // This test is for bluetooth devices, which should all have a MAC address.
-            if (deviceAddress == null) fail("The device was present but its address was null.");
+            if (association == null || association.getDeviceMacAddress() == null) {
+                fail("The device was present but its address was null.");
+                return;
+            }
 
+            String deviceAddress = association.getDeviceMacAddress().toString();
             mCompanionDeviceManager.startObservingDevicePresence(deviceAddress);
             mCurrentAssociation = getAssociation(association.getId());
             Log.d(LOG_TAG, "Associated with device: " + deviceAddress);
@@ -285,7 +288,9 @@
         @Override
         boolean verify() {
             // Check that it is associated and being observed.
-            return mCurrentAssociation != null && mCurrentAssociation.isNotifyOnDeviceNearby();
+            // Bypass inaccessible AssociationInfo#isNotifyOnDeviceNearby() with toString()
+            return mCurrentAssociation != null
+                    && mCurrentAssociation.toString().contains("mNotifyOnDeviceNearby=true");
         }
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java
index 37760d5..11829c3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java
@@ -45,7 +45,7 @@
     @Override
     public void onDeviceAppeared(AssociationInfo association) {
         NEARBY_DEVICES.add(association.getId());
-        String message = "Device appeared: " + association.getDeviceMacAddressAsString();
+        String message = "Device appeared: " + association.getDeviceMacAddress();
         Log.d(LOG_TAG, message);
         Toast.makeText(this, message, Toast.LENGTH_LONG).show();
     }
@@ -53,7 +53,7 @@
     @Override
     public void onDeviceDisappeared(AssociationInfo association) {
         NEARBY_DEVICES.remove(association.getId());
-        String message = "Device disappeared: " + association.getDeviceMacAddressAsString();
+        String message = "Device disappeared: " + association.getDeviceMacAddress();
         Log.d(LOG_TAG, message);
         Toast.makeText(this, message, Toast.LENGTH_LONG).show();
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
index ff12bd2..171d612 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
@@ -54,15 +54,18 @@
      */
     private static final String TAG = "ReadLogsTestActivity";
 
-    private static final String PERMISSION = "android.permission.READ_LOGS";
-
-    private static final String ALLOW_LOGD_ACCESS = "Allow logd access";
-    private static final String DENY_LOGD_ACCESS = "Decline logd access";
     private static final String SYSTEM_LOG_START = "--------- beginning of system";
 
     private static final int NUM_OF_LINES_FG = 10;
     private static final int NUM_OF_LINES_BG = 0;
-    private static final int LOG_ACCESS_INTERVAL = 1000 * 60 * 2;
+    private static final int LOG_ACCESS_INTERVAL_MILLIS = 1000 * 60 * 2;
+
+    private static final List<String> LOG_CAT_TEST_COMMAND = Arrays.asList("logcat",
+            "-b", "system",
+            "-v", "uid",
+            "-v", "process",
+            "-t", Integer.toString(NUM_OF_LINES_FG));
+
     private volatile long mLastLogAccess = 0;
 
     private static Context sContext;
@@ -71,11 +74,14 @@
     private static String sAppPackageName;
     private static ExecutorService sExecutorService;
 
+    private static String sLogCatUidFilterRegex;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         sContext = this;
+        sLogCatUidFilterRegex = "^[A-Z]{1}\\(\\s" + sContext.getApplicationInfo().uid;
         sActivityManager = sContext.getSystemService(ActivityManager.class);
         sExecutorService = Executors.newSingleThreadExecutor();
 
@@ -114,72 +120,70 @@
     public void runLogcatInForegroundAllowOnlyOnce() {
         Log.d(TAG, "Inside runLogcatInForegroundAllowOnlyOnce()");
 
-        if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL)) {
+        if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL_MILLIS)) {
             String reason = "Please wait for "
-                    + ((mLastLogAccess + LOG_ACCESS_INTERVAL - SystemClock.elapsedRealtime())
+                    + ((mLastLogAccess + LOG_ACCESS_INTERVAL_MILLIS - SystemClock.elapsedRealtime())
                     / 1000) + " seconds before running the test.";
             Toast.makeText(this, reason, Toast.LENGTH_LONG).show();
             return;
         }
 
-        sExecutorService.execute(new Runnable() {
+        sExecutorService.execute(() ->  {
+            BufferedReader reader = null;
+            try {
 
-            public void run() {
-                BufferedReader reader = null;
+                // Dump the logcat most recent 10 lines before the compile command,
+                // and check if there are logs about compiling the test package.
+                Process logcat = new ProcessBuilder(LOG_CAT_TEST_COMMAND).start();
+                reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
+                logcat.waitFor();
+
+                List<String> logcatOutput = new ArrayList<>();
+                String current;
+                Integer lineCount = 0;
+                while ((current = reader.readLine()) != null) {
+                    logcatOutput.add(current);
+                    lineCount++;
+                }
+
+                Log.d(TAG, "Logcat system allow line count: " + lineCount);
+                Log.d(TAG, "Logcat system allow output: " + logcatOutput);
+
                 try {
+                    assertTrue("System log output is null", logcatOutput.size() != 0);
 
-                    // Dump the logcat most recent 10 lines before the compile command,
-                    // and check if there are logs about compiling the test package.
-                    java.lang.Process logcat = new ProcessBuilder(
-                            Arrays.asList("logcat", "-b", "system", "-t",
-                                    Integer.toString(NUM_OF_LINES_FG))).start();
-                    reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
-                    logcat.waitFor();
+                    // Check if the logcatOutput is not null. If logcatOutput is null,
+                    // it throws an assertion error
+                    assertNotNull(logcatOutput.get(0), "logcat output should not be null");
 
-                    List<String> logcatOutput = new ArrayList<>();
-                    String current;
-                    Integer lineCount = 0;
-                    while ((current = reader.readLine()) != null) {
-                        logcatOutput.add(current);
-                        lineCount++;
+                    boolean allowLog = logcatOutput.get(0).contains(SYSTEM_LOG_START);
+                    assertTrue("Allow system log access contains log", allowLog);
+
+                    boolean allowLineCount = lineCount > NUM_OF_LINES_FG;
+                    assertTrue("Allow system log access count", allowLineCount);
+
+                    Log.d(TAG, "Logcat system allow log contains: " + allowLog + " lineCount: "
+                            + lineCount + " larger than: " + allowLineCount);
+
+                    mLastLogAccess = SystemClock.elapsedRealtime();
+
+                    runOnUiThread(() ->
+                            Toast.makeText(this, "User Consent Allow Testing passed",
+                                    Toast.LENGTH_LONG).show());
+
+                } catch (AssertionError e) {
+                    fail("User Consent Allow Testing failed");
+                }
+
+            } catch (Exception e) {
+                Log.e(TAG, "User Consent Testing failed");
+            } finally {
+                try {
+                    if (reader != null) {
+                        reader.close();
                     }
-
-                    Log.d(TAG, "Logcat system allow line count: " + lineCount);
-                    Log.d(TAG, "Logcat system allow output: " + logcatOutput);
-
-                    try {
-
-                        assertTrue("System log output is null", logcatOutput.size() != 0);
-
-                        // Check if the logcatOutput is not null. If logcatOutput is null,
-                        // it throws an assertion error
-                        assertNotNull(logcatOutput.get(0), "logcat output should not be null");
-
-                        boolean allowLog = logcatOutput.get(0).contains(SYSTEM_LOG_START);
-                        assertTrue("Allow system log access containe log", allowLog);
-
-                        boolean allowLineCount = lineCount > NUM_OF_LINES_FG;
-                        assertTrue("Allow system log access count", allowLineCount);
-
-                        Log.d(TAG, "Logcat system allow log contains: " + allowLog + " lineCount: "
-                                + lineCount + " larger than: " + allowLineCount);
-
-                        mLastLogAccess = SystemClock.elapsedRealtime();
-
-                    } catch (AssertionError e) {
-                        fail("User Consent Allow Testing failed");
-                    }
-
-                } catch (Exception e) {
-                    Log.e(TAG, "User Consent Testing failed");
-                } finally {
-                    try {
-                        if (reader != null) {
-                            reader.close();
-                        }
-                    } catch (IOException e) {
-                        Log.d(TAG, "Could not close reader: " + e.getMessage());
-                    }
+                } catch (IOException e) {
+                    Log.d(TAG, "Could not close reader: " + e.getMessage());
                 }
             }
         });
@@ -199,56 +203,53 @@
     public void runLogcatInForegroundDontAllow() {
         Log.d(TAG, "Inside runLogcatInForegroundDontAllow()");
 
-        if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL)) {
+        if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL_MILLIS)) {
             String reason = "Please wait for "
-                    + ((mLastLogAccess + LOG_ACCESS_INTERVAL - SystemClock.elapsedRealtime())
+                    + ((mLastLogAccess + LOG_ACCESS_INTERVAL_MILLIS - SystemClock.elapsedRealtime())
                     / 1000) + " seconds before running the test.";
             Toast.makeText(this, reason, Toast.LENGTH_LONG).show();
             return;
         }
 
-        sExecutorService.execute(new Runnable() {
+        sExecutorService.execute(() -> {
+            BufferedReader reader = null;
+            try {
+                Process logcat = new ProcessBuilder(LOG_CAT_TEST_COMMAND).start();
+                logcat.waitFor();
 
-            public void run() {
-                BufferedReader reader = null;
+                // Merge several logcat streams, and take the last N lines
+                reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
+                assertNotNull(reader);
+
+                String current;
+                int lineCount = 0;
+                while ((current = reader.readLine()) != null
+                        && current.matches(sLogCatUidFilterRegex)) {
+                    lineCount++;
+                }
+
+                Log.d(TAG, "Logcat system deny line count:" + lineCount);
+
+                mLastLogAccess = SystemClock.elapsedRealtime();
+
                 try {
-                    java.lang.Process logcat = new ProcessBuilder(
-                            Arrays.asList("logcat", "-b", "system", "-t",
-                                    Integer.toString(NUM_OF_LINES_FG))).start();
-                    logcat.waitFor();
+                    assertTrue("Deny System log access", lineCount == NUM_OF_LINES_BG);
 
-                    // Merge several logcat streams, and take the last N lines
-                    reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
-                    assertNotNull(reader);
-
-                    List<String> logcatOutput = new ArrayList<>();
-                    String current;
-                    int lineCount = 0;
-                    while ((current = reader.readLine()) != null) {
-                        logcatOutput.add(current);
-                        lineCount++;
+                    runOnUiThread(() ->
+                            Toast.makeText(this, "User Consent Deny Testing passed",
+                                    Toast.LENGTH_LONG).show());
+                } catch (AssertionError e) {
+                    fail("User Consent Deny Testing failed");
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "User Consent Testing failed");
+            } finally {
+                try {
+                    if (reader != null) {
+                        reader.close();
                     }
-
-                    Log.d(TAG, "Logcat system deny line count:" + lineCount);
-
-                    mLastLogAccess = SystemClock.elapsedRealtime();
-
-                    try {
-                        assertTrue("Deny System log access", lineCount == NUM_OF_LINES_BG);
-                    } catch (AssertionError e) {
-                        fail("User Consent Deny Testing failed");
-                    }
-
-                } catch (Exception e) {
-                    Log.e(TAG, "User Consent Testing failed");
-                } finally {
-                    try {
-                        if (reader != null) {
-                            reader.close();
-                        }
-                    } catch (IOException e) {
-                        Log.d(TAG, "Could not close reader: " + e.getMessage());
-                    }
+                } catch (IOException e) {
+                    Log.d(TAG, "Could not close reader: " + e.getMessage());
                 }
             }
         });
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRssiPrecisionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRssiPrecisionActivity.java
deleted file mode 100644
index 1548910..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRssiPrecisionActivity.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.presence;
-
-import android.app.AlertDialog;
-import android.bluetooth.BluetoothAdapter;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-/** Tests the precision of the device's RSSI measurement wtfdelet */
-public class BleRssiPrecisionActivity extends PassFailButtons.Activity {
-    private static final String TAG = BleRssiPrecisionActivity.class.getName();
-
-    // Report log schema
-    private static final String KEY_RSSI_RANGE_DBM = "rssi_range_dbm";
-    private static final String KEY_REFERENCE_DEVICE = "reference_device";
-
-    // Thresholds
-    private static final int MAX_RSSI_RANGE_DBM = 18;
-
-    private EditText reportRssiRangeEditText;
-    private EditText reportReferenceDeviceEditText;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.ble_rssi_precision);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        reportRssiRangeEditText = findViewById(R.id.report_rssi_range);
-        reportReferenceDeviceEditText = findViewById(R.id.report_reference_device);
-
-        DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
-                PackageManager.FEATURE_BLUETOOTH_LE);
-
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
-        if (!adapter.isEnabled()) {
-            new AlertDialog.Builder(this)
-                    .setTitle(R.string.ble_bluetooth_disable_title)
-                    .setMessage(R.string.ble_bluetooth_disable_message)
-                    .setOnCancelListener(dialog -> finish())
-                    .create().show();
-        }
-
-        reportRssiRangeEditText.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        reportReferenceDeviceEditText.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-    }
-
-    private void checkTestInputs() {
-        getPassButton().setEnabled(checkDistanceRangeInput() && checkReferenceDeviceInput());
-    }
-
-    private boolean checkDistanceRangeInput() {
-        String rssiRangeInput = reportRssiRangeEditText.getText().toString();
-
-        if (!rssiRangeInput.isEmpty()) {
-            int rssiRange = Integer.parseInt(rssiRangeInput);
-            // RSSI range must be inputted and within acceptable range before test can be passed
-            return rssiRange <= MAX_RSSI_RANGE_DBM;
-        }
-        return false;
-    }
-
-    private boolean checkReferenceDeviceInput() {
-        // Reference device must be inputted before test can be passed
-        return !reportReferenceDeviceEditText.getText().toString().isEmpty();
-    }
-
-    @Override
-    public void recordTestResults() {
-        String rssiRange = reportRssiRangeEditText.getText().toString();
-        String referenceDevice = reportReferenceDeviceEditText.getText().toString();
-
-        if (!rssiRange.isEmpty()) {
-            Log.i(TAG, "BLE RSSI Range (dBm): " + rssiRange);
-            getReportLog().addValue(KEY_RSSI_RANGE_DBM, Integer.parseInt(rssiRange),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!referenceDevice.isEmpty()) {
-            Log.i(TAG, "BLE Reference Device: " + referenceDevice);
-            getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-        getReportLog().submit();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRxTxCalibrationActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRxTxCalibrationActivity.java
deleted file mode 100644
index 2de7edf..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRxTxCalibrationActivity.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.presence;
-
-import android.app.AlertDialog;
-import android.bluetooth.BluetoothAdapter;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-/**
- * Tests that the device's Rx/Tx calibration results in a median range (cm) within the specified
- * bounds
- */
-public class BleRxTxCalibrationActivity extends PassFailButtons.Activity {
-    private static final String TAG = BleRxTxCalibrationActivity.class.getName();
-
-    // Report log schema
-    private static final String KEY_CHANNEL_RSSI_RANGE = "channel_rssi_range";
-    private static final String KEY_CORE_RSSI_RANGE = "core_rssi_range";
-    private static final String KEY_REFERENCE_DEVICE = "reference_device";
-
-    // Thresholds
-    private static final int MAX_RSSI_RANGE = 6;
-
-    private EditText reportChannelsRssiRangeEditText;
-    private EditText reportCoresRssiRangeEditText;
-    private EditText reportReferenceDeviceEditText;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.ble_rx_tx_calibration);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        reportChannelsRssiRangeEditText = findViewById(R.id.report_channels_rssi_range);
-        reportCoresRssiRangeEditText = findViewById(R.id.report_cores_rssi_range);
-        reportReferenceDeviceEditText = findViewById(R.id.report_reference_device);
-
-        DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
-                PackageManager.FEATURE_BLUETOOTH_LE);
-
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
-        if (!adapter.isEnabled()) {
-            new AlertDialog.Builder(this)
-                    .setTitle(R.string.ble_bluetooth_disable_title)
-                    .setMessage(R.string.ble_bluetooth_disable_message)
-                    .setOnCancelListener(dialog -> finish())
-                    .create().show();
-        }
-
-        reportChannelsRssiRangeEditText.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        reportCoresRssiRangeEditText.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        reportReferenceDeviceEditText.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-    }
-
-    private void checkTestInputs() {
-        getPassButton().setEnabled(
-                checkChannelRssiInput() && checkCoreRssiInput() && checkReferenceDeviceInput());
-    }
-
-    private boolean checkChannelRssiInput() {
-        String channelsRssiRangeInput = reportChannelsRssiRangeEditText.getText().toString();
-        if (!channelsRssiRangeInput.isEmpty()) {
-            int channelsRssiRange = Integer.parseInt(channelsRssiRangeInput);
-            // RSSI range must be inputted and within acceptable range before test can be passed
-            return channelsRssiRange <= MAX_RSSI_RANGE;
-        }
-        return false;
-    }
-
-    private boolean checkCoreRssiInput() {
-        String coresRssiRangeInput = reportCoresRssiRangeEditText.getText().toString();
-        if (!coresRssiRangeInput.isEmpty()) {
-            int coresRssiRange = Integer.parseInt(coresRssiRangeInput);
-            // RSSI range must be inputted and within acceptable range before test can be passed
-            return coresRssiRange <= MAX_RSSI_RANGE;
-        }
-        // This field is optional, so return true even if the user has not inputted anything
-        return true;
-    }
-
-    private boolean checkReferenceDeviceInput() {
-        // Reference device must be inputted before test can be passed
-        return !reportReferenceDeviceEditText.getText().toString().isEmpty();
-    }
-
-    @Override
-    public void recordTestResults() {
-        String channelRssiRange = reportChannelsRssiRangeEditText.getText().toString();
-        String coreRssiRange = reportCoresRssiRangeEditText.getText().toString();
-        String referenceDevice = reportReferenceDeviceEditText.getText().toString();
-
-        if (!channelRssiRange.isEmpty()) {
-            Log.i(TAG, "BLE RSSI Range Across Channels (dBm): " + channelRssiRange);
-            getReportLog().addValue(KEY_CHANNEL_RSSI_RANGE, Integer.parseInt(channelRssiRange),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!coreRssiRange.isEmpty()) {
-            Log.i(TAG, "BLE RSSI Range Across Cores (dBm): " + coreRssiRange);
-            getReportLog().addValue(KEY_CORE_RSSI_RANGE, Integer.parseInt(coreRssiRange),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!referenceDevice.isEmpty()) {
-            Log.i(TAG, "BLE Reference Device: " + referenceDevice);
-            getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        getReportLog().submit();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/DeviceFeatureChecker.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/DeviceFeatureChecker.java
deleted file mode 100644
index 256fe3a..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/DeviceFeatureChecker.java
+++ /dev/null
@@ -1,44 +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 com.android.cts.verifier.presence;
-import android.app.Activity;
-import android.content.Context;
-import android.util.Log;
-import android.view.View;
-import android.widget.Toast;
-
-/**
- * Checks if a device supports a hardware feature needed for a test, and passes the test
- * automatically otherwise.
- */
-public class DeviceFeatureChecker {
-
-    /** Checks if a feature is supported.
-     *
-     * @param feature must be a string defined in PackageManager
-     */
-    public static void checkFeatureSupported(Context context, View passButton, String feature) {
-        if (!context.getPackageManager().hasSystemFeature(feature)) {
-            String message = String.format("Device does not support %s, automatically passing test",
-                    feature);
-            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
-            Log.e(context.getClass().getName(), message);
-            passButton.performClick();
-            Activity activity = (Activity) (context);
-            activity.finish();
-        }
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/InputTextHandler.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/InputTextHandler.java
deleted file mode 100644
index 2de68a5..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/InputTextHandler.java
+++ /dev/null
@@ -1,52 +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 com.android.cts.verifier.presence;
-
-import android.text.Editable;
-import android.text.TextWatcher;
-
-/**
- * Handles editable text inputted into test activities.
- */
-public class InputTextHandler {
-
-    /** Callback that is executed when text is changed. Takes modified text as input. */
-    public interface OnTextChanged {
-        void run(Editable s);
-    }
-
-    /**
-     * Generic text changed handler that will execute the provided callback when text is modified.
-     *
-     * @param callback called when text is changed, and passed the modified text
-     */
-    public static TextWatcher getOnTextChangedHandler(OnTextChanged callback) {
-        return new TextWatcher() {
-            @Override
-            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
-
-            @Override
-            public void onTextChanged(CharSequence s, int start, int before, int count) {}
-
-            @Override
-            public void afterTextChanged(Editable s) {
-                callback.run(s);
-            }
-        };
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionTestActivity.java
deleted file mode 100644
index 458d192..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionTestActivity.java
+++ /dev/null
@@ -1,271 +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 com.android.cts.verifier.presence;
-
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import com.google.common.collect.ImmutableMap;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Activity for testing that NAN measurements are within the acceptable ranges
- */
-public class NanPrecisionTestActivity extends PassFailButtons.Activity {
-    private static final String TAG = NanPrecisionTestActivity.class.getName();
-
-    // Report log schema
-    private static final String KEY_BANDWIDTH = "nan_bandwidth";
-    private static final String KEY_MEASUREMENT_RANGE_10CM_AT_68P = "measurement_range_10cm_68p";
-    private static final String KEY_MEASUREMENT_RANGE_1M_AT_68P = "measurement_range_1m_68p";
-    private static final String KEY_MEASUREMENT_RANGE_3M_AT_68p = "measurement_range_3m_68p";
-    private static final String KEY_MEASUREMENT_RANGE_5M_AT_68p = "measurement_range_5m_68p";
-    private static final String KEY_MEASUREMENT_RANGE_10CM_AT_90P = "measurement_range_10cm_90p";
-    private static final String KEY_MEASUREMENT_RANGE_1M_AT_90P = "measurement_range_1m_90p";
-    private static final String KEY_MEASUREMENT_RANGE_3M_AT_90p = "measurement_range_3m_90p";
-    private static final String KEY_MEASUREMENT_RANGE_5M_AT_90p = "measurement_range_5m_90p";
-    private static final String KEY_REFERENCE_DEVICE = "reference_device";
-
-    // Thresholds
-    private static final int MAX_DISTANCE_RANGE_METERS_160MHZ = 2;
-    private static final int MAX_DISTANCE_RANGE_METERS_80MHZ = 4;
-    private static final int MAX_DISTANCE_RANGE_METERS_40MHZ = 8;
-    private static final int MAX_DISTANCE_RANGE_METERS_20MHZ = 16;
-
-    // Maps NAN bandwidths to acceptable range thresholds
-    private static final ImmutableMap<Integer, Integer> BANDWIDTH_TO_THRESHOLD_MAP =
-            ImmutableMap.of(160, MAX_DISTANCE_RANGE_METERS_160MHZ, 80,
-                    MAX_DISTANCE_RANGE_METERS_80MHZ, 40, MAX_DISTANCE_RANGE_METERS_40MHZ, 20,
-                    MAX_DISTANCE_RANGE_METERS_20MHZ);
-
-    private EditText mBandwidthMhz;
-    private EditText mMeasurementRange10cmGt68p;
-    private EditText mMeasurementRange1mGt68p;
-    private EditText mMeasurementRange3mGt68p;
-    private EditText mMeasurementRange5mGt68p;
-    private EditText mMeasurementRange10cmGt90p;
-    private EditText mMeasurementRange1mGt90p;
-    private EditText mMeasurementRange3mGt90p;
-    private EditText mMeasurementRange5mGt90p;
-    private EditText mReferenceDeviceInput;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.nan_precision);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        mBandwidthMhz = (EditText) findViewById(R.id.nan_bandwidth);
-        mMeasurementRange10cmGt68p = (EditText) findViewById(R.id.distance_range_10cm_gt_68p);
-        mMeasurementRange1mGt68p = (EditText) findViewById(R.id.distance_range_1m_gt_68p);
-        mMeasurementRange3mGt68p = (EditText) findViewById(R.id.distance_range_3m_gt_68p);
-        mMeasurementRange5mGt68p = (EditText) findViewById(R.id.distance_range_5m_gt_68p);
-        mMeasurementRange10cmGt90p = (EditText) findViewById(R.id.distance_range_10cm_gt_90p);
-        mMeasurementRange1mGt90p = (EditText) findViewById(R.id.distance_range_1m_gt_90p);
-        mMeasurementRange3mGt90p = (EditText) findViewById(R.id.distance_range_3m_gt_90p);
-        mMeasurementRange5mGt90p = (EditText) findViewById(R.id.distance_range_5m_gt_90p);
-        mReferenceDeviceInput = (EditText) findViewById(R.id.reference_device);
-
-        DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
-                PackageManager.FEATURE_WIFI_AWARE);
-
-        mBandwidthMhz.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange10cmGt68p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange1mGt68p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange3mGt68p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange5mGt68p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange10cmGt90p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange1mGt90p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange3mGt90p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange5mGt90p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mReferenceDeviceInput.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-    }
-
-    private void checkTestInputs() {
-        getPassButton().setEnabled(checkMeasurementRange68thPercentileInput()
-                && checkMeasurementRange90thPercentileInput()
-                && checkReferenceDeviceInput());
-    }
-
-    private boolean checkMeasurementRange68thPercentileInput() {
-        return checkRequiredMeasurementRangeInput(mMeasurementRange10cmGt68p,
-                mMeasurementRange1mGt68p, mMeasurementRange3mGt68p, mMeasurementRange5mGt68p);
-    }
-
-    private boolean checkMeasurementRange90thPercentileInput() {
-        String measurementRangeInput10cmGt90p = mMeasurementRange10cmGt90p.getText().toString();
-        String measurementRangeInput1mGt90p = mMeasurementRange1mGt90p.getText().toString();
-        String measurementRangeInput3mGt90p = mMeasurementRange3mGt90p.getText().toString();
-        String measurementRangeInput5mGt90p = mMeasurementRange5mGt90p.getText().toString();
-        List<String> optionalMeasurementRangeList = Arrays.asList(measurementRangeInput10cmGt90p,
-                measurementRangeInput1mGt90p,
-                measurementRangeInput3mGt90p, measurementRangeInput5mGt90p);
-
-        boolean inputted = false;
-        for (String input : optionalMeasurementRangeList) {
-            if (!input.isEmpty()) {
-                inputted = true;
-                break;
-            }
-        }
-        // If one of the ranges is inputted for one of the distances, then it becomes required
-        // that the ranges are inputted for all the distances and for tests to pass, must be
-        // acceptable values
-        return !inputted || checkRequiredMeasurementRangeInput(mMeasurementRange10cmGt90p,
-                mMeasurementRange1mGt90p, mMeasurementRange3mGt90p, mMeasurementRange5mGt90p);
-    }
-
-    private boolean checkRequiredMeasurementRangeInput(EditText rangeInput10cm,
-            EditText rangeInput1m, EditText rangeInput3m, EditText rangeInput5m) {
-        String bandwidthInputMhz = mBandwidthMhz.getText().toString();
-        String measurementRangeInput10cmGt = rangeInput10cm.getText().toString();
-        String measurementRangeInput1mGt = rangeInput1m.getText().toString();
-        String measurementRangeInput3mGt = rangeInput3m.getText().toString();
-        String measurementRangeInput5mGt = rangeInput5m.getText().toString();
-        List<String> requiredMeasurementRangeList = Arrays.asList(measurementRangeInput10cmGt,
-                measurementRangeInput1mGt,
-                measurementRangeInput3mGt, measurementRangeInput5mGt);
-
-        for (String input : requiredMeasurementRangeList) {
-            if (bandwidthInputMhz.isEmpty() || input.isEmpty()) {
-                // Distance range must be inputted for all fields so fail early otherwise
-                return false;
-            }
-            if (!BANDWIDTH_TO_THRESHOLD_MAP.containsKey(Integer.parseInt(bandwidthInputMhz))) {
-                // bandwidth must be one of the expected thresholds
-                return false;
-            }
-            double distanceRange = Double.parseDouble(input);
-            int bandwidth = Integer.parseInt(bandwidthInputMhz);
-            if (distanceRange > BANDWIDTH_TO_THRESHOLD_MAP.get(bandwidth)) {
-                // All inputs must be in acceptable range so fail early otherwise
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private boolean checkReferenceDeviceInput() {
-        // Reference device used must be inputted before test can be passed.
-        return !mReferenceDeviceInput.getText().toString().isEmpty();
-    }
-
-    @Override
-    public void recordTestResults() {
-        String nanBandwidthMhz = mBandwidthMhz.getText().toString();
-        String measurementRange10cmGt68p = mMeasurementRange10cmGt68p.getText().toString();
-        String measurementRange1mGt68p = mMeasurementRange1mGt68p.getText().toString();
-        String measurementRange3mGt68p = mMeasurementRange3mGt68p.getText().toString();
-        String measurementRange5mGt68p = mMeasurementRange5mGt68p.getText().toString();
-        String measurementRange10cmGt90p = mMeasurementRange10cmGt90p.getText().toString();
-        String measurementRange1mGt90p = mMeasurementRange1mGt90p.getText().toString();
-        String measurementRange3mGt90p = mMeasurementRange3mGt90p.getText().toString();
-        String measurementRange5mGt90p = mMeasurementRange5mGt90p.getText().toString();
-        String referenceDevice = mReferenceDeviceInput.getText().toString();
-
-        if (!nanBandwidthMhz.isEmpty()) {
-            Log.i(TAG, "NAN Bandwidth at which data was collected: " + nanBandwidthMhz);
-            getReportLog().addValue(KEY_BANDWIDTH,
-                    Integer.parseInt(nanBandwidthMhz),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange10cmGt68p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 10cm: " + measurementRange10cmGt68p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_10CM_AT_68P,
-                    Double.parseDouble(measurementRange10cmGt68p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange1mGt68p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 1m: " + measurementRange1mGt68p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_1M_AT_68P,
-                    Double.parseDouble(measurementRange1mGt68p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange3mGt68p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 3m: " + measurementRange3mGt68p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_3M_AT_68p,
-                    Double.parseDouble(measurementRange3mGt68p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange5mGt68p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 5m: " + measurementRange5mGt68p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_5M_AT_68p,
-                    Double.parseDouble(measurementRange5mGt68p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange10cmGt90p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 10cm: " + measurementRange10cmGt68p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_10CM_AT_90P,
-                    Double.parseDouble(measurementRange10cmGt90p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange1mGt90p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 1m: " + measurementRange1mGt90p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_1M_AT_90P,
-                    Double.parseDouble(measurementRange1mGt90p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange3mGt90p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 3m: " + measurementRange3mGt90p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_3M_AT_90p,
-                    Double.parseDouble(measurementRange3mGt90p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange5mGt90p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 5m: " + measurementRange5mGt90p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_5M_AT_90p,
-                    Double.parseDouble(measurementRange5mGt90p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!referenceDevice.isEmpty()) {
-            Log.i(TAG, "NAN Reference Device: " + referenceDevice);
-            getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-        getReportLog().submit();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/presence/OWNERS
deleted file mode 100644
index e874499..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 1106357
-asalo@google.com
-jbabs@google.com
-christinatao@google.com
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/PresenceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/PresenceTestActivity.java
deleted file mode 100644
index 6776693..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/PresenceTestActivity.java
+++ /dev/null
@@ -1,60 +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 com.android.cts.verifier.presence;
-
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.SystemProperties;
-
-import com.android.cts.verifier.ManifestTestListAdapter;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class PresenceTestActivity extends PassFailButtons.TestListActivity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.pass_fail_list);
-        setPassFailButtonClickListeners();
-
-        List<String> disabledTest = new ArrayList<String>();
-        boolean isTv = getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
-        if (isTv) {
-            setInfoResources(R.string.presence_test, R.string.presence_test_tv_info, -1);
-            int firstSdk = SystemProperties.getInt("ro.product.first_api_level", 0);
-            if (firstSdk < Build.VERSION_CODES.TIRAMISU) {
-                disabledTest.add("com.android.cts.verifier.presence.UwbPrecisionActivity");
-                disabledTest.add("com.android.cts.verifier.presence.UwbShortRangeActivity");
-                disabledTest.add("com.android.cts.verifier.presence.BleRssiPrecisionActivity");
-                disabledTest.add("com.android.cts.verifier.presence.BleRxTxCalibrationActivity");
-                disabledTest.add("com.android.cts.verifier.presence.BleRxOffsetActivity");
-                disabledTest.add("com.android.cts.verifier.presence.BleTxOffsetActivity");
-                disabledTest.add("com.android.cts.verifier.presence.NanPrecisionTestActivity");
-            }
-        } else {
-            setInfoResources(R.string.presence_test, R.string.presence_test_info, -1);
-        }
-
-        setTestListAdapter(new ManifestTestListAdapter(this, PresenceTestActivity.class.getName(),
-                disabledTest.toArray(new String[disabledTest.size()])));
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbPrecisionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbPrecisionActivity.java
deleted file mode 100644
index 5d1ff86..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbPrecisionActivity.java
+++ /dev/null
@@ -1,100 +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 com.android.cts.verifier.presence;
-
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-/**
- * Activity for testing that UWB distance and angle of arrival measurements are within the right
- * range.
- */
-public class UwbPrecisionActivity extends PassFailButtons.Activity {
-    private static final String TAG = UwbPrecisionActivity.class.getName();
-    // Report log schema
-    private static final String KEY_DISTANCE_RANGE_CM = "distance_range_cm";
-    private static final String KEY_REFERENCE_DEVICE = "reference_device";
-    // Thresholds
-    private static final int MAX_DISTANCE_RANGE_CM = 30;
-
-    private EditText mDistanceRangeInput;
-    private EditText mReferenceDeviceInput;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.uwb_precision);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        mDistanceRangeInput = (EditText) findViewById(R.id.distance_range_cm);
-        mReferenceDeviceInput = (EditText) findViewById(R.id.reference_device);
-
-        DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
-                PackageManager.FEATURE_UWB);
-
-        mDistanceRangeInput.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mReferenceDeviceInput.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-    }
-
-    private void checkTestInputs() {
-        getPassButton().setEnabled(
-                checkDistanceRangeInput() && checkReferenceDeviceInput());
-    }
-
-    private boolean checkDistanceRangeInput() {
-        String distanceRangeInput = mDistanceRangeInput.getText().toString();
-        if (!distanceRangeInput.isEmpty()) {
-            double distanceRange = Double.parseDouble(distanceRangeInput);
-            // Distance range must be inputted and within acceptable range before test can be
-            // passed.
-            return distanceRange <= MAX_DISTANCE_RANGE_CM;
-        }
-        return false;
-    }
-
-    private boolean checkReferenceDeviceInput() {
-        // Reference device must be inputted before test can be passed.
-        return !mReferenceDeviceInput.getText().toString().isEmpty();
-    }
-
-    @Override
-    public void recordTestResults() {
-        String distanceRange = mDistanceRangeInput.getText().toString();
-        String referenceDevice = mReferenceDeviceInput.getText().toString();
-        if (!distanceRange.isEmpty()) {
-            Log.i(TAG, "UWB Distance Range: " + distanceRange);
-            getReportLog().addValue(KEY_DISTANCE_RANGE_CM, Double.parseDouble(distanceRange),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-        if (!referenceDevice.isEmpty()) {
-            Log.i(TAG, "UWB Reference Device: " + referenceDevice);
-            getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-        getReportLog().submit();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbShortRangeActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbShortRangeActivity.java
deleted file mode 100644
index 7f14800..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbShortRangeActivity.java
+++ /dev/null
@@ -1,95 +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 com.android.cts.verifier.presence;
-
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-/**
- * Activity for testing that UWB distance measurements are within the acceptable median.
- */
-public class UwbShortRangeActivity extends PassFailButtons.Activity {
-    private static final String TAG = UwbShortRangeActivity.class.getName();
-    // Report log schema
-    private static final String KEY_DISTANCE_MEDIAN_CM = "distance_median_cm";
-    private static final String KEY_REFERENCE_DEVICE = "reference_device";
-    // Median Thresholds
-    private static final double MIN_MEDIAN = 0.75;
-    private static final double MAX_MEDIAN = 1.25;
-    private EditText mMedianInput;
-    private EditText mReferenceDeviceInput;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.uwb_short_range);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        mMedianInput = (EditText) findViewById(R.id.distance_median_meters);
-        mReferenceDeviceInput = (EditText) findViewById(R.id.reference_device);
-
-        DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
-                PackageManager.FEATURE_UWB);
-
-        mMedianInput.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mReferenceDeviceInput.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-    }
-
-    private void checkTestInputs() {
-        getPassButton().setEnabled(checkMedianInput() && checkReferenceDeviceInput());
-    }
-
-    private boolean checkMedianInput() {
-        String medianInput = mMedianInput.getText().toString();
-        if (!medianInput.isEmpty()) {
-            double median = Double.parseDouble(medianInput);
-            return median >= MIN_MEDIAN && median <= MAX_MEDIAN;
-        }
-        return false;
-    }
-
-    private boolean checkReferenceDeviceInput() {
-        return !mReferenceDeviceInput.getText().toString().isEmpty();
-    }
-
-    @Override
-    public void recordTestResults() {
-        String medianInput = mMedianInput.getText().toString();
-        String referenceDeviceInput = mReferenceDeviceInput.getText().toString();
-        if (!medianInput.isEmpty()) {
-            Log.i(TAG, "UWB Distance Median: " + medianInput);
-            getReportLog().addValue(KEY_DISTANCE_MEDIAN_CM, Double.parseDouble(medianInput),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-        if (!referenceDeviceInput.isEmpty()) {
-            Log.i(TAG, "UWB Reference Device: " + referenceDeviceInput);
-            getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDeviceInput, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-        }
-        getReportLog().submit();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java
index 055f26f..c0df10c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java
@@ -66,9 +66,9 @@
 
     private void playVideo() {
         try {
-            mPlayer.start();
             mPlayer.prepare();
-            mPlayer.startThread();
+            mPlayer.startCodec();
+            mPlayer.play();
             mHandler.postDelayed(this::pauseStep, 5000);
         } catch(Exception e) {
             Log.d(TAG, "Could not play video", e);
@@ -95,7 +95,7 @@
 
     private void resumeStep() {
         try {
-            mPlayer.start();
+            mPlayer.resume();
             mHandler.postDelayed(this::enablePassButton, 3000);
         } catch(Exception e) {
             Log.d(TAG, "Could not resume video", e);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/OWNERS
new file mode 100644
index 0000000..4744ab8
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/OWNERS
@@ -0,0 +1,3 @@
+# Buganizer component id: 687598
+blindahl@google.com
+narcisaam@google.com
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java
index 0163c62f..c446143 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java
@@ -209,10 +209,10 @@
 
     private void playVideo() {
         try {
-            mPlayer.start();
             mPlayer.prepare();
+            mPlayer.startCodec();
             mPlayer.setLoopEnabled(true);
-            mPlayer.startThread();
+            mPlayer.play();
         } catch (Exception e) {
             Log.d(TAG, "Could not play the video.", e);
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java
index 641ab20..94ef536 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java
@@ -221,10 +221,10 @@
 
     private void playVideo() {
         try {
-            mPlayer.start();
             mPlayer.prepare();
+            mPlayer.startCodec();
             mPlayer.setLoopEnabled(true);
-            mPlayer.startThread();
+            mPlayer.play();
         } catch (Exception e) {
             Log.d(TAG, "Could not play video", e);
         }
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/RequireMultiUserSupport.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/RequireMultiUserSupport.java
new file mode 100644
index 0000000..03d21f4
--- /dev/null
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/RequireMultiUserSupport.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to indicate that a test requires multi-user support.
+ *
+ * <p>This can be enforced by using {@code DeviceState}.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+//@Experimental
+public @interface RequireMultiUserSupport {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
index b28b815a..7bd649d 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
@@ -67,6 +67,7 @@
 import com.android.bedstead.harrier.annotations.RequireFeature;
 import com.android.bedstead.harrier.annotations.RequireHeadlessSystemUserMode;
 import com.android.bedstead.harrier.annotations.RequireLowRamDevice;
+import com.android.bedstead.harrier.annotations.RequireMultiUserSupport;
 import com.android.bedstead.harrier.annotations.RequireNotHeadlessSystemUserMode;
 import com.android.bedstead.harrier.annotations.RequireNotLowRamDevice;
 import com.android.bedstead.harrier.annotations.RequirePackageInstalled;
@@ -786,6 +787,12 @@
                 ensureGlobalSettingSet(
                         ensureGlobalSettingSetAnnotation.key(),
                         ensureGlobalSettingSetAnnotation.value());
+                continue;
+            }
+
+            if (annotation instanceof RequireMultiUserSupport) {
+                requireMultiUserSupport();
+                continue;
             }
         }
 
@@ -2528,4 +2535,9 @@
         }
         TestApis.settings().global().putString(key, value);
     }
+
+    private void requireMultiUserSupport() {
+        assumeTrue("This test is only supported on multi user devices",
+                TestApis.users().supportsMultipleUsers());
+    }
 }
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
index 200feb7..0ce2d7f 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
@@ -40,6 +40,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.annotations.Experimental;
 import com.android.bedstead.nene.exceptions.AdbException;
 import com.android.bedstead.nene.exceptions.AdbParseException;
 import com.android.bedstead.nene.exceptions.NeneException;
@@ -485,6 +486,11 @@
         return mCachedUsers.get(id);
     }
 
+    @Experimental
+    public boolean supportsMultipleUsers() {
+        return UserManager.supportsMultipleUsers();
+    }
+
     static Stream<UserInfo> users() {
         if (Permissions.sIgnorePermissions.get()) {
             return sUserManager.getUsers(
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java
index ff389a1..4e798df 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java
@@ -19,17 +19,15 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.app.Instrumentation;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.os.SystemClock;
 import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.util.ArrayMap;
+import android.view.WindowInsets;
+import android.view.WindowManager;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -37,33 +35,31 @@
 import org.junit.rules.ExternalResource;
 
 import java.io.IOException;
-import java.util.Map;
 
 /**
  * Test rule to enable gesture navigation on the device. Designed to be a {@link ClassRule}.
  */
 public class GestureNavRule extends ExternalResource {
-    private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
     private static final String NAV_BAR_INTERACTION_MODE_RES_NAME = "config_navBarInteractionMode";
-    private static final int NAV_BAR_INTERACTION_MODE_GESTURAL = 2;
+    private static final int NAV_BAR_MODE_3BUTTON = 0;
+    private static final int NAV_BAR_MODE_2BUTTON = 1;
+    private static final int NAV_BAR_MODE_GESTURAL = 2;
+
+    private static final String NAV_BAR_MODE_3BUTTON_OVERLAY =
+            "com.android.internal.systemui.navbar.threebutton";
+    private static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
+            "com.android.internal.systemui.navbar.twobutton";
     private static final String GESTURAL_OVERLAY_NAME =
             "com.android.internal.systemui.navbar.gestural";
 
-    /** Most application's res id must be larger than 0x7f000000 */
-    public static final int MIN_APPLICATION_RES_ID = 0x7f000000;
-    public static final String SETTINGS_CLASS =
-            SETTINGS_PACKAGE_NAME + ".Settings$SystemDashboardActivity";
+    private static final int WAIT_OVERLAY_TIMEOUT = 3000;
+    private static final int PEEK_INTERVAL = 200;
 
-    private final Map<String, Boolean> mSystemGestureOptionsMap = new ArrayMap<>();
     private final Context mTargetContext;
     private final UiDevice mDevice;
+    private final WindowManager mWindowManager;
 
-    // Bounds for actions like swipe and click.
-    private String mEdgeToEdgeNavigationTitle;
-    private String mSystemNavigationTitle;
-    private String mGesturePreferenceTitle;
-    private boolean mConfiguredInSettings;
-    private boolean mRevertOverlay;
+    private final String mOriginalOverlayPackage;
 
     @Override
     protected void before() throws Throwable {
@@ -74,7 +70,9 @@
 
     @Override
     protected void after() {
-        disableGestureNav();
+        if (!mOriginalOverlayPackage.equals(GESTURAL_OVERLAY_NAME)) {
+            disableGestureNav();
+        }
     }
 
     /**
@@ -85,39 +83,16 @@
         Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
         mDevice = UiDevice.getInstance(instrumentation);
         mTargetContext = instrumentation.getTargetContext();
-        PackageManager packageManager = mTargetContext.getPackageManager();
-        Resources res;
-        try {
-            res = packageManager.getResourcesForApplication(SETTINGS_PACKAGE_NAME);
-        } catch (PackageManager.NameNotFoundException e) {
-            return;
-        }
-        if (res == null) {
-            return;
-        }
 
-        mEdgeToEdgeNavigationTitle = getSettingsString(res, "edge_to_edge_navigation_title");
-        mGesturePreferenceTitle = getSettingsString(res, "gesture_preference_title");
-        mSystemNavigationTitle = getSettingsString(res, "system_navigation_title");
-
-        String text = getSettingsString(res, "edge_to_edge_navigation_title");
-        if (text != null) {
-            mSystemGestureOptionsMap.put(text, false);
-        }
-        text = getSettingsString(res, "swipe_up_to_switch_apps_title");
-        if (text != null) {
-            mSystemGestureOptionsMap.put(text, false);
-        }
-        text = getSettingsString(res, "legacy_navigation_title");
-        if (text != null) {
-            mSystemGestureOptionsMap.put(text, false);
-        }
-
-        mConfiguredInSettings = false;
+        mOriginalOverlayPackage = getCurrentOverlayPackage();
+        mWindowManager = mTargetContext.getSystemService(WindowManager.class);
     }
 
     @SuppressWarnings("BooleanMethodIsAlwaysInverted")
     private boolean hasSystemGestureFeature() {
+        if (!containsNavigationBar()) {
+            return false;
+        }
         final PackageManager pm = mTargetContext.getPackageManager();
 
         // No bars on embedded devices.
@@ -128,59 +103,21 @@
                 || pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
     }
 
-
-    private UiObject2 findSystemNavigationObject(String text, boolean addCheckSelector) {
-        BySelector widgetFrameSelector = By.res("android", "widget_frame");
-        BySelector checkboxSelector = By.checkable(true);
-        if (addCheckSelector) {
-            checkboxSelector = checkboxSelector.checked(true);
+    private String getCurrentOverlayPackage() {
+        final int currentNavMode = getCurrentNavMode();
+        switch (currentNavMode) {
+            case NAV_BAR_MODE_GESTURAL:
+                return GESTURAL_OVERLAY_NAME;
+            case NAV_BAR_MODE_2BUTTON:
+                return NAV_BAR_MODE_2BUTTON_OVERLAY;
+            case NAV_BAR_MODE_3BUTTON:
+            default:
+                return NAV_BAR_MODE_3BUTTON_OVERLAY;
         }
-        BySelector textSelector = By.text(text);
-        BySelector targetSelector = By.hasChild(widgetFrameSelector).hasDescendant(textSelector)
-                .hasDescendant(checkboxSelector);
-
-        return mDevice.findObject(targetSelector);
     }
 
-    private boolean launchToSettingsSystemGesture() {
-
-        // Open the Settings app as close as possible to the gesture Fragment
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        ComponentName settingComponent = new ComponentName(SETTINGS_PACKAGE_NAME, SETTINGS_CLASS);
-        intent.setComponent(settingComponent);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        mTargetContext.startActivity(intent);
-
-        // Wait for the app to appear
-        mDevice.wait(Until.hasObject(By.pkg("com.android.settings").depth(0)),
-                5000);
-        mDevice.wait(Until.hasObject(By.text(mGesturePreferenceTitle)), 5000);
-        if (mDevice.findObject(By.text(mGesturePreferenceTitle)) == null) {
-            return false;
-        }
-        mDevice.findObject(By.text(mGesturePreferenceTitle)).click();
-        mDevice.wait(Until.hasObject(By.text(mSystemNavigationTitle)), 5000);
-        if (mDevice.findObject(By.text(mSystemNavigationTitle)) == null) {
-            return false;
-        }
-        mDevice.findObject(By.text(mSystemNavigationTitle)).click();
-        mDevice.wait(Until.hasObject(By.text(mEdgeToEdgeNavigationTitle)), 5000);
-
-        return mDevice.hasObject(By.text(mEdgeToEdgeNavigationTitle));
-    }
-
-    private void leaveSettings() {
-        mDevice.pressBack(); /* Back to Gesture */
-        mDevice.waitForIdle();
-        mDevice.pressBack(); /* Back to System */
-        mDevice.waitForIdle();
-        mDevice.pressBack(); /* back to Settings */
-        mDevice.waitForIdle();
-        mDevice.pressBack(); /* Back to Home */
-        mDevice.waitForIdle();
-
-        mDevice.pressHome(); /* double confirm back to home */
-        mDevice.waitForIdle();
+    private void insetsToRect(Insets insets, Rect outRect) {
+        outRect.set(insets.left, insets.top, insets.right, insets.bottom);
     }
 
     private void enableGestureNav() {
@@ -188,71 +125,68 @@
             return;
         }
         try {
-            if (mDevice.executeShellCommand("cmd overlay list").contains(GESTURAL_OVERLAY_NAME)) {
+            if (!mDevice.executeShellCommand("cmd overlay list").contains(GESTURAL_OVERLAY_NAME)) {
+                return;
+            }
+        } catch (IOException ignore) {
+            //
+        }
+        monitorOverlayChange(() -> {
+            try {
                 mDevice.executeShellCommand("cmd overlay enable " + GESTURAL_OVERLAY_NAME);
-                mDevice.waitForIdle();
+            } catch (IOException e) {
+                // Do nothing
             }
-        } catch (IOException e) {
-            // Do nothing
-        }
-
-        if (isGestureMode()) {
-            mRevertOverlay = true;
-            return;
-        }
-
-        // Set up the gesture navigation by enabling it via the Settings app
-        boolean isOperatedSettingsToExpectedOption = launchToSettingsSystemGesture();
-        if (isOperatedSettingsToExpectedOption) {
-            for (Map.Entry<String, Boolean> entry : mSystemGestureOptionsMap.entrySet()) {
-                UiObject2 uiObject2 = findSystemNavigationObject(entry.getKey(), true);
-                entry.setValue(uiObject2 != null);
-            }
-            UiObject2 edgeToEdgeObj = mDevice.findObject(By.text(mEdgeToEdgeNavigationTitle));
-            if (edgeToEdgeObj != null) {
-                edgeToEdgeObj.click();
-                mConfiguredInSettings = true;
-            }
-        }
-        mDevice.waitForIdle();
-        leaveSettings();
-
-        mDevice.pressHome();
-        mDevice.waitForIdle();
-
-        mDevice.waitForIdle();
+        });
     }
 
-    /**
-     * Restore the original configured value for the system gesture by operating Settings.
-     */
     private void disableGestureNav() {
         if (!hasSystemGestureFeature()) {
             return;
         }
-
-        if (mRevertOverlay) {
+        monitorOverlayChange(() -> {
             try {
-                mDevice.executeShellCommand("cmd overlay disable " + GESTURAL_OVERLAY_NAME);
-            } catch (IOException e) {
+                mDevice.executeShellCommand("cmd overlay enable " + mOriginalOverlayPackage);
+            } catch (IOException ignore) {
                 // Do nothing
             }
-            if (!isGestureMode()) {
-                return;
-            }
-        }
+        });
+    }
 
-        if (mConfiguredInSettings) {
-            launchToSettingsSystemGesture();
-            for (Map.Entry<String, Boolean> entry : mSystemGestureOptionsMap.entrySet()) {
-                if (entry.getValue()) {
-                    UiObject2 navigationObject = findSystemNavigationObject(entry.getKey(), false);
-                    if (navigationObject != null) {
-                        navigationObject.click();
-                    }
+    private void getCurrentInsetsSize(Rect outSize) {
+        outSize.setEmpty();
+        if (mWindowManager != null) {
+            WindowInsets insets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
+            Insets navInsets = insets.getInsetsIgnoringVisibility(
+                    WindowInsets.Type.navigationBars());
+            insetsToRect(navInsets, outSize);
+        }
+    }
+
+    // Monitoring the navigation bar insets size change as a hint of gesture mode has changed, not
+    // the best option for every kind of devices. We can consider listening OVERLAY_CHANGED
+    // broadcast in U.
+    private void monitorOverlayChange(Runnable overlayChangeCommand) {
+        if (mWindowManager != null) {
+            final Rect initSize = new Rect();
+            getCurrentInsetsSize(initSize);
+
+            overlayChangeCommand.run();
+            // wait for insets size change
+            final Rect peekSize = new Rect();
+            int t = 0;
+            while (t < WAIT_OVERLAY_TIMEOUT) {
+                SystemClock.sleep(PEEK_INTERVAL);
+                t += PEEK_INTERVAL;
+                getCurrentInsetsSize(peekSize);
+                if (!peekSize.equals(initSize)) {
+                    break;
                 }
             }
-            leaveSettings();
+        } else {
+            // shouldn't happen
+            overlayChangeCommand.run();
+            SystemClock.sleep(WAIT_OVERLAY_TIMEOUT);
         }
     }
 
@@ -266,20 +200,23 @@
         assumeTrue("Gesture navigation required", isGestureMode);
     }
 
-    private boolean isGestureMode() {
-        // TODO: b/153032202 consider the CTS on GSI case.
+    private int getCurrentNavMode() {
         Resources res = mTargetContext.getResources();
         int naviModeId = res.getIdentifier(NAV_BAR_INTERACTION_MODE_RES_NAME, "integer", "android");
-        int naviMode = res.getInteger(naviModeId);
-        return naviMode == NAV_BAR_INTERACTION_MODE_GESTURAL;
+        return res.getInteger(naviModeId);
     }
 
-    private static String getSettingsString(Resources res, String strResName) {
-        int resIdString = res.getIdentifier(strResName, "string", SETTINGS_PACKAGE_NAME);
-        if (resIdString <= MIN_APPLICATION_RES_ID) {
-            return null;
-        }
+    private boolean containsNavigationBar() {
+        final Rect peekSize = new Rect();
+        getCurrentInsetsSize(peekSize);
+        return peekSize.height() != 0;
+    }
 
-        return res.getString(resIdString);
+    private boolean isGestureMode() {
+        if (!containsNavigationBar()) {
+            return false;
+        }
+        final int naviMode = getCurrentNavMode();
+        return naviMode == NAV_BAR_MODE_GESTURAL;
     }
 }
diff --git a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
index 820fd95..8884bf6 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -83,6 +83,7 @@
     private static ImmutableList<String> sSystemserverclasspathJars;
     private static ImmutableList<String> sSharedLibJars;
     private static ImmutableList<SharedLibraryInfo> sSharedLibs;
+    private static ImmutableMultimap<String, String> sSharedLibsPathsToName;
     private static ImmutableMultimap<String, String> sJarsToClasses;
     private static ImmutableMultimap<String, String> sJarsToFiles;
 
@@ -206,6 +207,7 @@
                     "Landroid/os/IVoldListener;",
                     "Landroid/os/IVoldMountCallback;",
                     "Landroid/os/IVoldTaskListener;",
+                    "Landroid/os/TouchOcclusionMode;",
                     "Landroid/os/storage/CrateMetadata;",
                     "Landroid/view/LayerMetadataKey;",
                     "Lcom/android/internal/annotations/CompositeRWLock;",
@@ -795,6 +797,13 @@
                 .filter(file -> !file.contains("GmsCore"))
                 .filter(file -> !file.contains("com.google.android.gms"))
                 .collect(ImmutableList.toImmutableList());
+        final ImmutableSetMultimap.Builder<String, String> sharedLibsPathsToName =
+                ImmutableSetMultimap.builder();
+        sSharedLibs.forEach(sharedLibraryInfo -> {
+                sharedLibraryInfo.paths.forEach(path ->
+                        sharedLibsPathsToName.putAll(path, sharedLibraryInfo.name));
+        });
+        sSharedLibsPathsToName = sharedLibsPathsToName.build();
 
         final ImmutableSetMultimap.Builder<String, String> jarsToFiles =
                 ImmutableSetMultimap.builder();
@@ -1038,17 +1047,19 @@
         // WARNING: Do not add more exceptions here, no androidx should be in bootclasspath.
         // See go/androidx-api-guidelines#module-naming for more details.
         final ImmutableMap<String, ImmutableSet<String>>
-                LegacyExemptAndroidxSharedLibsJarToClasses =
+                LegacyExemptAndroidxSharedLibsNamesToClasses =
                 new ImmutableMap.Builder<String, ImmutableSet<String>>()
-                .put("/vendor/framework/androidx.camera.extensions.impl.jar",
+                .put("androidx.camera.extensions.impl",
                     ImmutableSet.of("Landroidx/camera/extensions/impl/"))
-                .put("/system_ext/framework/androidx.window.extensions.jar",
+                .put("androidx.window.extensions",
                     ImmutableSet.of("Landroidx/window/common/", "Landroidx/window/extensions/",
                         "Landroidx/window/util/"))
-                .put("/system_ext/framework/androidx.window.sidecar.jar",
+                .put("androidx.window.sidecar",
                     ImmutableSet.of("Landroidx/window/common/", "Landroidx/window/sidecar",
                         "Landroidx/window/util"))
-                .put("/vendor/framework/com.google.android.camera.experimental2020_midyear.jar",
+                .put("com.google.android.camera.experimental2019",
+                    ImmutableSet.of("Landroidx/annotation"))
+                .put("com.google.android.camera.experimental2020_midyear",
                     ImmutableSet.of("Landroidx/annotation"))
                 .build();
         assertWithMessage("There must not be any androidx classes on the "
@@ -1057,7 +1068,7 @@
                 .that(sJarsToClasses.entries().stream()
                         .filter(e -> e.getValue().startsWith("Landroidx/"))
                         .filter(e -> !isLegacyAndroidxDependency(
-                            LegacyExemptAndroidxSharedLibsJarToClasses, e.getKey(), e.getValue()))
+                            LegacyExemptAndroidxSharedLibsNamesToClasses, e.getKey(), e.getValue()))
                         .collect(Collectors.toList())
                 ).isEmpty();
     }
@@ -1067,7 +1078,8 @@
      * and shared library jars.
      */
     @Test
-    public void testNoKotlinFilesInClasspaths() {
+    public void testNoKotlinFilesInClasspaths() throws Exception {
+        assumeTrue(mDeviceSdkLevel.isDeviceAtLeastT());
         ImmutableList<String> kotlinFiles =
                 Stream.of(sBootclasspathJars.stream(),
                         sSystemserverclasspathJars.stream(),
@@ -1103,11 +1115,12 @@
     }
 
     private boolean isLegacyAndroidxDependency(
-            ImmutableMap<String, ImmutableSet<String>> legacyExemptAndroidxSharedLibsJarToClasses,
-            String jar, String className) {
-        return legacyExemptAndroidxSharedLibsJarToClasses.containsKey(jar)
-                && legacyExemptAndroidxSharedLibsJarToClasses.get(jar).stream().anyMatch(
-                        v -> className.startsWith(v));
+            ImmutableMap<String, ImmutableSet<String>> legacyExemptAndroidxSharedLibsNamesToClasses,
+            String path, String className) {
+        return sSharedLibsPathsToName.get(path).stream()
+                .filter(legacyExemptAndroidxSharedLibsNamesToClasses::containsKey)
+                .flatMap(name -> legacyExemptAndroidxSharedLibsNamesToClasses.get(name).stream())
+                .anyMatch(className::startsWith);
     }
 
     private String[] collectApkInApexPaths() {
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
index 4da5fff..9c8a81d 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
@@ -25,6 +25,8 @@
 import android.content.pm.PackageManager;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+
 import java.util.ArrayList;
 
 /**
@@ -41,6 +43,7 @@
     private static final String SIMPLE_APP_PKG = "com.android.cts.launcherapps.simpleapp";
     private static final String SIMPLE_APP_ACTIVITY =
             "com.android.cts.launcherapps.simpleapp.SimpleActivityImmediateExit";
+    private static final String ARG_PID_BEFORE_STOP = "pidOfSimpleapp";
 
     public void testSetUserControlDisabledPackages() throws Exception {
         ArrayList<String> protectedPackages = new ArrayList<>();
@@ -86,14 +89,15 @@
         // Check if package is part of UserControlDisabledPackages before checking if
         // package is stopped since it is a necessary condition to prevent stopping of
         // package
-
         assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho()))
                 .containsExactly(SIMPLE_APP_PKG);
-        assertPackageRunningState(/* running= */ true);
+        assertPackageRunningState(/* running= */ true,
+                InstrumentationRegistry.getArguments().getString(ARG_PID_BEFORE_STOP, "-1"));
     }
 
     public void testFgsStopWithUserControlEnabled() throws Exception {
-        assertPackageRunningState(/* running= */ false);
+        assertPackageRunningState(/* running= */ false,
+                InstrumentationRegistry.getArguments().getString(ARG_PID_BEFORE_STOP, "-1"));
         assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho())).isEmpty();
     }
 
@@ -120,9 +124,15 @@
         return pid.length() > 0;
     }
 
-    private void assertPackageRunningState(boolean shouldBeRunning) throws Exception {
+    private void assertPackageRunningState(boolean shouldBeRunning, String argPid)
+            throws Exception {
+        String pid = executeShellCommand(String.format("pidof %s", SIMPLE_APP_PKG)).trim();
+
+        final boolean samePid = pid.equals(argPid);
+        final boolean stillRunning = samePid && isPackageRunning(SIMPLE_APP_PKG);
+
         assertWithMessage("Package %s running for user %s", SIMPLE_APP_PKG,
                 getCurrentUser().getIdentifier())
-                .that(isPackageRunning(SIMPLE_APP_PKG)).isEqualTo(shouldBeRunning);
+                .that(stillRunning).isEqualTo(shouldBeRunning);
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index c87a7f8..d1773d0 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -70,6 +70,7 @@
     private static final String TEST_APP_LOCATION = "/data/local/tmp/cts/packageinstaller/";
 
     private static final String ARG_NETWORK_LOGGING_BATCH_COUNT = "batchCount";
+    private static final String ARG_PID_BEFORE_STOP = "pidOfSimpleapp";
 
     private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
             "CtsHasLauncherActivityApp.apk";
@@ -1059,13 +1060,16 @@
      */
     private void tryFgsStoppingProtectedPackage(int userId, boolean canUserStopPackage)
             throws Exception {
+        String pid = executeShellCommand(String.format("pidof %s", SIMPLE_APP_PKG)).trim();
         fgsStopPackageForUser(SIMPLE_APP_PKG, userId);
         if (canUserStopPackage) {
             executeDeviceTestMethod(".UserControlDisabledPackagesTest",
-                    "testFgsStopWithUserControlEnabled");
+                    "testFgsStopWithUserControlEnabled",
+                     Collections.singletonMap(ARG_PID_BEFORE_STOP, pid));
         } else {
             executeDeviceTestMethod(".UserControlDisabledPackagesTest",
-                    "testFgsStopWithUserControlDisabled");
+                    "testFgsStopWithUserControlDisabled",
+                     Collections.singletonMap(ARG_PID_BEFORE_STOP, pid));
         }
     }
 
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
index 11f24fa..d6ac485 100755
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
@@ -25,6 +25,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.StringReader;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -36,6 +37,41 @@
     private static final String TEST_PKG = "com.android.cts.framestatstestapp";
 
     /**
+     * Parse each line from output of dumpsys to handle special fields such as
+     * 'aaa,"bbb,ccc",ddd', to capture properly.
+     */
+    private static String[] parseCsv(String line) {
+        ArrayList<String> parts = new ArrayList<>();
+        String[] splitStrings = line.split(",", -1);
+        String s = "";
+        boolean escaping = false;
+        for (String splitString : splitStrings) {
+            if (escaping) {
+                s += "," + splitString;
+            } else {
+                if (splitString.startsWith("\"")) {
+                    // Field start with ". Start escaping.
+                    s = splitString;
+                    escaping = true;
+                } else {
+                    parts.add(splitString);
+                }
+            }
+            if (escaping && s.length() > 1 && s.endsWith("\"")) {
+                // Field end with ". Stop escaping.
+                parts.add(s.substring(1, s.length() - 1));
+                escaping = false;
+            }
+        }
+        if (escaping) {
+            // Unclosed escaping string. Add it anyway.
+            parts.add(s.substring(1));
+        }
+
+        return parts.toArray(new String[parts.size()]);
+    }
+
+    /**
      * Tests the output of "dumpsys batterystats --checkin".
      *
      * @throws Exception
@@ -58,11 +94,7 @@
 
 
                 try {
-                    // With a default limit of 0, empty strings at the end are discarded.
-                    // We still consider the empty string as a valid value in some cases.
-                    // Using any negative number for the limit will preserve a trailing empty string.
-                    // @see String#split(String, int)
-                    String[] parts = line.split(",", -1);
+                    String[] parts = parseCsv(line);
                     assertInteger(parts[0]); // old version
                     assertInteger(parts[1]); // UID
                     switch (parts[2]) { // aggregation type
diff --git a/hostsidetests/scopedstorage/Android.bp b/hostsidetests/scopedstorage/Android.bp
index 527e8ef..0e2a887 100644
--- a/hostsidetests/scopedstorage/Android.bp
+++ b/hostsidetests/scopedstorage/Android.bp
@@ -91,7 +91,7 @@
     // Tag as a CTS artifact
     test_suites: [
         "general-tests",
-        "mts",
+        "mts-mediaprovider",
         "cts",
     ],
 }
@@ -155,7 +155,7 @@
     // Tag as a CTS artifact
     test_suites: [
         "general-tests",
-        "mts",
+        "mts-mediaprovider",
         "cts",
     ],
 }
@@ -171,7 +171,7 @@
     // Tag as a CTS artifact
     test_suites: [
         "general-tests",
-        "mts",
+        "mts-mediaprovider",
         "cts",
     ],
 }
@@ -187,7 +187,7 @@
     // Tag as a CTS artifact
     test_suites: [
         "general-tests",
-        "mts",
+        "mts-mediaprovider",
         "cts",
     ],
 }
diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
index 099a0ab..4df785c 100644
--- a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
+++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
@@ -79,6 +79,7 @@
 import static android.scopedstorage.cts.lib.TestUtils.isAppInstalled;
 import static android.scopedstorage.cts.lib.TestUtils.listAs;
 import static android.scopedstorage.cts.lib.TestUtils.openWithMediaProvider;
+import static android.scopedstorage.cts.lib.TestUtils.queryAudioFile;
 import static android.scopedstorage.cts.lib.TestUtils.queryFile;
 import static android.scopedstorage.cts.lib.TestUtils.queryFileExcludingPending;
 import static android.scopedstorage.cts.lib.TestUtils.queryImageFile;
@@ -1772,6 +1773,37 @@
     }
 
     /**
+     * Test that renaming file paths to an external directory such as Android/* and Android/* /*
+     * except Android/media/* /* is not allowed.
+     */
+    @Test
+    public void testRenameFileToAppSpecificDir() throws Exception {
+        final File testFile = new File(getExternalMediaDir(), IMAGE_FILE_NAME);
+        final File testFileNew = new File(getExternalMediaDir(), NONMEDIA_FILE_NAME);
+
+        try {
+            // Create a file in app's external media directory
+            if (!testFile.exists()) {
+                assertThat(testFile.createNewFile()).isTrue();
+            }
+
+            final String androidDirPath = getExternalStorageDir().getPath() + "/Android";
+
+            // Verify that we can't rename a file to Android/ or Android/data or
+            // Android/media directory
+            assertCantRenameFile(testFile, new File(androidDirPath, IMAGE_FILE_NAME));
+            assertCantRenameFile(testFile, new File(androidDirPath + "/data", IMAGE_FILE_NAME));
+            assertCantRenameFile(testFile, new File(androidDirPath + "/media", IMAGE_FILE_NAME));
+
+            // Verify that we can rename a file to app specific media directory.
+            assertCanRenameFile(testFile, testFileNew);
+        } finally {
+            testFile.delete();
+            testFileNew.delete();
+        }
+    }
+
+    /**
      * Test that renaming directories is allowed and aligns to default directory restrictions.
      */
     @Test
@@ -2992,6 +3024,45 @@
         }
     }
 
+    /**
+     * Test that renaming a file to {@link Environment#DIRECTORY_RINGTONES} sets
+     * {@link MediaStore.Audio.AudioColumns#IS_RINGTONE}
+     */
+
+    @Test
+    public void testRenameToRingtoneDirectory() throws Exception {
+        final File fileInDownloads = new File(getDownloadDir(), AUDIO_FILE_NAME);
+        final File fileInRingtones = new File(getRingtonesDir(), AUDIO_FILE_NAME);
+
+        try {
+            assertThat(fileInDownloads.createNewFile()).isTrue();
+            assertThat(MediaStore.scanFile(getContentResolver(), fileInDownloads)).isNotNull();
+
+            assertCanRenameFile(fileInDownloads, fileInRingtones);
+
+            try (Cursor c = queryAudioFile(fileInRingtones,
+                    MediaStore.Audio.AudioColumns.IS_RINGTONE)) {
+                assertTrue(c.moveToFirst());
+                assertWithMessage("Expected " + MediaStore.Audio.AudioColumns.IS_RINGTONE
+                        + " to be set after renaming to " + fileInRingtones)
+                        .that(c.getInt(0)).isEqualTo(1);
+            }
+
+            assertCanRenameFile(fileInRingtones, fileInDownloads);
+
+            try (Cursor c = queryAudioFile(fileInDownloads,
+                    MediaStore.Audio.AudioColumns.IS_RINGTONE)) {
+                assertTrue(c.moveToFirst());
+                assertWithMessage("Expected " + MediaStore.Audio.AudioColumns.IS_RINGTONE
+                        + " to be unset after renaming to " + fileInDownloads)
+                        .that(c.getInt(0)).isEqualTo(0);
+            }
+        } finally {
+            fileInDownloads.delete();
+            fileInRingtones.delete();
+        }
+    }
+
     @Test
     @SdkSuppress(minSdkVersion = 31, codeName = "S")
     public void testTransformsDirFileOperations() throws Exception {
diff --git a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
index 0670639..2e694ed 100644
--- a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
+++ b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
@@ -751,6 +751,17 @@
     }
 
     /**
+     * Queries {@link ContentResolver} for an audio file and returns a {@link Cursor} with the given
+     * columns.
+     */
+    @NonNull
+    public static Cursor queryAudioFile(File file, String... projection) {
+        return queryFile(getContentResolver(),
+                MediaStore.Audio.Media.getContentUri(sStorageVolumeName), file,
+                /*includePending*/ true, projection);
+    }
+
+    /**
      * Queries {@link ContentResolver} for a file and returns the corresponding mime type for its
      * entry in the database.
      */
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 573035c..dea2688 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -116,8 +116,6 @@
     private File devicePcFile;
     private File deviceSvcFile;
     private File seappNeverAllowFile;
-    private File libsepolwrap;
-    private File libcpp;
     private File copyLibcpp;
     private File sepolicyTests;
 
@@ -907,29 +905,8 @@
         return (os.startsWith("mac") || os.startsWith("darwin"));
     }
 
-    private void setupLibraries() throws Exception {
-        // The host side binary tests are host OS specific. Use Linux
-        // libraries on Linux and Mac libraries on Mac.
-        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
-        if (isMac()) {
-            libsepolwrap = buildHelper.getTestFile("libsepolwrap.dylib");
-            libcpp = buildHelper.getTestFile("libc++.dylib");
-            copyLibcpp = new File(System.getProperty("java.io.tmpdir") + "/libc++.dylib");
-            Files.copy(libcpp.toPath(), copyLibcpp.toPath(), StandardCopyOption.REPLACE_EXISTING);
-        } else {
-            libsepolwrap = buildHelper.getTestFile("libsepolwrap.so");
-            libcpp = buildHelper.getTestFile("libc++.so");
-            copyLibcpp = new File(System.getProperty("java.io.tmpdir") + "/libc++.so");
-            Files.copy(libcpp.toPath(), copyLibcpp.toPath(), StandardCopyOption.REPLACE_EXISTING);
-        }
-        libsepolwrap.deleteOnExit();
-        libcpp.deleteOnExit();
-        copyLibcpp.deleteOnExit();
-    }
-
     private void assertSepolicyTests(String test, String testExecutable,
             boolean includeVendorSepolicy) throws Exception {
-        setupLibraries();
         sepolicyTests = copyResourceToTempFile(testExecutable);
         sepolicyTests.setExecutable(true);
 
@@ -951,12 +928,6 @@
         }
 
         ProcessBuilder pb = new ProcessBuilder(args);
-        Map<String, String> env = pb.environment();
-        if (isMac()) {
-            env.put("DYLD_LIBRARY_PATH", System.getProperty("java.io.tmpdir"));
-        } else {
-            env.put("LD_LIBRARY_PATH", System.getProperty("java.io.tmpdir"));
-        }
         pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
         pb.redirectErrorStream(true);
         Process p = pb.start();
@@ -1367,7 +1338,7 @@
     @CddTest(requirement="9.7")
     @Test
     public void testDrmServerDomain() throws DeviceNotAvailableException {
-        assertDomainN("u:r:drmserver:s0", "/system/bin/drmserver", "/system/bin/drmserver64");
+        assertDomainHasExecutable("u:r:drmserver:s0", "/system/bin/drmserver", "/system/bin/drmserver64");
     }
 
     /* Installd is always running */
diff --git a/hostsidetests/securitybulletin/Android.bp b/hostsidetests/securitybulletin/Android.bp
index 30b6161..2524227 100644
--- a/hostsidetests/securitybulletin/Android.bp
+++ b/hostsidetests/securitybulletin/Android.bp
@@ -43,6 +43,7 @@
 
 cc_defaults {
     name: "cts_hostsidetests_securitybulletin_defaults",
+    auto_gen_config: false,
     compile_multilib: "both",
     multilib: {
         lib32: {
diff --git a/hostsidetests/securitybulletin/res/cve_2021_39623.ogg b/hostsidetests/securitybulletin/res/cve_2021_39623.ogg
new file mode 100644
index 0000000..1992a17
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2021_39623.ogg
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2022_22082.dsf b/hostsidetests/securitybulletin/res/cve_2022_22082.dsf
new file mode 100644
index 0000000..60d1a5a
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2022_22082.dsf
Binary files differ
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/Android.bp
new file mode 100644
index 0000000..50662fd
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/Android.bp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "CVE-2021-39623",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+    ],
+    header_libs: [
+        "libmediametrics_headers",
+    ],
+    shared_libs: [
+        "libstagefright",
+        "libdatasource",
+        "libutils",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/poc.cpp
new file mode 100644
index 0000000..d9e38ba
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/poc.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../includes/common.h"
+#include <datasource/DataSourceFactory.h>
+#include <dlfcn.h>
+#include <gui/SurfaceComposerClient.h>
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaExtractorFactory.h>
+#include <media/stagefright/SimpleDecodingSource.h>
+#include <sys/mman.h>
+
+typedef void *(*mmap_t)(void *, size_t, int, int, int, off_t);
+mmap_t real_mmap = nullptr;
+
+using namespace android;
+
+bool testInProgress = false;
+constexpr size_t kTargetBufferSize = 32768;
+struct sigaction new_action, old_action;
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+  if (testInProgress && info->si_signo == SIGSEGV) {
+    (*old_action.sa_sigaction)(signum, info, context);
+    return;
+  }
+  exit(EXIT_FAILURE);
+}
+
+void *mmap(void *addr, size_t length, int prot, int flags, int fd,
+           off_t offset) {
+  real_mmap = (mmap_t)dlsym(RTLD_NEXT, "mmap");
+  if (!real_mmap) {
+    exit(EXIT_FAILURE);
+  }
+  if (length == kTargetBufferSize) {
+    char *tmp_ptr = (char *)real_mmap(addr, length + PAGE_SIZE, prot,
+                                      flags | MAP_ANONYMOUS, -1, offset);
+    mprotect(tmp_ptr + length, PAGE_SIZE, PROT_NONE);
+    return tmp_ptr;
+  }
+  return real_mmap(addr, length, prot, flags, fd, offset);
+}
+
+int main(int argc, char **argv) {
+  FAIL_CHECK(argc > 1);
+  sigemptyset(&new_action.sa_mask);
+  new_action.sa_flags = SA_SIGINFO;
+  new_action.sa_sigaction = sigsegv_handler;
+  sigaction(SIGSEGV, &new_action, &old_action);
+
+  sp<DataSource> dataSource = DataSourceFactory::getInstance()->CreateFromURI(
+      nullptr /* httpService */, argv[1]);
+  FAIL_CHECK(dataSource);
+
+  sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
+  FAIL_CHECK(extractor);
+
+  sp<MediaSource> mediaSource =
+      CreateMediaSourceFromIMediaSource(extractor->getTrack(0));
+  FAIL_CHECK(mediaSource);
+
+  sp<MediaSource> rawSource = SimpleDecodingSource::Create(
+      mediaSource, MediaCodecList::kPreferSoftwareCodecs, nullptr, nullptr,
+      false);
+  FAIL_CHECK(rawSource);
+
+  status_t err = rawSource->start();
+  FAIL_CHECK(err == OK);
+
+  MediaSource::ReadOptions options = {};
+  MediaBufferBase *buffer = nullptr;
+
+  testInProgress = true;
+  rawSource->read(&buffer, &options);
+  testInProgress = false;
+  if (buffer) {
+    buffer->release();
+    buffer = nullptr;
+  }
+  options.clearSeekTo();
+  options.setSeekTo(0);
+  rawSource->stop();
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
index 12287b0..95c90d4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,43 +16,39 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AppModeFull;
+import static org.junit.Assume.assumeNoException;
+
 import android.platform.test.annotations.AsbSecurityTest;
 
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
 
-import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class CVE_2021_0954 extends StsExtraBusinessLogicHostTestBase {
-    private static final String TEST_PKG = "android.security.cts.cve_2021_0954";
-    private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
-    private static final String TEST_APP = "CVE-2021-0954.apk";
-    private ITestDevice device;
+    private static final String TEST_PKG = "android.security.cts.CVE_2021_0954";
 
-    @Before
-    public void setUp() throws Exception {
-        device = getDevice();
-        uninstallPackage(device, TEST_PKG);
-
-        /* Wake up the screen */
-        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
-        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
-        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
-    }
-
-    @AppModeFull
     @AsbSecurityTest(cveBugId = 143559931)
     @Test
     public void testPocCVE_2021_0954() throws Exception {
-        installPackage(TEST_APP);
-        AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW",
-                device);
-        runDeviceTests(TEST_PKG, TEST_CLASS, "testVulnerableActivityPresence");
+        try {
+            ITestDevice device = getDevice();
+            uninstallPackage(device, TEST_PKG);
+
+            /* Wake up the screen */
+            AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+            installPackage("CVE-2021-0954.apk");
+            AdbUtils.runCommandLine(
+                    "pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW", device);
+            runDeviceTests(TEST_PKG, TEST_PKG + "." + "DeviceTest", "testOverlayButtonPresence");
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
new file mode 100644
index 0000000..9ab3f08
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39623 extends SecurityTestCase {
+
+    /**
+     * b/194105348
+     * Vulnerability Behaviour: SIGSEGV in self
+     * Vulnerable Library: libstagefright (As per AOSP code)
+     * Vulnerable Function: doRead (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 194105348)
+    @Test
+    public void testPocCVE_2021_39623() throws Exception {
+        String binaryName = "CVE-2021-39623";
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName)
+                .setBacktraceIncludes(new BacktraceFilterPattern("libstagefright",
+                        "android::SimpleDecodingSource::doRead"));
+        String signals[] = {CrashUtils.SIGSEGV};
+        testConfig.config.setSignals(signals);
+        testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+        String inputFiles[] = {"cve_2021_39623.ogg"};
+        testConfig.inputFiles = Arrays.asList(inputFiles);
+        testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java
new file mode 100644
index 0000000..e661b4f
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20353 extends StsExtraBusinessLogicHostTestBase {
+
+    @AsbSecurityTest(cveBugId = 221041256)
+    @Test
+    public void testPocCVE_2022_20353() {
+        try {
+            final String testPkg = "android.security.cts.CVE_2022_20353";
+            ITestDevice device = getDevice();
+
+            AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+            // to generate NOTICE.html if not already present
+            AdbUtils.runCommandLine("am start -a android.settings.LICENSE", device);
+
+            installPackage("CVE-2022-20353.apk");
+
+            runDeviceTests(testPkg, testPkg + ".DeviceTest", "testDefaultRingtonePreference");
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java
new file mode 100644
index 0000000..e71a1f3
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security.cts;
+
+import static org.junit.Assume.*;
+
+import android.platform.test.annotations.AsbSecurityTest;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_22082 extends SecurityTestCase {
+
+    /**
+     * CVE-2022-22082
+     */
+    @AsbSecurityTest(cveBugId = 223211217)
+    @Test
+    public void testPocCVE_2022_22082() throws Exception {
+        /*
+         * Non StageFright test.
+         */
+        safeReboot();
+        AdbUtils.pushResource("/cve_2022_22082.dsf", "/sdcard/cve_2022_22082.dsf", getDevice());
+        AdbUtils.runCommandLine("logcat -c", getDevice());
+        AdbUtils.runCommandLine(
+                "am start -a android.intent.action.VIEW -t audio/dsf -d file:///sdcard/cve_2022_22082.dsf",
+                getDevice());
+        Thread.sleep(10000);
+        AdbUtils.assertNoCrashes(getDevice(), "media.extractor");
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml
index 7f819bc..ef3e6cd 100644
--- a/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml
@@ -17,6 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.security.cts.BUG_182282630"
           android:targetSandboxVersion="2">
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
     <application
         android:label="@string/app_name"
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp
index aa9f71f..59350cf 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
 android_test_helper_app {
     name: "CVE-2021-0954",
     defaults: ["cts_support_defaults"],
-    srcs: ["src/**/*.java"],
+    srcs: [
+        "src/**/*.java"
+    ],
     test_suites: [
-        "cts",
-        "vts10",
         "sts",
     ],
     static_libs: [
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml
index a7e0218..75299c4 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <!--
-  Copyright 2021 The Android Open Source Project
+  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.
@@ -13,25 +13,19 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
+
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
-    package="android.security.cts.cve_2021_0954"
+    package="android.security.cts.CVE_2021_0954"
     android:versionCode="1"
     android:versionName="1.0">
-
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
-
-    <application
-        android:allowBackup="true"
-        android:label="CVE_2021_0954"
-        android:supportsRtl="true">
-        <uses-library android:name="android.test.runner" />
+    <application>
         <service android:name=".PocService"
             android:enabled="true"
-            android:exported="false" />
+            android:exported="true" />
     </application>
-
    <instrumentation
         android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="android.security.cts.cve_2021_0954" />
+        android:targetPackage="android.security.cts.CVE_2021_0954" />
 </manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/integers.xml
new file mode 100644
index 0000000..363df00
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/integers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <integer name="assumptionFailure">-1</integer>
+    <integer name="noAssumptionFailure">0</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/strings.xml
new file mode 100644
index 0000000..7c4d959
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+    <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+    <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
+    <string name="cmdDumpsysActivity">dumpsys activity %1$s</string>
+    <string name="empty"></string>
+    <string name="overlayErrorMessage">Device is vulnerable to b/143559931 hence any app with
+    "SYSTEM_ALERT_WINDOW can overlay the %1$s screen</string>
+    <string name="mResumedTrue">mResumed=true</string>
+    <string name="messageKey">message</string>
+    <string name="overlayButtonText">OverlayButton</string>
+    <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+    <string name="resultKey">result</string>
+    <string name="sharedPreferences">CVE_2021_0954_prefs</string>
+    <string name="timedOutPocActivity">Timed out waiting on a result from PocActivity</string>
+    <string name="vulClass">com.android.internal.app.ResolverActivity</string>
+    <string name="vulClassAuto">com.android.car.activityresolver.CarResolverActivity</string>
+    <string name="vulPkg">android</string>
+    <string name="vulPkgAuto">com.android.car.activityresolver</string>
+    <string name="vulActivityNotRunningError">The %1$s is not currently running on the device
+    </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java
index f986906..9a94ef9 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,17 +14,20 @@
  * limitations under the License.
  */
 
-package android.security.cts.cve_2021_0954;
+package android.security.cts.CVE_2021_0954;
 
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assume.assumeNoException;
 
-import android.content.ActivityNotFoundException;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.pm.PackageManager;
 import android.provider.Settings;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -32,90 +35,107 @@
 import androidx.test.uiautomator.UiDevice;
 import androidx.test.uiautomator.Until;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.IOException;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
 import java.util.regex.Pattern;
 
 @RunWith(AndroidJUnit4.class)
 public class DeviceTest {
-    private static final String TEST_PKG = "android.security.cts.cve_2021_0954";
-    private static final String TEST_VULNERABLE_PKG = "android";
-    private static final String TEST_VULNERABLE_ACTIVITY =
-            "com.android.internal.app.ResolverActivity";
-    private static final int LAUNCH_TIMEOUT_MS = 20000;
-    private static final String vulnerableActivityName = "ResolverActivity";
-    private UiDevice mDevice;
-    String activityDump = "";
+    private Context mContext = getApplicationContext();
+    private static final int TIMEOUT_MS = 10000;
 
-    private void startOverlayService() {
-        Context context = getApplicationContext();
-        assertNotNull(context);
-        Intent intent = new Intent(context, PocService.class);
-        assertNotNull(intent);
-
-        if (Settings.canDrawOverlays(getApplicationContext())) {
-            context.startService(intent);
-        } else {
-            try {
-                context.startService(intent);
-            } catch (Exception e) {
-                throw new RuntimeException("Unable to start the overlay service", e);
-            }
-        }
+    private boolean hasFeature(String feature) {
+        return mContext.getPackageManager().hasSystemFeature(feature);
     }
 
-    public void startVulnerableActivity() {
-        Context context = getApplicationContext();
-        Intent intent = new Intent();
-        intent.setClassName(TEST_VULNERABLE_PKG, TEST_VULNERABLE_ACTIVITY);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        try {
-            context.startActivity(intent);
-        } catch (ActivityNotFoundException e) {
-            assumeNoException("Activity not found on device", e);
-        }
+    private boolean isAuto() {
+        return hasFeature(PackageManager.FEATURE_AUTOMOTIVE);
     }
 
-    @Before
-    public void setUp() throws Exception {
-        mDevice = UiDevice.getInstance(getInstrumentation());
+    String getStringRes(int key) {
+        return mContext.getResources().getString(key);
+    }
 
-        /* Start the vulnerable activity */
-        startVulnerableActivity();
-        if (!mDevice.wait(Until.hasObject(By.res("android:id/contentPanel")
-                .clazz("android.widget.ScrollView").pkg("android")), LAUNCH_TIMEOUT_MS)) {
-            return;
-        }
+    String getStringResWithArg(int key, String arg) {
+        return mContext.getResources().getString(key, arg);
+    }
 
-        /* Start the overlay service */
-        startOverlayService();
+    int getIntegerRes(int key) {
+        return mContext.getResources().getInteger(key);
     }
 
     @Test
-    public void testVulnerableActivityPresence() {
-        Pattern overlayTextPattern = Pattern.compile("OverlayButton", Pattern.CASE_INSENSITIVE);
-        if (!mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS)) {
-            return;
-        }
-
-        /*
-         * Check if the currently running activity is the vulnerable activity, if not abort the test
-         */
+    public void testOverlayButtonPresence() {
         try {
-            activityDump = mDevice.executeShellCommand("dumpsys activity");
-        } catch (IOException e) {
-            throw new RuntimeException("Could not execute dumpsys activity command");
+            UiDevice device = UiDevice.getInstance(getInstrumentation());
+
+            /* Start the overlay service */
+            assumeTrue(getStringRes(R.string.canNotDrawOverlaysMsg),
+                    Settings.canDrawOverlays(mContext));
+            Intent intent = new Intent(mContext, PocService.class);
+            mContext.startService(intent);
+
+            /* Wait for a result from overlay service */
+            SharedPreferences sharedPrefs = mContext.getSharedPreferences(
+                    getStringRes(R.string.sharedPreferences), Context.MODE_PRIVATE);
+            final Semaphore preferenceChanged = new Semaphore(0);
+            OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+                @Override
+                public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+                        String key) {
+                    if (key.equals(getStringRes(R.string.resultKey))) {
+                        preferenceChanged.release();
+                    }
+                }
+            };
+            sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
+            assumeTrue(preferenceChanged.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            int result = sharedPrefs.getInt(getStringRes(R.string.resultKey),
+                    getIntegerRes(R.integer.assumptionFailure));
+            String message = sharedPrefs.getString(getStringRes(R.string.messageKey),
+                    getStringRes(R.string.defaultSemaphoreMsg));
+            assumeTrue(message, result != getIntegerRes(R.integer.assumptionFailure));
+
+            /* Wait for the UI of overlay window to appear */
+            Pattern overlayTextPattern = Pattern.compile(
+                    mContext.getString(R.string.overlayButtonText), Pattern.CASE_INSENSITIVE);
+            assumeTrue(mContext.getString(R.string.overlayUiScreenError),
+                    device.wait(Until.hasObject(By.text(overlayTextPattern)), TIMEOUT_MS));
+
+            /* Start the vulnerable activity */
+            intent = new Intent();
+            String vulActivity = getStringRes(R.string.vulClass);
+            String vulPkg = getStringRes(R.string.vulPkg);
+            if (isAuto()) {
+                vulActivity = getStringRes(R.string.vulClassAuto);
+                vulPkg = getStringRes(R.string.vulPkgAuto);
+            }
+            intent.setClassName(vulPkg, vulActivity);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(intent);
+
+            /* Wait until the object of overlay window is gone */
+            boolean overlayDisallowed =
+                    device.wait(Until.gone(By.pkg(mContext.getPackageName())), TIMEOUT_MS);
+
+            /*
+             * Check if the currently running activity is the vulnerable activity, if not abort the
+             * test
+             */
+            String activityDump = device.executeShellCommand(
+                    getStringResWithArg(R.string.cmdDumpsysActivity, vulActivity));
+            Pattern activityPattern = Pattern.compile(getStringRes(R.string.mResumedTrue));
+            assumeTrue(getStringRes(R.string.vulActivityNotRunningError),
+                    activityPattern.matcher(activityDump).find());
+
+            /* Failing the test as fix is not present */
+            assertTrue(getStringResWithArg(R.string.overlayErrorMessage, vulActivity),
+                    overlayDisallowed);
+        } catch (Exception e) {
+            assumeNoException(e);
         }
-        Pattern activityPattern =
-                Pattern.compile("mResumedActivity.*" + vulnerableActivityName + ".*\n");
-        if (!activityPattern.matcher(activityDump).find()) {
-            return;
-        }
-        String message = "Device is vulnerable to b/143559931 hence any app with "
-                + "SYSTEM_ALERT_WINDOW can overlay the ResolverActivity screen";
-        assertNull(message, mDevice.findObject(By.text(overlayTextPattern)));
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java
index 82b78a2..79270ba 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,47 +14,65 @@
  * limitations under the License.
  */
 
-package android.security.cts.cve_2021_0954;
+package android.security.cts.CVE_2021_0954;
 
 import android.app.Service;
+import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
-import android.os.Handler;
 import android.os.IBinder;
-import android.provider.Settings;
 import android.view.Gravity;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.widget.Button;
 
 public class PocService extends Service {
-    public static Button mButton;
-    private WindowManager mWindowManager;
-    private WindowManager.LayoutParams mLayoutParams;
+    Button mButton;
+    WindowManager mWindowManager;
 
-    private static int getScreenWidth() {
+    private int getScreenWidth() {
         return Resources.getSystem().getDisplayMetrics().widthPixels;
     }
 
-    private static int getScreenHeight() {
+    private int getScreenHeight() {
         return Resources.getSystem().getDisplayMetrics().heightPixels;
     }
 
+    String getStringRes(int key) {
+        return getResources().getString(key);
+    }
+
+    int getIntegerRes(int key) {
+        return getResources().getInteger(key);
+    }
+
     @Override
     public void onCreate() {
-        super.onCreate();
-        mWindowManager = getSystemService(WindowManager.class);
-        mLayoutParams = new WindowManager.LayoutParams();
-        mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-        mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        mLayoutParams.format = PixelFormat.OPAQUE;
-        mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
-        mLayoutParams.width = getScreenWidth();
-        mLayoutParams.height = getScreenHeight();
-        mLayoutParams.x = getScreenWidth() / 2;
-        mLayoutParams.y = getScreenHeight() / 2;
+        try {
+            super.onCreate();
+            mWindowManager = getSystemService(WindowManager.class);
+            LayoutParams layoutParams = new LayoutParams();
+            layoutParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY;
+            layoutParams.flags =
+                    LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;
+            layoutParams.format = PixelFormat.OPAQUE;
+            layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+            layoutParams.width = getScreenWidth();
+            layoutParams.height = getScreenHeight();
+            layoutParams.x = getScreenWidth() / 2;
+            layoutParams.y = getScreenHeight() / 2;
+
+            /* Show the floating window */
+            mButton = new Button(this);
+            mButton.setText(getString(R.string.overlayButtonText));
+            mWindowManager.addView(mButton, layoutParams);
+        } catch (Exception e) {
+            sendTestResult(getIntegerRes(R.integer.assumptionFailure), e.getMessage());
+            return;
+        }
+        sendTestResult(getIntegerRes(R.integer.noAssumptionFailure), getStringRes(R.string.empty));
     }
 
     @Override
@@ -63,31 +81,27 @@
     }
 
     @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        showFloatingWindow();
-        return super.onStartCommand(intent, flags, startId);
-    }
-
-    @Override
     public void onDestroy() {
-        if (mWindowManager != null && mButton != null) {
-            mWindowManager.removeView(mButton);
+        try {
+            if (mWindowManager != null && mButton != null) {
+                mWindowManager.removeView(mButton);
+            }
+            super.onDestroy();
+        } catch (Exception e) {
+            sendTestResult(getIntegerRes(R.integer.assumptionFailure), e.getMessage());
         }
-        super.onDestroy();
     }
 
-    private void showFloatingWindow() {
-        if (Settings.canDrawOverlays(this)) {
-            mButton = new Button(getApplicationContext());
-            mButton.setText("OverlayButton");
-            mWindowManager.addView(mButton, mLayoutParams);
-            new Handler().postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    onDestroy();
-                }
-            }, 60000); // one minute
-            mButton.setTag(mButton.getVisibility());
+    private void sendTestResult(int result, String message) {
+        try {
+            SharedPreferences sh = getSharedPreferences(getStringRes(R.string.sharedPreferences),
+                    Context.MODE_PRIVATE);
+            SharedPreferences.Editor edit = sh.edit();
+            edit.putInt(getStringRes(R.string.resultKey), result);
+            edit.putString(getStringRes(R.string.messageKey), message);
+            edit.commit();
+        } catch (Exception e) {
+            // ignore the exception
         }
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/Android.bp
new file mode 100644
index 0000000..37d35eb
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+    name: "CVE-2022-20353",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+    ],
+    sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/AndroidManifest.xml
new file mode 100644
index 0000000..d4129ac
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2022_20353">
+    <application
+        android:label="@string/appName"
+        android:supportsRtl="true">
+        <activity
+            android:name=".PocActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.RINGTONE_PICKER" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+    </application>
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2022_20353" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/integers.xml
new file mode 100644
index 0000000..3207c29
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <integer name="assumptionFailure">-1</integer>
+    <integer name="success">0</integer>
+    <integer name="timeoutMs">20000</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/strings.xml
new file mode 100644
index 0000000..27e87f6
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <string name="alwaysButtonId">android:id/button_always</string>
+    <string name="appName">CVE-2022-20353</string>
+    <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
+    <string name="failureMessage">
+    Device is vulnerable to b/221041256!! Privilege escalation possible in
+    com.android.settings.DefaultRingtonePreference
+    </string>
+    <string name="fileName">NOTICE.html</string>
+    <string name="getRingtoneCmd">settings get system ringtone</string>
+    <string name="messageKey">message</string>
+    <string name="noticeUri">
+    content://com.android.settings.files/my_cache/NOTICE.html
+    </string>
+    <string name="resType">string</string>
+    <string name="resultKey">result</string>
+    <string name="setRingtoneCmd">settings put system ringtone</string>
+    <string name="sharedPreferences">sharedPreferences</string>
+    <string name="textResId">ringtone_title</string>
+    <string name="uiObjectNotFoundMsg">Unable to find UiObject with %1$s text/id</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/DeviceTest.java
new file mode 100644
index 0000000..af1f978
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/DeviceTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20353;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiScrollable;
+import androidx.test.uiautomator.UiSelector;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    Resources mResources;
+    UiDevice mDevice;
+    Context mContext;
+
+    // Wait for UiObject to appear and click on the UiObject if it is visible
+    private boolean clickUiObject(BySelector selector) {
+        boolean objectFound =
+                mDevice.wait(Until.hasObject(selector), mResources.getInteger(R.integer.timeoutMs));
+        if (objectFound) {
+            mDevice.findObject(selector).click();
+        }
+        return objectFound;
+    }
+
+    @Test
+    public void testDefaultRingtonePreference() {
+        String defaultRingtone = null;
+        try {
+            mDevice = UiDevice.getInstance(getInstrumentation());
+            mContext = getInstrumentation().getContext();
+            mResources = mContext.getResources();
+            defaultRingtone =
+                    mDevice.executeShellCommand(mContext.getString(R.string.getRingtoneCmd));
+
+            Intent intent = new Intent(Settings.ACTION_SOUND_SETTINGS);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(intent);
+
+            String settingsPackageName =
+                    intent.resolveActivity(mContext.getPackageManager()).getPackageName();
+            Context settingsContext = mContext.createPackageContext(settingsPackageName,
+                    Context.CONTEXT_IGNORE_SECURITY);
+            Resources res = settingsContext.getPackageManager()
+                    .getResourcesForApplication(settingsPackageName);
+            String text = settingsContext
+                    .getString(res.getIdentifier(mContext.getString(R.string.textResId),
+                            mContext.getString(R.string.resType), settingsPackageName));
+            // scroll until text 'Phone ringtone' is visible
+            UiScrollable uiScrollable = new UiScrollable(new UiSelector().scrollable(true));
+            uiScrollable.scrollTextIntoView(text);
+            // click on 'Phone ringtone'
+            BySelector selector = By.text(text);
+            assumeTrue(mContext.getString(R.string.uiObjectNotFoundMsg, text),
+                    clickUiObject(selector));
+            // select CTS PoC app
+            text = mContext.getString(R.string.appName);
+            selector = By.text(text);
+            assumeTrue(mContext.getString(R.string.uiObjectNotFoundMsg, text),
+                    clickUiObject(selector));
+            // select 'Always'
+            String resId = mContext.getString(R.string.alwaysButtonId);
+            selector = By.res(resId);
+            assumeTrue(mContext.getString(R.string.uiObjectNotFoundMsg, resId),
+                    clickUiObject(selector));
+
+            SharedPreferences sharedPrefs = mContext.getSharedPreferences(
+                    mContext.getString(R.string.sharedPreferences), Context.MODE_APPEND);
+            Semaphore preferenceChanged = new Semaphore(0);
+            OnSharedPreferenceChangeListener sharedPrefListener =
+                    new OnSharedPreferenceChangeListener() {
+                        @Override
+                        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+                                String key) {
+                            if (key.equals(mContext.getString(R.string.resultKey))) {
+                                preferenceChanged.release();
+                            }
+                        }
+                    };
+            sharedPrefs.registerOnSharedPreferenceChangeListener(sharedPrefListener);
+            // wait for PocActivity to complete
+            assumeTrue(preferenceChanged.tryAcquire(mResources.getInteger(R.integer.timeoutMs),
+                    TimeUnit.MILLISECONDS));
+            int result = sharedPrefs.getInt(mContext.getString(R.string.resultKey),
+                    mResources.getInteger(R.integer.assumptionFailure));
+            String message = sharedPrefs.getString(mContext.getString(R.string.messageKey),
+                    mContext.getString(R.string.defaultSemaphoreMsg));
+            assumeTrue(message, result != mResources.getInteger(R.integer.assumptionFailure));
+
+            String ringtoneUri = "";
+            boolean isVulnerable = false;
+            long startTime = System.currentTimeMillis();
+            while ((System.currentTimeMillis() - startTime) < mResources
+                    .getInteger(R.integer.timeoutMs)) {
+                ringtoneUri =
+                        mDevice.executeShellCommand(mContext.getString(R.string.getRingtoneCmd));
+                if (ringtoneUri.contains(mContext.getString(R.string.fileName))) {
+                    isVulnerable = true;
+                    break;
+                }
+            }
+            assertFalse(mContext.getString(R.string.failureMessage), isVulnerable);
+        } catch (Exception e) {
+            assumeNoException(e);
+        } finally {
+            try {
+                // reset ringtone to default (other than 'null') present before test
+                mDevice.executeShellCommand(
+                        mContext.getString(R.string.setRingtoneCmd) + " " + defaultRingtone);
+                mDevice.pressHome();
+            } catch (Exception e) {
+                // ignore exception here
+            }
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/PocActivity.java
new file mode 100644
index 0000000..977e647
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/PocActivity.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20353;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Bundle;
+
+/* PocActivity is required in this test since it is required that CTS PoC app is selected when */
+/* choosing an app for setting default ringtone. RingtonePicker appears due to actions done in */
+/* DeviceTest.                                                                                 */
+public class PocActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        try {
+            super.onCreate(savedInstanceState);
+            Intent intent = new Intent();
+            /* set NOTICE.html file uri as EXTRA_RINGTONE_PICKED_URI which sets NOTICE.html as */
+            /* default ringtone if vulnerability is present                                    */
+            intent.putExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI,
+                    Uri.parse(getString(R.string.noticeUri)));
+            setResult(Activity.RESULT_OK, intent);
+            finish();
+            sendTestResult(getResources().getInteger(R.integer.success), "");
+        } catch (Exception e) {
+            sendTestResult(getResources().getInteger(R.integer.assumptionFailure), e.getMessage());
+        }
+    }
+
+    void sendTestResult(int result, String message) {
+        try {
+            SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
+                    Context.MODE_PRIVATE);
+            SharedPreferences.Editor edit = sh.edit();
+            edit.putInt(getString(R.string.resultKey), result);
+            edit.putString(getString(R.string.messageKey), message);
+            edit.commit();
+        } catch (Exception e) {
+            // ignore exception here
+        }
+    }
+
+}
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java
index be665ba..7f29d44 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java
@@ -69,10 +69,6 @@
                 .addAllowedLogSource("AID_SYSTEM")
                 .addAllowedLogSource("AID_BLUETOOTH")
                 .addAllowedLogSource("com.android.bluetooth")
-                // TODO(b/236681553): Remove this.
-                .addAllowedLogSource("com.android.bluetooth.services")
-                // TODO(b/236681553): Remove this.
-                .addAllowedLogSource("com.google.android.bluetooth.services")
                 .addAllowedLogSource("AID_LMKD")
                 .addAllowedLogSource("AID_MEDIA")
                 .addAllowedLogSource("AID_RADIO")
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java b/tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java
index 7b7e9e03..4ff8d9e 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java
@@ -41,6 +41,7 @@
 
 import org.junit.After;
 import org.junit.AfterClass;
+import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -73,6 +74,12 @@
     public static void setUpBeforeClass() throws Exception {
         sDocumentsUiPackageName = getDocumentsUiPackageName();
         sGetContentTakeOverActivityAliasState = GetContentActivityAliasUtils.enableAndGetOldState();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
         clearPackageData(sDocumentsUiPackageName);
     }
 
@@ -82,6 +89,37 @@
     }
 
     @Test
+    public void testMimeTypeFilter() throws Exception {
+        final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        intent.addCategory(Intent.CATEGORY_OPENABLE);
+        intent.setType("audio/*");
+        mActivity.startActivityForResult(intent, REQUEST_CODE);
+        mDevice.waitForIdle();
+        // Should open documentsUi
+        assertThatShowsDocumentsUiButtons();
+
+        // We don't test the result of the picker here because the intention of the test is only to
+        // test that DocumentsUi is opened.
+    }
+
+    @Test
+    public void testExtraMimeTypeFilter() throws Exception {
+        final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        intent.addCategory(Intent.CATEGORY_OPENABLE);
+        intent.setType("image/*");
+        intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"video/*", "audio/*"});
+        mActivity.startActivityForResult(intent, REQUEST_CODE);
+        mDevice.waitForIdle();
+        // Should open documentsUi
+        assertThatShowsDocumentsUiButtons();
+
+        // We don't test the result of the picker here because the intention of the test is only to
+        // test that DocumentsUi is opened.
+    }
+
+    @Test
     public void testBrowse_singleSelect() throws Exception {
         final int itemCount = 1;
         List<Pair<Uri, String>> createdImagesData = createImagesAndGetUriAndPath(itemCount,
@@ -135,6 +173,13 @@
         }
     }
 
+    private void assertThatShowsDocumentsUiButtons() {
+        // Assert that "Recent files" header for DocumentsUi shows
+        // Add a short timeout wait for DocumentsUi to show
+        assertThat(new UiObject(new UiSelector().resourceId(sDocumentsUiPackageName
+                + ":id/header_title")).waitForExists(SHORT_TIMEOUT)).isTrue();
+    }
+
     private UiObject findSaveButton() {
         return new UiObject(new UiSelector().resourceId(
                         sDocumentsUiPackageName + ":id/container_save")
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java b/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java
index bd17374..0f61dc7 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java
@@ -29,7 +29,10 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
+
 import android.app.Activity;
+import android.content.ActivityNotFoundException;
 import android.content.ClipData;
 import android.content.Intent;
 import android.net.Uri;
@@ -136,4 +139,21 @@
         assertPersistedGrant(uri, mContext.getContentResolver());
         assertRedactedReadOnlyAccess(uri);
     }
+
+    @Test
+    public void testMimeTypeFilter() throws Exception {
+        final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
+        intent.setType("audio/*");
+        assertThrows(ActivityNotFoundException.class,
+                () -> mActivity.startActivityForResult(intent, REQUEST_CODE));
+    }
+
+    @Test
+    public void testExtraMimeTypeFilter() throws Exception {
+        final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
+        intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"audio/*"});
+        mActivity.startActivityForResult(intent, REQUEST_CODE);
+        final GetResultActivity.Result res = mActivity.getResult();
+        assertThat(res.resultCode).isEqualTo(Activity.RESULT_CANCELED);
+    }
 }
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
index 3d0bcd3..440e472 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
@@ -18,6 +18,7 @@
 
 import static android.photopicker.cts.util.GetContentActivityAliasUtils.clearPackageData;
 import static android.photopicker.cts.util.GetContentActivityAliasUtils.getDocumentsUiPackageName;
+import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertContainsMimeType;
 import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertMimeType;
 import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertPersistedGrant;
 import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertPickerUriFormat;
@@ -578,6 +579,89 @@
         }
     }
 
+    @Test
+    public void testExtraMimeTypeFilter() throws Exception {
+        final int dngVideoCount = 2;
+        // Creates 2 videos with mime type: "video/dng"
+        mUriList.addAll(createDNGVideosAndGetUris(dngVideoCount, mContext.getUserId()));
+
+        final int mp4VideoCount = 3;
+        // Creates 3 videos with mime type: "video/mp4"
+        mUriList.addAll(createVideosAndGetUris(mp4VideoCount, mContext.getUserId()));
+
+        final int imageCount = 4;
+        // Creates 4 images with mime type: "image/dng"
+        mUriList.addAll(createImagesAndGetUris(imageCount, mContext.getUserId()));
+
+        Intent intent = new Intent(mAction);
+        addMultipleSelectionFlag(intent);
+
+        if (Intent.ACTION_GET_CONTENT.equals(intent.getAction())) {
+            intent.setType("*/*");
+        }
+        final String[] mimeTypes = new String[]{"video/dng", "image/dng"};
+        intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
+        launchPhotoPickerForIntent(intent);
+
+        final int totalCount = dngVideoCount + imageCount;
+        final List<UiObject> itemList = findItemList(totalCount);
+        final int itemCount = itemList.size();
+        assertThat(itemCount).isAtLeast(totalCount);
+        for (int i = 0; i < itemCount; i++) {
+            clickAndWait(mDevice, itemList.get(i));
+        }
+
+        clickAndWait(mDevice, findAddButton());
+
+        final ClipData clipData = mActivity.getResult().data.getClipData();
+        assertWithMessage("Expected number of items returned to be: " + itemCount)
+                .that(clipData.getItemCount()).isEqualTo(itemCount);
+        for (int i = 0; i < itemCount; i++) {
+            final Uri uri = clipData.getItemAt(i).getUri();
+            assertPickerUriFormat(uri, mContext.getUserId());
+            assertPersistedGrant(uri, mContext.getContentResolver());
+            assertRedactedReadOnlyAccess(uri);
+            assertContainsMimeType(uri, mimeTypes);
+        }
+    }
+
+    @Test
+    public void testMimeTypeFilterPriority() throws Exception {
+        final int videoCount = 2;
+        mUriList.addAll(createDNGVideosAndGetUris(videoCount, mContext.getUserId()));
+        final int imageCount = 1;
+        mUriList.addAll(createImagesAndGetUris(imageCount, mContext.getUserId()));
+
+        Intent intent = new Intent(mAction);
+        addMultipleSelectionFlag(intent);
+        // setType has lower priority than EXTRA_MIME_TYPES filters.
+        intent.setType("image/*");
+        final String mimeType = "video/dng";
+        intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {mimeType});
+        launchPhotoPickerForIntent(intent);
+
+        // find all items
+        final List<UiObject> itemList = findItemList(-1);
+        final int itemCount = itemList.size();
+        assertThat(itemCount).isAtLeast(videoCount);
+        for (int i = 0; i < itemCount; i++) {
+            clickAndWait(mDevice, itemList.get(i));
+        }
+
+        clickAndWait(mDevice, findAddButton());
+
+        final ClipData clipData = mActivity.getResult().data.getClipData();
+        assertWithMessage("Expected number of items returned to be: " + itemCount)
+                .that(clipData.getItemCount()).isEqualTo(itemCount);
+        for (int i = 0; i < itemCount; i++) {
+            final Uri uri = clipData.getItemAt(i).getUri();
+            assertPickerUriFormat(uri, mContext.getUserId());
+            assertPersistedGrant(uri, mContext.getContentResolver());
+            assertRedactedReadOnlyAccess(uri);
+            assertMimeType(uri, mimeType);
+        }
+    }
+
     private void assertMuteButtonState(UiObject muteButton, boolean isMuted)
             throws UiObjectNotFoundException {
         // We use content description to assert the state of the mute button, there is no other way
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/GetContentActivityAliasUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/GetContentActivityAliasUtils.java
index 493f641..0ccdd3f 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/util/GetContentActivityAliasUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/GetContentActivityAliasUtils.java
@@ -67,6 +67,11 @@
     public static void clearPackageData(String packageName) throws Exception {
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .executeShellCommand("pm clear " + packageName);
+
+        // We should ideally be listening to an effective measure to know if package data was
+        // cleared, like listening to a broadcasts or checking a value. But that information is
+        // very package private and not available.
+        Thread.sleep(500);
     }
 
     public static String getDocumentsUiPackageName() {
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java
index d9749f2..6d86cee 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java
@@ -80,6 +80,12 @@
         assertThat(resultMimeType).isEqualTo(expectedMimeType);
     }
 
+    public static void assertContainsMimeType(Uri uri, String[] expectedMimeTypes) {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final String resultMimeType = context.getContentResolver().getType(uri);
+        assertThat(Arrays.asList(expectedMimeTypes).contains(resultMimeType)).isTrue();
+    }
+
     public static void assertRedactedReadOnlyAccess(Uri uri) throws Exception {
         assertThat(uri).isNotNull();
         final String[] projection = new String[]{ PickerMediaColumns.MIME_TYPE };
diff --git a/tests/app/app/assets/picture_800_by_600.png b/tests/app/app/assets/picture_800_by_600.png
new file mode 100644
index 0000000..dc8f3d4
--- /dev/null
+++ b/tests/app/app/assets/picture_800_by_600.png
Binary files differ
diff --git a/tests/app/src/android/app/cts/NotificationTemplateTest.kt b/tests/app/src/android/app/cts/NotificationTemplateTest.kt
index 6db8aa6..bef1319 100644
--- a/tests/app/src/android/app/cts/NotificationTemplateTest.kt
+++ b/tests/app/src/android/app/cts/NotificationTemplateTest.kt
@@ -32,6 +32,7 @@
 import android.widget.TextView
 import androidx.annotation.ColorInt
 import androidx.test.filters.SmallTest
+import com.android.compatibility.common.util.CddTest;
 import com.google.common.truth.Truth.assertThat
 import org.junit.Assume
 import kotlin.test.assertFailsWith
@@ -283,8 +284,9 @@
         }
     }
 
+    @CddTest(requirement = "3.8.3.1/C-2-1")
     fun testPromoteBigPicture_withBigPictureUriIcon() {
-        val pictureUri = Uri.parse("content://android.app.stubs.assets/picture_400_by_300.png")
+        val pictureUri = Uri.parse("content://android.app.stubs.assets/picture_800_by_600.png")
         val pictureIcon = Icon.createWithContentUri(pictureUri)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                 .setSmallIcon(R.drawable.ic_media_play)
@@ -385,8 +387,9 @@
                 !!.sameAs(picture)).isTrue()
     }
 
+    @CddTest(requirement = "3.8.3.1/C-2-1")
     fun testBigPicture_withBigLargeIcon_withContentUri() {
-        val iconUri = Uri.parse("content://android.app.stubs.assets/picture_400_by_300.png")
+        val iconUri = Uri.parse("content://android.app.stubs.assets/picture_800_by_600.png")
         val icon = Icon.createWithContentUri(iconUri)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                 .setSmallIcon(R.drawable.ic_media_play)
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSessionCtsTestBase.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSessionCtsTestBase.java
index 70b68b4..affdaa8 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSessionCtsTestBase.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSessionCtsTestBase.java
@@ -676,6 +676,7 @@
                                         .build())
                         .build();
         mDb1.setSchemaAsync(new SetSchemaRequest.Builder().addSchemas(schema).build()).get();
+
         // Creates a large batch of Documents, since we have max document size in Framework which is
         // 512KiB, we will create 1KiB * 4000 docs = 4MiB total size > 1MiB binder transaction limit
         char[] chars = new char[1024]; // 1KiB
@@ -3851,4 +3852,104 @@
         documents = convertSearchResultsToDocuments(searchResults);
         assertThat(documents).containsExactly(inEmail1);
     }
+
+    @Test
+    public void testSetSchemaWithIncompatibleNestedSchema() throws Exception {
+        // 1. Set the original schema. This should succeed without any problems.
+        AppSearchSchema originalNestedSchema =
+                new AppSearchSchema.Builder("TypeA")
+                        .addProperty(
+                                new StringPropertyConfig.Builder("prop1")
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .build())
+                        .build();
+        SetSchemaRequest originalRequest =
+                new SetSchemaRequest.Builder().addSchemas(originalNestedSchema).build();
+        mDb1.setSchemaAsync(originalRequest).get();
+
+        // 2. Set a new schema with a new type that refers to "TypeA" and an incompatible change to
+        // "TypeA". This should fail.
+        AppSearchSchema newNestedSchema =
+                new AppSearchSchema.Builder("TypeA")
+                        .addProperty(
+                                new StringPropertyConfig.Builder("prop1")
+                                        .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+                                        .build())
+                        .build();
+        AppSearchSchema newSchema =
+                new AppSearchSchema.Builder("TypeB")
+                        .addProperty(
+                                new AppSearchSchema.DocumentPropertyConfig.Builder("prop2", "TypeA")
+                                        .build())
+                        .build();
+        final SetSchemaRequest newRequest =
+                new SetSchemaRequest.Builder().addSchemas(newNestedSchema, newSchema).build();
+        Throwable throwable =
+                assertThrows(ExecutionException.class, () -> mDb1.setSchemaAsync(newRequest).get())
+                        .getCause();
+        assertThat(throwable).isInstanceOf(AppSearchException.class);
+        AppSearchException exception = (AppSearchException) throwable;
+        assertThat(exception.getResultCode()).isEqualTo(RESULT_INVALID_SCHEMA);
+        assertThat(exception).hasMessageThat().contains("Schema is incompatible.");
+        assertThat(exception).hasMessageThat().contains("Incompatible types: {TypeA}");
+
+        // 3. Now set that same set of schemas but with forceOverride=true. This should succeed.
+        SetSchemaRequest newRequestForced =
+                new SetSchemaRequest.Builder()
+                        .addSchemas(newNestedSchema, newSchema)
+                        .setForceOverride(true)
+                        .build();
+        mDb1.setSchemaAsync(newRequestForced).get();
+    }
+
+    @Test
+    public void testEmojiSnippet() throws Exception {
+        // Schema registration
+        mDb1.setSchemaAsync(
+                        new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build())
+                .get();
+
+        // String:     "Luca Brasi sleeps with the 🐟🐟🐟."
+        //              ^    ^     ^      ^    ^   ^ ^  ^ ^
+        // UTF8 idx:    0    5     11     18   23 27 3135 39
+        // UTF16 idx:   0    5     11     18   23 27 2931 33
+        // Breaks into segments: "Luca", "Brasi", "sleeps", "with", "the", "🐟", "🐟"
+        // and "🐟".
+        // Index a document to instance 1.
+        String sicilianMessage = "Luca Brasi sleeps with the 🐟🐟🐟.";
+        AppSearchEmail inEmail1 =
+                new AppSearchEmail.Builder("namespace", "uri1").setBody(sicilianMessage).build();
+        checkIsBatchResultSuccess(
+                mDb1.putAsync(
+                        new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1).build()));
+
+        AppSearchEmail inEmail2 =
+                new AppSearchEmail.Builder("namespace", "uri2")
+                        .setBody("Some other content.")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.putAsync(
+                        new PutDocumentsRequest.Builder().addGenericDocuments(inEmail2).build()));
+
+        // Query for "🐟"
+        SearchResultsShim searchResults =
+                mDb1.search(
+                        "🐟",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+                                .setSnippetCount(1)
+                                .setSnippetCountPerProperty(1)
+                                .build());
+        List<SearchResult> page = searchResults.getNextPageAsync().get();
+        assertThat(page).hasSize(1);
+        assertThat(page.get(0).getGenericDocument()).isEqualTo(inEmail1);
+        List<SearchResult.MatchInfo> matches = page.get(0).getMatchInfos();
+        assertThat(matches).hasSize(1);
+        assertThat(matches.get(0).getPropertyPath()).isEqualTo("body");
+        assertThat(matches.get(0).getFullText()).isEqualTo(sicilianMessage);
+        assertThat(matches.get(0).getExactMatch()).isEqualTo("🐟");
+        if (mDb1.getFeatures().isFeatureSupported(Features.SEARCH_RESULT_MATCH_INFO_SUBMATCH)) {
+            assertThat(matches.get(0).getSubmatch()).isEqualTo("🐟");
+        }
+    }
 }
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java
index 5dd2eac..0bfa693 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java
@@ -576,6 +576,30 @@
     }
 
     @Test
+    public void testNestedProperties_buildBlankPaths() {
+        Exception e =
+                assertThrows(
+                        IllegalArgumentException.class,
+                        () ->
+                                new GenericDocument.Builder<>("namespace", "id1", "schema1")
+                                        .setPropertyString("", "foo"));
+        assertThat(e.getMessage()).isEqualTo("Property name cannot be blank.");
+
+        e =
+                assertThrows(
+                        IllegalArgumentException.class,
+                        () ->
+                                new GenericDocument.Builder<>("namespace", "id1", "schema1")
+                                        .setPropertyDocument(
+                                                "propDoc",
+                                                new GenericDocument.Builder<>(
+                                                                "namespace", "id2", "schema1")
+                                                        .setPropertyString("", "Bat", "Hawk")
+                                                        .build()));
+        assertThat(e.getMessage()).isEqualTo("Property name cannot be blank.");
+    }
+
+    @Test
     public void testNestedProperties_invalidPaths() {
         GenericDocument doc =
                 new GenericDocument.Builder<>("namespace", "id1", "schema1")
@@ -592,25 +616,28 @@
                                         .build())
                         .build();
 
-        // Some paths are invalid because they don't apply to the given document --- these should
+        // These paths are invalid because they don't apply to the given document --- these should
         // return null. It's not the querier's fault.
         assertThat(doc.getPropertyStringArray("propString.propInts")).isNull();
         assertThat(doc.getPropertyStringArray("propDocs.propFoo")).isNull();
         assertThat(doc.getPropertyStringArray("propDocs.propNestedString.propFoo")).isNull();
+    }
 
-        // Some paths are invalid because they are malformed. These throw an exception --- the
-        // querier shouldn't provide such paths.
-        assertThrows(
-                IllegalArgumentException.class, () -> doc.getPropertyStringArray("propString[0"));
-        assertThrows(
-                IllegalArgumentException.class, () -> doc.getPropertyStringArray("propString[0.]"));
-        assertThrows(
-                IllegalArgumentException.class,
-                () -> doc.getPropertyStringArray("propString[banana]"));
-        assertThrows(
-                IllegalArgumentException.class, () -> doc.getPropertyStringArray("propString[-1]"));
-        assertThrows(
-                IllegalArgumentException.class, () -> doc.getPropertyStringArray("propDocs[0]cat"));
+    @Test
+    public void testNestedProperties_arrayTypesInvalidPath() {
+        GenericDocument doc = new GenericDocument.Builder<>("namespace", "id1", "schema1").build();
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyString("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyDocument("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyBoolean("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyDouble("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyLong("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyBytes("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyStringArray("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyDocumentArray("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyBooleanArray("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyDoubleArray("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyLongArray("."));
+        assertThrows(IllegalArgumentException.class, () -> doc.getPropertyBytesArray("."));
     }
 
     @Test
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java
index 71822ca..47337ca 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java
@@ -1641,6 +1641,11 @@
 
     @Test
     public void testAddObserver_schemaChange_added() throws Exception {
+        assumeTrue(
+                mDb1.getFeatures()
+                        .isFeatureSupported(
+                                Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK));
+
         // Register an observer
         TestObserverCallback observer = new TestObserverCallback();
         mGlobalSearchSession.registerObserverCallback(
@@ -1688,6 +1693,11 @@
 
     @Test
     public void testAddObserver_schemaChange_removed() throws Exception {
+        assumeTrue(
+                mDb1.getFeatures()
+                        .isFeatureSupported(
+                                Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK));
+
         // Add a schema type
         mDb1.setSchemaAsync(
                         new SetSchemaRequest.Builder()
@@ -1723,6 +1733,11 @@
 
     @Test
     public void testAddObserver_schemaChange_contents() throws Exception {
+        assumeTrue(
+                mDb1.getFeatures()
+                        .isFeatureSupported(
+                                Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK));
+
         // Add a schema
         mDb1.setSchemaAsync(
                         new SetSchemaRequest.Builder()
@@ -1794,6 +1809,11 @@
 
     @Test
     public void testAddObserver_schemaChange_contents_skipBySpec() throws Exception {
+        assumeTrue(
+                mDb1.getFeatures()
+                        .isFeatureSupported(
+                                Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK));
+
         // Add a schema
         mDb1.setSchemaAsync(
                         new SetSchemaRequest.Builder()
@@ -1862,6 +1882,11 @@
 
     @Test
     public void testRegisterObserver_schemaMigration() throws Exception {
+        assumeTrue(
+                mDb1.getFeatures()
+                        .isFeatureSupported(
+                                Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK));
+
         // Add a schema with two types
         mDb1.setSchemaAsync(
                         new SetSchemaRequest.Builder()
diff --git a/tests/camera/Android.bp b/tests/camera/Android.bp
index aae58c6..c2334fc 100644
--- a/tests/camera/Android.bp
+++ b/tests/camera/Android.bp
@@ -65,6 +65,7 @@
         "truth-prebuilt",
         "androidx.heifwriter_heifwriter",
         "androidx.test.rules",
+        "MediaPerformanceClassCommon",
     ],
     jni_libs: [
         "libctscamera2_jni",
diff --git a/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java b/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java
index feb5567..772e7a5 100644
--- a/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java
+++ b/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java
@@ -36,6 +36,7 @@
 import android.hardware.camera2.TotalCaptureResult;
 import android.media.Image;
 import android.media.ImageReader;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.test.AndroidTestCase;
@@ -210,8 +211,9 @@
      * Version.MEDIA_PERFORMANCE_CLASS
      */
     public void testSPerfClassJpegSizes() throws Exception {
-        boolean isSPerfClass = CameraTestUtils.isSPerfClass();
-        if (!isSPerfClass) {
+        final boolean isAtLeastSPerfClass =
+                (Build.VERSION.MEDIA_PERFORMANCE_CLASS >= Build.VERSION_CODES.S);
+        if (!isAtLeastSPerfClass) {
             return;
         }
 
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 6af7758..c9d0314 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -55,6 +55,10 @@
 import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.cts.helpers.CameraUtils;
+import android.mediapc.cts.common.Requirement;
+import android.mediapc.cts.common.RequiredMeasurement;
+import android.mediapc.cts.common.RequirementConstants;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.media.CamcorderProfile;
 import android.media.ImageReader;
 import android.os.Build;
@@ -74,15 +78,11 @@
 
 import androidx.test.rule.ActivityTestRule;
 
-import androidx.test.InstrumentationRegistry;
-
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
 
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -92,12 +92,10 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.function.BiPredicate;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import static android.hardware.camera2.cts.CameraTestUtils.MPC_REPORT_LOG_NAME;
-import static android.hardware.camera2.cts.CameraTestUtils.MPC_STREAM_NAME;
-
 /**
  * Extended tests for static camera characteristics.
  */
@@ -113,6 +111,9 @@
      */
     private static final int MIN_ALLOWABLE_WHITELEVEL = 32; // must have sensor bit depth > 5
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     private List<CameraCharacteristics> mCharacteristics;
 
     private static final Size FULLHD = new Size(1920, 1080);
@@ -131,10 +132,6 @@
     private static final long PREVIEW_RUN_MS = 500;
     private static final long FRAME_DURATION_30FPS_NSEC = (long) 1e9 / 30;
 
-    private static final long MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION = 12000000;
-    private static final long MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION = 5000000;
-    private static final long MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION = 4000000;
-
     private static final long MIN_UHR_SENSOR_RESOLUTION = 24000000;
     /*
      * HW Levels short hand
@@ -2857,28 +2854,70 @@
     }
 
     /**
-     * Update performance class level based on condition
-     *
-     * @param condition whether the condition is met for passLevel
-     * @param passLevel the highest performance class level when condition is true
-     * @param failLevel the performance class when condition is false
+     * Camera hardware level requirement for Media Performance Class
      */
-    private int updatePerfClassLevel(boolean condition, int passLevel, int failLevel) {
-        return condition ? passLevel : failLevel;
-    }
+    public static class PrimaryCameraHwLevelReq extends Requirement {
+        private static final String TAG = PrimaryCameraHwLevelReq.class.getSimpleName();
 
-    /**
-     * Update perf class level based on meetSPerfClass and meetRPerfClass.
-     */
-    private int updatePerfClassLevelRS(boolean meetSPerfClass, boolean meetRPerfClass,
-            int perfClassLevel) {
-        if (!meetRPerfClass) {
-            return CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-        } else if (!meetSPerfClass &&
-                perfClassLevel > CameraTestUtils.PERFORMANCE_CLASS_R) {
-            return Math.min(CameraTestUtils.PERFORMANCE_CLASS_R, perfClassLevel);
+        /**
+         * Creates a >= predicate for camera hardware level
+         */
+        private static BiPredicate<Integer, Integer> camHwLevelGte() {
+            return new BiPredicate<Integer, Integer>() {
+                @Override
+                public boolean test(Integer actual, Integer expected) {
+                    return StaticMetadata.hardwareLevelPredicate(actual, expected);
+                }
+
+                @Override
+                public String toString() {
+                    return "Camera Hardware Level Greater than or equal to";
+                }
+            };
         }
-        return perfClassLevel;
+        private static final BiPredicate<Integer, Integer> CAM_HW_LEVEL_GTE = camHwLevelGte();
+        private PrimaryCameraHwLevelReq(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setPrimaryRearCameraHwlLevel(Integer hwLevel) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_HWL_LEVEL, hwLevel);
+        }
+
+        public void setPrimaryFrontCameraHwlLevel(Integer hwLevel) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_HWL_LEVEL, hwLevel);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-3] MUST support android.info.supportedHardwareLevel property as FULL or
+         * better for back primary and LIMITED or better for front primary camera.
+         */
+        public static PrimaryCameraHwLevelReq createPrimaryCameraHwLevelReq() {
+            RequiredMeasurement<Integer> rearCameraHwlLevel = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.REAR_CAMERA_HWL_LEVEL)
+                .setPredicate(CAM_HW_LEVEL_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R,
+                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+                .addRequiredValue(Build.VERSION_CODES.S,
+                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU,
+                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+                .build();
+            RequiredMeasurement<Integer> frontCameraHwlLevel = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_HWL_LEVEL)
+                .setPredicate(CAM_HW_LEVEL_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R,
+                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED)
+                .addRequiredValue(Build.VERSION_CODES.S,
+                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU,
+                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+                .build();
+            return new PrimaryCameraHwLevelReq(RequirementConstants.R7_5__H_1_3,
+                    rearCameraHwlLevel, frontCameraHwlLevel);
+        }
     }
 
     /**
@@ -2886,34 +2925,47 @@
      * in CDD camera section 7.5
      */
     @Test
-    @CddTest(requirement = "7.5/H-1-1,H-1-2,H-1-3,H-1-4,H-1-8,H-1-9,H-1-10,H-1-11,H-1-12,H-1-13,H-1-14")
+    @CddTest(requirements = {
+            "2.2.7.2/7.5/H-1-1",
+            "2.2.7.2/7.5/H-1-2",
+            "2.2.7.2/7.5/H-1-3",
+            "2.2.7.2/7.5/H-1-4",
+            "2.2.7.2/7.5/H-1-8",
+            "2.2.7.2/7.5/H-1-9",
+            "2.2.7.2/7.5/H-1-10",
+            "2.2.7.2/7.5/H-1-11",
+            "2.2.7.2/7.5/H-1-12",
+            "2.2.7.2/7.5/H-1-13",
+            "2.2.7.2/7.5/H-1-14"})
     public void testCameraPerfClassCharacteristics() throws Exception {
         if (mAdoptShellPerm) {
             // Skip test for system camera. Performance class is only applicable for public camera
             // ids.
             return;
         }
-        boolean assertRPerfClass = CameraTestUtils.isRPerfClass();
-        boolean assertSPerfClass = CameraTestUtils.isSPerfClass();
-        boolean assertTPerfClass = CameraTestUtils.isTPerfClass();
-        boolean assertPerfClass = (assertRPerfClass || assertSPerfClass || assertTPerfClass);
-
-        // R & S Performance Class
-        int perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH13 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH14 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH18 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-
-        // T Performance Class
-        int perfClassLevelH19 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH110 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH111 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH112 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH113 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH114 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-
-        DeviceReportLog reportLog = new DeviceReportLog(MPC_REPORT_LOG_NAME, MPC_STREAM_NAME);
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.PrimaryCameraRequirement primaryRearReq =
+                pce.addPrimaryRearCameraReq();
+        PerformanceClassEvaluator.PrimaryCameraRequirement primaryFrontReq =
+                pce.addPrimaryFrontCameraReq();
+        PrimaryCameraHwLevelReq hwLevelReq = pce.addRequirement(
+                PrimaryCameraHwLevelReq.createPrimaryCameraHwLevelReq());
+        PerformanceClassEvaluator.CameraTimestampSourceRequirement timestampSourceReq =
+                pce.addR7_5__H_1_4();
+        PerformanceClassEvaluator.CameraRawRequirement rearRawReq =
+                pce.addR7_5__H_1_8();
+        PerformanceClassEvaluator.Camera240FpsRequirement hfrReq =
+                pce.addR7_5__H_1_9();
+        PerformanceClassEvaluator.UltraWideZoomRatioRequirement ultrawideZoomRatioReq =
+                pce.addR7_5__H_1_10();
+        PerformanceClassEvaluator.ConcurrentRearFrontRequirement concurrentRearFrontReq =
+                pce.addR7_5__H_1_11();
+        PerformanceClassEvaluator.PreviewStabilizationRequirement previewStabilizationReq =
+                pce.addR7_5__H_1_12();
+        PerformanceClassEvaluator.LogicalMultiCameraRequirement logicalMultiCameraReq =
+                pce.addR7_5__H_1_13();
+        PerformanceClassEvaluator.StreamUseCaseRequirement streamUseCaseReq =
+                pce.addR7_5__H_1_14();
 
         String primaryRearId = null;
         String primaryFrontId = null;
@@ -2940,42 +2992,29 @@
             List<Size> videoSizes = CameraTestUtils.getSupportedVideoSizes(cameraId,
                     mCameraManager, null /*bound*/);
 
+            Integer timestampSource = c.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE);
             if (isPrimaryRear) {
                 primaryRearId = cameraId;
-                if (sensorResolution < MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION) {
-                    mCollector.expectTrue("Primary rear camera resolution should be at least " +
-                            MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION + " pixels, is "+
-                            sensorResolution, !assertPerfClass);
-                    perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-                }
-                reportLog.addValue("rear camera resolution", sensorResolution,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
+                primaryRearReq.setPrimaryCameraSupported(true);
+                primaryRearReq.setResolution(sensorResolution);
+                hwLevelReq.setPrimaryRearCameraHwlLevel(staticInfo.getHardwareLevelChecked());
+                timestampSourceReq.setRearCameraTimestampSource(timestampSource);
 
                 // 4K @ 30fps
                 boolean supportUHD = videoSizes.contains(UHD);
                 boolean supportDC4K = videoSizes.contains(DC4K);
-                reportLog.addValue("rear camera 4k support", supportUHD | supportDC4K,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
-                if (!supportUHD && !supportDC4K) {
-                    mCollector.expectTrue("Primary rear camera should support 4k video recording",
-                            !assertPerfClass);
-                    perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-                } else {
+                boolean support4K = (supportUHD || supportDC4K);
+                primaryRearReq.setVideoSizeReqSatisfied(support4K);
+                if (support4K) {
                     long minFrameDuration = config.getOutputMinFrameDuration(
                             android.media.MediaRecorder.class, supportDC4K ? DC4K : UHD);
-                    reportLog.addValue("rear camera 4k frame duration", minFrameDuration,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
-                    if (minFrameDuration >= (1e9 / 29.9)) {
-                        mCollector.expectTrue("Primary rear camera should support 4k video @ 30fps",
-                                !assertPerfClass);
-                        perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-                    }
+                    primaryRearReq.setVideoFps(1e9 / minFrameDuration);
+                } else {
+                    primaryRearReq.setVideoFps(-1);
                 }
 
                 // H-1-9
                 boolean supportHighSpeed = staticInfo.isCapabilitySupported(CONSTRAINED_HIGH_SPEED);
-                mCollector.expectTrue("Primary rear camera should support high speed recording",
-                        !assertTPerfClass || supportHighSpeed);
                 boolean support240Fps = false;
                 if (supportHighSpeed) {
                     Size[] availableHighSpeedSizes = config.getHighSpeedVideoSizes();
@@ -2995,101 +3034,31 @@
                             break;
                         }
                     }
-                    mCollector.expectTrue("Primary rear camera should support HD or FULLHD @ 240",
-                            !assertTPerfClass || support240Fps);
                 }
-                perfClassLevelH19 = updatePerfClassLevel(support240Fps,
-                        perfClassLevelH19, CameraTestUtils.PERFORMANCE_CLASS_S);
-                reportLog.addValue("rear camera 720p/1080p @ 240fps support", support240Fps,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
+                hfrReq.setRear240FpsSupported(support240Fps);
             } else {
                 primaryFrontId = cameraId;
-                if (sensorResolution < MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION) {
-                    mCollector.expectTrue("Primary front camera resolution should be at least "
-                            + MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION + " pixels, is "
-                            + sensorResolution, !(assertSPerfClass || assertTPerfClass));
-                    perfClassLevelH12 = Math.min(
-                            perfClassLevelH12, CameraTestUtils.PERFORMANCE_CLASS_R);
-                }
-                if (sensorResolution < MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION) {
-                    mCollector.expectTrue("Primary front camera resolution should be at least " +
-                            MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION + " pixels, is "+
-                            sensorResolution, !assertRPerfClass);
-                    perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-                }
-                reportLog.addValue("front camera resolution", sensorResolution,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
+                primaryFrontReq.setPrimaryCameraSupported(true);
+                primaryFrontReq.setResolution(sensorResolution);
+                hwLevelReq.setPrimaryFrontCameraHwlLevel(staticInfo.getHardwareLevelChecked());
+                timestampSourceReq.setFrontCameraTimestampSource(timestampSource);
 
                 // 1080P @ 30fps
                 boolean supportFULLHD = videoSizes.contains(FULLHD);
-                reportLog.addValue("front camera 1080p support", supportFULLHD,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
-                if (!supportFULLHD) {
-                    mCollector.expectTrue(
-                            "Primary front camera should support 1080P video recording",
-                            !assertPerfClass);
-                    perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-                } else {
+                primaryFrontReq.setVideoSizeReqSatisfied(supportFULLHD);
+                if (supportFULLHD) {
                     long minFrameDuration = config.getOutputMinFrameDuration(
                             android.media.MediaRecorder.class, FULLHD);
-                    if (minFrameDuration >= (1e9 / 29.9)) {
-                        mCollector.expectTrue(
-                                "Primary front camera should support 1080P video @ 30fps",
-                                !assertPerfClass);
-                        perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-                    }
-                    reportLog.addValue("front camera 1080p frame duration", minFrameDuration,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
+                    primaryFrontReq.setVideoFps(1e9 / minFrameDuration);
+                } else {
+                    primaryFrontReq.setVideoFps(-1);
                 }
             }
 
-            String facingString = isPrimaryRear ? "rear" : "front";
-            // H-1-3
-            if (assertTPerfClass || assertSPerfClass || (assertRPerfClass && isPrimaryRear)) {
-                mCollector.expectTrue("Primary " + facingString +
-                        " camera should be at least FULL, but is " +
-                        toStringHardwareLevel(staticInfo.getHardwareLevelChecked()),
-                        staticInfo.isHardwareLevelAtLeastFull());
-            } else if (assertRPerfClass) {
-                mCollector.expectTrue("Primary " + facingString +
-                        " camera should be at least LIMITED, but is " +
-                        toStringHardwareLevel(staticInfo.getHardwareLevelChecked()),
-                        staticInfo.isHardwareLevelAtLeastLimited());
-            }
-
-            reportLog.addValue(facingString + " camera hardware level",
-                    staticInfo.getHardwareLevelChecked(), ResultType.NEUTRAL, ResultUnit.NONE);
-            if (isPrimaryRear) {
-                perfClassLevelH13 = updatePerfClassLevel(staticInfo.isHardwareLevelAtLeastFull(),
-                        perfClassLevelH13, CameraTestUtils.PERFORMANCE_CLASS_NOT_MET);
-            } else {
-                perfClassLevelH13 = updatePerfClassLevelRS(staticInfo.isHardwareLevelAtLeastFull(),
-                        staticInfo.isHardwareLevelAtLeastLimited(), perfClassLevelH13);
-            }
-
-            // H-1-4
-            Integer timestampSource = c.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE);
-            reportLog.addValue(facingString + " timestampSource",
-                    timestampSource, ResultType.NEUTRAL, ResultUnit.NONE);
-            boolean realtimeTimestamp = (timestampSource != null &&
-                    timestampSource.equals(CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME));
-            mCollector.expectTrue(
-                    "Primary " + facingString + " camera should support real-time timestamp source",
-                    !assertPerfClass || realtimeTimestamp);
-            perfClassLevelH14 = updatePerfClassLevel(realtimeTimestamp, perfClassLevelH14,
-                    CameraTestUtils.PERFORMANCE_CLASS_NOT_MET);
-
             // H-1-8
             if (isPrimaryRear) {
                 boolean supportRaw = staticInfo.isCapabilitySupported(RAW);
-                reportLog.addValue(facingString + " camera raw support",
-                        supportRaw, ResultType.NEUTRAL, ResultUnit.NONE);
-                if (assertSPerfClass || assertTPerfClass) {
-                    mCollector.expectTrue("Primary rear camera should support RAW capability",
-                            supportRaw);
-                }
-                perfClassLevelH18 = updatePerfClassLevel(supportRaw, perfClassLevelH18,
-                        CameraTestUtils.PERFORMANCE_CLASS_R);
+                rearRawReq.setRearRawSupported(supportRaw);
             }
 
             // H-1-10
@@ -3098,96 +3067,76 @@
             Range<Float> zoomRatioRange = staticInfo.getZoomRatioRangeChecked();
             boolean meetH110 = (primaryToMaxFovRatio >= 1.0f - FOV_THRESHOLD)
                     || (zoomRatioRange.getLower() < 1.0f - FOV_THRESHOLD);
-            mCollector.expectTrue("Primary " + facingString + " camera must support zoomRatio < "
-                    + "1.0f if there is an ultrawide lens with the same facing",
-                    !assertTPerfClass || meetH110);
-            perfClassLevelH110 = updatePerfClassLevel(meetH110, perfClassLevelH110,
-                    CameraTestUtils.PERFORMANCE_CLASS_S);
-            reportLog.addValue(facingString + " camera supports maximum FOV using zoom ratio",
-                    meetH110, ResultType.NEUTRAL, ResultUnit.NONE);
+            if (isPrimaryRear) {
+                ultrawideZoomRatioReq.setRearUltraWideZoomRatioReqMet(meetH110);
+            } else {
+                ultrawideZoomRatioReq.setFrontUltraWideZoomRatioReqMet(meetH110);
+            }
 
             // H-1-12
-            boolean meetH112 = staticInfo.isPreviewStabilizationSupported();
-            mCollector.expectTrue("Primary " + facingString + " camera must support preview "
-                    + "stabilization", !assertTPerfClass || meetH112);
-            perfClassLevelH112 = updatePerfClassLevel(meetH112, perfClassLevelH112,
-                    CameraTestUtils.PERFORMANCE_CLASS_S);
-            reportLog.addValue(facingString + " camera preview stabilization", meetH112,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
+            boolean previewStab = staticInfo.isPreviewStabilizationSupported();
+            if (isPrimaryRear) {
+                previewStabilizationReq.setRearPreviewStabilizationSupported(previewStab);
+            } else {
+                previewStabilizationReq.setFrontPreviewStabilizationSupported(previewStab);
+            }
 
             // H-1-13
             int facing = staticInfo.getLensFacingChecked();
             int numOfPhysicalRgbCameras = getNumberOfRgbPhysicalCameras(facing);
-            boolean meetH113 = (numOfPhysicalRgbCameras <= 1) || staticInfo.isLogicalMultiCamera();
-            mCollector.expectTrue("Primary " + facingString + " camera must be LOGICAL_MULTI_CAMERA"
-                    + " in case of multiple RGB cameras with same facing",
-                    !assertTPerfClass || meetH113);
-            perfClassLevelH113 = updatePerfClassLevel(meetH113, perfClassLevelH113,
-                    CameraTestUtils.PERFORMANCE_CLASS_S);
-            reportLog.addValue(facingString + " camera is LOGICAL_MULTI_CAMERA in case of multiple "
-                    + "RGB cameras with same facing", meetH113, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
+            boolean logicalMultiCameraReqMet =
+                    (numOfPhysicalRgbCameras <= 1) || staticInfo.isLogicalMultiCamera();
+            if (isPrimaryRear) {
+                logicalMultiCameraReq.setRearLogicalMultiCameraReqMet(logicalMultiCameraReqMet);
+            } else {
+                logicalMultiCameraReq.setFrontLogicalMultiCameraReqMet(logicalMultiCameraReqMet);
+            }
 
             // H-1-14
-            boolean meetH114 = staticInfo.isStreamUseCaseSupported();
-            mCollector.expectTrue("Primary " + facingString + " camera must support stream "
-                    + "use case", !assertTPerfClass || meetH114);
-            perfClassLevelH114 = updatePerfClassLevel(meetH114, perfClassLevelH114,
-                    CameraTestUtils.PERFORMANCE_CLASS_S);
-            reportLog.addValue(facingString + " camera stream use case", meetH114,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
+            boolean streamUseCaseSupported = staticInfo.isStreamUseCaseSupported();
+            if (isPrimaryRear) {
+                streamUseCaseReq.setRearStreamUseCaseSupported(streamUseCaseSupported);
+            } else {
+                streamUseCaseReq.setFrontStreamUseCaseSupported(streamUseCaseSupported);
+            }
         }
-        HashSet<String> primaryCameras = new HashSet<String>();
+
         if (primaryRearId == null) {
-            mCollector.expectTrue("There must be a primary rear camera for performance class.",
-                    !assertPerfClass);
-            perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-        } else {
-            primaryCameras.add(primaryRearId);
+            primaryRearReq.setPrimaryCameraSupported(false);
+            primaryRearReq.setResolution(-1);
+            primaryRearReq.setVideoSizeReqSatisfied(false);
+            primaryRearReq.setVideoFps(-1);
+            hwLevelReq.setPrimaryRearCameraHwlLevel(-1);
+            timestampSourceReq.setRearCameraTimestampSource(
+                    CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN);
+            rearRawReq.setRearRawSupported(false);
+            hfrReq.setRear240FpsSupported(false);
+            ultrawideZoomRatioReq.setRearUltraWideZoomRatioReqMet(false);
+            previewStabilizationReq.setRearPreviewStabilizationSupported(false);
+            logicalMultiCameraReq.setRearLogicalMultiCameraReqMet(false);
+            streamUseCaseReq.setRearStreamUseCaseSupported(false);
         }
         if (primaryFrontId == null) {
-            mCollector.expectTrue("There must be a primary front camera for performance class.",
-                    !assertPerfClass);
-            perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-        } else {
-            primaryCameras.add(primaryFrontId);
+            primaryFrontReq.setPrimaryCameraSupported(false);
+            primaryFrontReq.setResolution(-1);
+            primaryFrontReq.setVideoSizeReqSatisfied(false);
+            primaryFrontReq.setVideoFps(-1);
+            hwLevelReq.setPrimaryFrontCameraHwlLevel(-1);
+            timestampSourceReq.setFrontCameraTimestampSource(
+                    CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN);
+            ultrawideZoomRatioReq.setFrontUltraWideZoomRatioReqMet(false);
+            previewStabilizationReq.setFrontPreviewStabilizationSupported(false);
+            logicalMultiCameraReq.setFrontLogicalMultiCameraReqMet(false);
+            streamUseCaseReq.setFrontStreamUseCaseSupported(false);
         }
 
         // H-1-11
         Set<Set<String>> concurrentCameraIds = mCameraManager.getConcurrentCameraIds();
+        Set<String> primaryCameras = new HashSet<>(Arrays.asList(primaryRearId, primaryFrontId));
         boolean supportPrimaryFrontBack = concurrentCameraIds.contains(primaryCameras);
-        mCollector.expectTrue("Concurrent primary front and primary back streaming must be "
-                + "supported", !assertTPerfClass || supportPrimaryFrontBack);
-        perfClassLevelH111 = updatePerfClassLevel(supportPrimaryFrontBack,
-                perfClassLevelH111, CameraTestUtils.PERFORMANCE_CLASS_S);
-        reportLog.addValue("concurrent front back support", supportPrimaryFrontBack,
-                 ResultType.NEUTRAL, ResultUnit.NONE);
+        concurrentRearFrontReq.setConcurrentRearFrontSupported(supportPrimaryFrontBack);
 
-        reportLog.addValue("Version", "0.0.1", ResultType.NEUTRAL, ResultUnit.NONE);
-        final String PERF_CLASS_REQ_NUM_PREFIX = "2.2.7.2/7.5/";
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-1",
-                perfClassLevelH11, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-2",
-                perfClassLevelH12, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-3",
-                perfClassLevelH13, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-4",
-                perfClassLevelH14, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-8",
-                perfClassLevelH18, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-9",
-                perfClassLevelH19, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-10",
-                perfClassLevelH110, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-11",
-                perfClassLevelH111, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-12",
-                perfClassLevelH112, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-13",
-                perfClassLevelH113, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-14",
-                perfClassLevelH114, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.submit(InstrumentationRegistry.getInstrumentation());
+        pce.submitAndCheck();
     }
 
     /**
diff --git a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
index 3c88a3a..c9c28ea 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
@@ -1234,8 +1234,13 @@
 
                         mOutMediaFileName = mDebugFileNameBase + "/test_cslowMo_video_" +
                             captureRate + "fps_" + id + "_" + size.toString() + ".mp4";
-                        Log.v(TAG, "previewFrameRate:" + previewFrameRate);
-                        prepareRecording(size, previewFrameRate, captureRate);
+
+                        // b/239101664 It appears that video frame rates higher than 30 fps may not
+                        // trigger slow motion recording consistently.
+                        int videoFrameRate = previewFrameRate > VIDEO_FRAME_RATE ?
+                                VIDEO_FRAME_RATE : previewFrameRate;
+                        Log.v(TAG, "videoFrameRate:" + videoFrameRate);
+                        prepareRecording(size, videoFrameRate, captureRate);
 
                         SystemClock.sleep(PREVIEW_DURATION_MS);
 
@@ -1243,7 +1248,7 @@
 
                         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
                         // Start recording
-                        startSlowMotionRecording(/*useMediaRecorder*/true, previewFrameRate,
+                        startSlowMotionRecording(/*useMediaRecorder*/true, videoFrameRate,
                                 captureRate, fpsRange, resultListener,
                                 /*useHighSpeedSession*/true);
 
@@ -1256,7 +1261,7 @@
                         startConstrainedPreview(fpsRange, previewResultListener);
 
                         // Convert number of frames camera produced into the duration in unit of ms.
-                        float frameDurationMs = 1000.0f / previewFrameRate;
+                        float frameDurationMs = 1000.0f / videoFrameRate;
                         float durationMs = resultListener.getTotalNumFrames() * frameDurationMs;
 
                         // Validation.
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 e8d6168..4a86b49 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -142,8 +142,6 @@
 
     public static final String OFFLINE_CAMERA_ID = "offline_camera_id";
     public static final String REPORT_LOG_NAME = "CtsCameraTestCases";
-    public static final String MPC_REPORT_LOG_NAME = "MediaPerformanceClassLogs";
-    public static final String MPC_STREAM_NAME = "CameraCts";
 
     private static final int EXIF_DATETIME_LENGTH = 19;
     private static final int EXIF_DATETIME_ERROR_MARGIN_SEC = 60;
@@ -3815,33 +3813,6 @@
         return zoomRatios;
     }
 
-    public static final int PERFORMANCE_CLASS_NOT_MET = 0;
-    public static final int PERFORMANCE_CLASS_R = Build.VERSION_CODES.R;
-    public static final int PERFORMANCE_CLASS_S = Build.VERSION_CODES.R + 1;
-    public static final int PERFORMANCE_CLASS_T = Build.VERSION_CODES.S + 2;
-    public static final int PERFORMANCE_CLASS_CURRENT = PERFORMANCE_CLASS_T;
-
-    /**
-     * Check whether this mobile device is R performance class as defined in CDD
-     */
-    public static boolean isRPerfClass() {
-        return Build.VERSION.MEDIA_PERFORMANCE_CLASS == PERFORMANCE_CLASS_R;
-    }
-
-    /**
-     * Check whether this mobile device is S performance class as defined in CDD
-     */
-    public static boolean isSPerfClass() {
-        return Build.VERSION.MEDIA_PERFORMANCE_CLASS == PERFORMANCE_CLASS_S;
-    }
-
-    /**
-     * Check whether this mobile device is T performance class as defined in CDD
-     */
-    public static boolean isTPerfClass() {
-        return Build.VERSION.MEDIA_PERFORMANCE_CLASS == PERFORMANCE_CLASS_T;
-    }
-
     /**
      * Check whether a camera Id is a primary rear facing camera
      */
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index fc8c4db..f188685 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -229,6 +229,13 @@
      * at least the desired one (but could be higher)
      */
     public boolean isHardwareLevelAtLeast(int level) {
+        int deviceLevel = getHardwareLevelChecked();
+
+        return hardwareLevelPredicate(deviceLevel, level);
+    }
+
+    // Return true if level1 is at least level2
+    public static boolean hardwareLevelPredicate(int level1, int level2) {
         final int[] sortedHwLevels = {
             CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
             CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL,
@@ -236,19 +243,19 @@
             CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
             CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3
         };
-        int deviceLevel = getHardwareLevelChecked();
-        if (level == deviceLevel) {
+
+        if (level1 == level2) {
             return true;
         }
 
         for (int sortedlevel : sortedHwLevels) {
-            if (sortedlevel == level) {
+            if (sortedlevel == level2) {
                 return true;
-            } else if (sortedlevel == deviceLevel) {
+            } else if (sortedlevel == level1) {
                 return false;
             }
         }
-        Assert.fail("Unknown hardwareLevel " + level + " and device hardware level " + deviceLevel);
+        Assert.fail("Unknown hardwareLevel " + level1 + " and device hardware level " + level2);
         return false;
     }
 
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java
index 2c3934c..bdf4bc6 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java
@@ -27,6 +27,7 @@
 import com.android.bedstead.harrier.BedsteadJUnit4;
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.EnsureHasPermission;
+import com.android.bedstead.harrier.annotations.RequireMultiUserSupport;
 import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
@@ -52,6 +53,7 @@
     @EnsureHasDeviceOwner
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
     @RequireRunOnPrimaryUser
+    @RequireMultiUserSupport
     public void createCloneProfile_hasDeviceOwner_fails() {
         assertThrows(NeneException.class,
                 () -> TestApis.users().createUser()
@@ -67,6 +69,7 @@
     @EnsureHasNoDeviceOwner
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
     @RequireRunOnPrimaryUser
+    @RequireMultiUserSupport
     public void createCloneProfile_noDeviceOwner_succeeds() {
         UserReference cloneUser = TestApis.users().createUser()
                 .parent(TestApis.users().instrumented())
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
index 2688d11..9c2714c 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
@@ -23,6 +23,7 @@
 import static org.testng.Assert.assertThrows;
 
 import android.app.admin.RemoteDevicePolicyManager;
+import android.app.role.RoleManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.provider.Telephony;
@@ -65,6 +66,7 @@
     private ComponentName mAdmin;
     private RemoteDevicePolicyManager mDpm;
     private TelephonyManager mTelephonyManager;
+    private RoleManager mRoleManager;
 
     @Before
     public void setUp() {
@@ -72,13 +74,15 @@
         mAdmin = dpc.componentName();
         mDpm = dpc.devicePolicyManager();
         mTelephonyManager = sContext.getSystemService(TelephonyManager.class);
+        mRoleManager = sContext.getSystemService(RoleManager.class);
     }
 
     // TODO(b/198588696): Add support is @RequireSmsCapable and @RequireNotSmsCapable
     @Postsubmit(reason = "new test")
     @PolicyAppliesTest(policy = DefaultSmsApplication.class)
     public void setDefaultSmsApplication_works() {
-        assumeTrue(mTelephonyManager.isSmsCapable());
+        assumeTrue(mTelephonyManager.isSmsCapable()
+                || (mRoleManager != null && mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
         String previousSmsAppName = getDefaultSmsPackage();
         try (TestAppInstance smsApp = sSmsApp.install()) {
             mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
@@ -93,7 +97,8 @@
     @Postsubmit(reason = "new test")
     @PolicyDoesNotApplyTest(policy = DefaultSmsApplication.class)
     public void setDefaultSmsApplication_unchanged() {
-        assumeTrue(mTelephonyManager.isSmsCapable());
+        assumeTrue(mTelephonyManager.isSmsCapable()
+                || (mRoleManager != null && mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
         String previousSmsAppName = getDefaultSmsPackage();
         try (TestAppInstance smsApp = sSmsApp.install()) {
             mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
@@ -108,7 +113,8 @@
     @Postsubmit(reason = "new test")
     @CanSetPolicyTest(policy = DefaultSmsApplication.class)
     public void setDefaultSmsApplication_smsPackageDoesNotExist_unchanged() {
-        assumeTrue(mTelephonyManager.isSmsCapable());
+        assumeTrue(mTelephonyManager.isSmsCapable()
+                || (mRoleManager != null && mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
         String previousSmsAppName = getDefaultSmsPackage();
 
         mDpm.setDefaultSmsApplication(mAdmin, FAKE_SMS_APP_NAME);
@@ -135,7 +141,8 @@
     @Postsubmit(reason = "new test")
     @CanSetPolicyTest(policy = DefaultSmsApplication.class)
     public void setDefaultSmsApplication_notSmsCapable_unchanged() {
-        assumeTrue(!mTelephonyManager.isSmsCapable());
+        assumeTrue(!mTelephonyManager.isSmsCapable()
+                && (mRoleManager == null || !mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
         String previousSmsAppName = getDefaultSmsPackage();
         try (TestAppInstance smsApp = sSmsApp.install()) {
             mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
index 286ccae..1c35d48 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
@@ -54,6 +54,7 @@
 import com.android.bedstead.harrier.annotations.EnsureHasPermission;
 import com.android.bedstead.harrier.annotations.Postsubmit;
 import com.android.bedstead.harrier.annotations.RequireFeature;
+import com.android.bedstead.harrier.annotations.RequireMultiUserSupport;
 import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDpc;
@@ -65,6 +66,7 @@
 import com.android.bedstead.remotedpc.RemoteDpc;
 import com.android.bedstead.testapp.TestApp;
 import com.android.bedstead.testapp.TestAppInstance;
+import com.android.compatibility.common.util.CddTest;
 import com.android.eventlib.truth.EventLogsSubject;
 import com.android.queryable.queries.ActivityQuery;
 
@@ -140,6 +142,7 @@
     @EnsureHasNoDpc
     @EnsureHasNoSecondaryUser
     @Test
+    @CddTest(requirements = {"3.9.4/C-3-1"})
     public void createAndProvisionManagedProfile_roleHolderIsInWorkProfile()
             throws ProvisioningException, InterruptedException {
         UserHandle profile = null;
@@ -172,7 +175,9 @@
     @EnsureHasDeviceOwner
     @RequireRunOnPrimaryUser
     @EnsureHasNoSecondaryUser
+    @RequireMultiUserSupport
     @Test
+    @CddTest(requirements = {"3.9.4/C-3-1"})
     public void createAndManageUser_roleHolderIsInManagedUser() throws InterruptedException {
         UserHandle managedUser = null;
         String roleHolderPackageName = null;
@@ -313,6 +318,7 @@
     @EnsureHasNoWorkProfile
     @RequireRunOnPrimaryUser
     @EnsureHasNoDpc
+    @RequireMultiUserSupport
     public void shouldAllowBypassingDevicePolicyManagementRoleQualification_withUsers_returnsFalse()
             throws Exception {
         resetInternalShouldAllowBypassingState();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
index fcf71d0..dfe77fb 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
@@ -45,6 +45,7 @@
 import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
 import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.packages.Package;
+import com.android.bedstead.nene.utils.Poll;
 import com.android.bedstead.testapp.TestApp;
 import com.android.bedstead.testapp.TestAppInstance;
 import com.android.queryable.queries.StringQuery;
@@ -235,6 +236,11 @@
 
     private void assertPackageStopped(String packageName)
             throws Exception {
+        Poll.forValue("Package " + packageName + " stopped", () -> isPackageStopped(packageName))
+                .toBeEqualTo(true)
+                .errorOnFail()
+                .await();
+
         assertWithMessage("Package %s not stopped", packageName)
                 .that(isPackageStopped(packageName)).isTrue();
     }
diff --git a/tests/framework/base/windowmanager/Android.bp b/tests/framework/base/windowmanager/Android.bp
index 168ee3f..b786d83 100644
--- a/tests/framework/base/windowmanager/Android.bp
+++ b/tests/framework/base/windowmanager/Android.bp
@@ -67,6 +67,7 @@
         "cts-wm-overlayapp-base",
         "cts-wm-shared",
         "platform-compat-test-rules",
+        "cts_window_jetpack_utils",
     ],
 
     test_suites: [
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index 39c3d3e..1a86422 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -38,6 +38,8 @@
                  android:enableOnBackInvokedCallback="true"
                  android:testOnly="true">
         <uses-library android:name="android.test.runner"/>
+        <uses-library android:name="androidx.window.extensions"
+            android:required="false" />
 
         <activity android:name="android.server.wm.ActivityManagerTestBase$ConfigChangeHandlingActivity"
              android:resizeableActivity="true"
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
index d12b7c1d..477cc8d 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
@@ -16,6 +16,7 @@
 
 package android.server.wm.jetpack.utils;
 
+import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
 import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
 import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityBounds;
 import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getMaximumActivityBounds;
@@ -28,6 +29,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.Activity;
 import android.content.ComponentName;
@@ -51,6 +53,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.function.Predicate;
 
 /**
@@ -447,6 +450,13 @@
         }
     }
 
+    public static void assumeActivityEmbeddingSupportedDevice() {
+        assumeExtensionSupportedDevice();
+        assumeTrue("Device does not support ActivityEmbedding",
+                Objects.requireNonNull(getWindowExtensions())
+                        .getActivityEmbeddingComponent() != null);
+    }
+
     private static void assertSplitInfoTopSplitIsCorrect(@NonNull List<SplitInfo> splitInfoList,
             @NonNull Activity primaryActivity, @NonNull Activity secondaryActivity) {
         assertFalse("Split info callback should not be empty", splitInfoList.isEmpty());
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java b/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java
index b6c43f1..a26d3c2 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java
@@ -23,10 +23,14 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.Instrumentation;
+import android.os.SystemClock;
 import android.server.wm.TestJournalProvider.TestJournalContainer;
 import android.server.wm.backlegacyapp.Components;
 import android.support.test.uiautomator.UiDevice;
+import android.view.InputEvent;
+import android.view.MotionEvent;
 
+import androidx.annotation.NonNull;
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.GestureNavRule;
@@ -74,7 +78,45 @@
     private void doBackGesture() {
         int midHeight = mUiDevice.getDisplayHeight() / 2;
         int midWidth = mUiDevice.getDisplayWidth() / 2;
-        mUiDevice.swipe(0, midHeight, midWidth, midHeight, 100);
+        quickSwipe(0, midHeight, midWidth, midHeight, 10);
         mUiDevice.waitForIdle();
     }
+
+    private void injectInputEventUnSynced(@NonNull InputEvent event) {
+        mInstrumentation.getUiAutomation().injectInputEvent(event, false /* sync */,
+                false /* waitForAnimations */);
+    }
+
+    /**
+     * Injecting a sequence of motion event to simulate swipe without waiting for sync transaction.
+     */
+    private void quickSwipe(float startX, float startY, float endX, float endY, int steps) {
+        if (steps <= 0) {
+            steps = 1;
+        }
+        final long startDownTime = SystemClock.uptimeMillis();
+        MotionEvent firstDown = MotionEvent.obtain(startDownTime, startDownTime,
+                MotionEvent.ACTION_DOWN, startX, startY, 0);
+        injectInputEventUnSynced(firstDown);
+
+        // inject in every 5 ms.
+        final int delayMillis = 5;
+        long nextEventTime = startDownTime + delayMillis;
+        final float stepGapX = (endX - startX) / steps;
+        final float stepGapY = (endY - startY) / steps;
+        for (int i = 0; i < steps; i++) {
+            SystemClock.sleep(delayMillis);
+            final float nextX = startX + stepGapX * i;
+            final float nextY = startY + stepGapY * i;
+            MotionEvent move = MotionEvent.obtain(startDownTime, nextEventTime,
+                    MotionEvent.ACTION_MOVE, nextX, nextY, 0);
+            injectInputEventUnSynced(move);
+            nextEventTime += delayMillis;
+        }
+
+        SystemClock.sleep(delayMillis);
+        MotionEvent up = MotionEvent.obtain(startDownTime, nextEventTime,
+                MotionEvent.ACTION_UP, endX, endY, 0);
+        injectInputEventUnSynced(up);
+    }
 }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
index 385a5af..9fd1a41 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
@@ -18,8 +18,10 @@
 
 import static android.server.wm.WindowManagerState.STATE_RESUMED;
 import static android.server.wm.jetpack.second.Components.SECOND_UNTRUSTED_EMBEDDING_ACTIVITY;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.assumeActivityEmbeddingSupportedDevice;
 
 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.assertFalse;
@@ -32,6 +34,7 @@
 import android.graphics.Rect;
 import android.os.Binder;
 import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
 import android.server.wm.WindowManagerState.Task;
 import android.window.TaskFragmentCreationParams;
 import android.window.TaskFragmentInfo;
@@ -39,6 +42,7 @@
 
 import androidx.annotation.NonNull;
 
+import org.junit.Before;
 import org.junit.Test;
 
 /**
@@ -47,11 +51,19 @@
  * Build/Install/Run:
  *     atest CtsWindowManagerDeviceTestCases:TaskFragmentTrustedModeTest
  */
+@Presubmit
 public class TaskFragmentTrustedModeTest extends TaskFragmentOrganizerTestBase {
 
     private final ComponentName mTranslucentActivity = new ComponentName(mContext,
             TranslucentActivity.class);
 
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        assumeActivityEmbeddingSupportedDevice();
+    }
+
     /**
      * Verifies the visibility of a task fragment that has overlays on top of activities embedded
      * in untrusted mode when there is an overlay over the task fragment.
@@ -239,7 +251,7 @@
      */
     @Test
     public void testUntrustedModeTaskFragment_startActivityInTaskFragmentOutsideOfParentBounds() {
-        final Task parentTask = mWmState.getRootTask(mOwnerTaskId);
+        Task parentTask = mWmState.getRootTask(mOwnerTaskId);
         final Rect parentBounds = new Rect(parentTask.getBounds());
         final IBinder errorCallbackToken = new Binder();
         final WindowContainerTransaction wct = new WindowContainerTransaction()
@@ -254,8 +266,11 @@
         // It is disallowed to start activity to TaskFragment with bounds outside of its parent
         // in untrusted mode.
         assertTaskFragmentError(errorCallbackToken, SecurityException.class);
-        mWmState.waitForAppTransitionIdleOnDisplay(mOwnerActivity.getDisplayId());
-        mWmState.assertNotExist(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY);
+
+        parentTask = mWmState.getRootTask(mOwnerTaskId);
+        assertWithMessage("Activity must be started in parent Task because it's not"
+                + " allowed to be embedded").that(parentTask.mActivities).contains(
+                mWmState.getActivity(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY));
     }
 
     /**
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
index 65465b2..8dc33b1 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
@@ -59,6 +59,7 @@
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
@@ -226,6 +227,11 @@
         final Instrumentation instrumentation = getInstrumentation();
         assumeThat(MockImeSession.getUnavailabilityReason(instrumentation.getContext()),
                 nullValue());
+        final Resources resources = instrumentation.getContext().getResources();
+        final boolean isHideNavBarForKeyboardEnabled = resources.getBoolean(
+                resources.getIdentifier("config_hideNavBarForKeyboard", "bool", "android"));
+        assumeFalse("Device is configured to not show navigation bar for keyboard",
+                isHideNavBarForKeyboardEnabled);
         final MockImeSession imeSession = MockImeHelper.createManagedMockImeSession(this);
         final ImeEventStream stream = imeSession.openEventStream();
         final TestActivity activity = startActivityInWindowingModeFullScreen(TestActivity.class);
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java
index ccd8659..8855dee 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java
@@ -32,7 +32,7 @@
      *
      * <p>See Bug 174534092 about why we ended up having this.</p>
      */
-    private static final int TOLERANCE = 4;
+    private static final int TOLERANCE = 6;
 
     /**
      * A utility class that represents A8R8G8B bitmap as an integer array.
diff --git a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
index 08ddca1..2baa2f1 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
@@ -33,10 +33,12 @@
 import android.content.pm.PackageManager.ResolveInfoFlags;
 import android.location.Geocoder;
 import android.location.Geocoder.GeocodeListener;
+import android.platform.test.annotations.AppModeFull;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.RetryRule;
 
 import org.junit.Before;
@@ -73,6 +75,8 @@
         }
     }
 
+    @ApiTest(apis = "android.location.Geocoder#getFromLocation")
+    @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
     @Test
     public void testGetFromLocation() {
         assumeTrue(Geocoder.isPresent());
@@ -82,6 +86,8 @@
         verify(listener, timeout(10000)).onGeocode(anyList());
     }
 
+    @ApiTest(apis = "android.location.Geocoder#getFromLocation")
+    @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
     @Test
     public void testGetFromLocation_sync() throws Exception {
         assumeTrue(Geocoder.isPresent());
@@ -89,6 +95,8 @@
         mGeocoder.getFromLocation(60, 30, 5);
     }
 
+    @ApiTest(apis = "android.location.Geocoder#getFromLocation")
+    @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
     @Test
     public void testGetFromLocation_badInput() {
         GeocodeListener listener = mock(GeocodeListener.class);
@@ -102,6 +110,8 @@
                 () -> mGeocoder.getFromLocation(10, 181, 5, listener));
     }
 
+    @ApiTest(apis = "android.location.Geocoder#getFromLocationName")
+    @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
     @Test
     public void testGetFromLocationName() {
         assumeTrue(Geocoder.isPresent());
@@ -111,6 +121,8 @@
         verify(listener, timeout(10000)).onGeocode(anyList());
     }
 
+    @ApiTest(apis = "android.location.Geocoder#getFromLocationName")
+    @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
     @Test
     public void testGetFromLocationName_sync() throws Exception {
         assumeTrue(Geocoder.isPresent());
@@ -118,6 +130,8 @@
         mGeocoder.getFromLocationName("Dalvik,Iceland", 5);
     }
 
+    @ApiTest(apis = "android.location.Geocoder#getFromLocationName")
+    @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
     @Test
     public void testGetFromLocationName_badInput() {
         GeocodeListener listener = mock(GeocodeListener.class);
diff --git a/tests/media/src/android/mediav2/cts/CodecInfoTest.java b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
index 5f9aa09..14ebd28 100644
--- a/tests/media/src/android/mediav2/cts/CodecInfoTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
@@ -158,10 +158,10 @@
                             .noneMatch(x -> x == COLOR_FormatSurface));
         }
 
-        // For devices launching with Android T, if a codec supports an HDR profile, it must
-        // advertise P010 support
+        // For devices launching with Android T, if a codec supports an HDR profile and device
+        // supports HDR display, it must advertise P010 support
         int[] HdrProfileArray = mProfileHdrMap.get(mMediaType);
-        if (FIRST_SDK_IS_AT_LEAST_T && HdrProfileArray != null) {
+        if (VNDK_IS_AT_LEAST_T && HdrProfileArray != null && DISPLAY_HDR_TYPES.length > 0) {
             for (CodecProfileLevel pl : caps.profileLevels) {
                 if (IntStream.of(HdrProfileArray).anyMatch(x -> x == pl.profile)) {
                     assertFalse(mCodecInfo.getName() + " supports HDR profile " + pl.profile + "," +
diff --git a/tests/mediapc/AndroidTest.xml b/tests/mediapc/AndroidTest.xml
index dcc8995..dc36e58 100644
--- a/tests/mediapc/AndroidTest.xml
+++ b/tests/mediapc/AndroidTest.xml
@@ -24,6 +24,11 @@
         <option name="config-filename" value="CtsMediaPerformanceClassTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaPerformanceClassTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaPerformanceClassTestCases-1.2" />
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java b/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
index 327fb9c..d3fd292 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
@@ -20,6 +20,7 @@
 
 import static org.junit.Assume.assumeTrue;
 
+import android.hardware.camera2.CameraMetadata;
 import android.media.MediaFormat;
 import android.os.Build;
 
@@ -849,7 +850,493 @@
         }
     }
 
-    private <R extends Requirement> R addRequirement(R req) {
+    public static class PrimaryCameraRequirement extends Requirement {
+        private static final long MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION = 12000000;
+        private static final long MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION = 5000000;
+        private static final long MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION = 4000000;
+        private static final String TAG = PrimaryCameraRequirement.class.getSimpleName();
+
+        private PrimaryCameraRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setPrimaryCameraSupported(boolean hasPrimaryCamera) {
+            this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_AVAILABLE,
+                    hasPrimaryCamera);
+        }
+
+        public void setResolution(long resolution) {
+            this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_RESOLUTION,
+                    resolution);
+        }
+
+        public void setVideoSizeReqSatisfied(boolean videoSizeReqSatisfied) {
+            this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED,
+                    videoSizeReqSatisfied);
+        }
+
+        public void setVideoFps(double videoFps) {
+            this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_VIDEO_FPS, videoFps);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-1] MUST have a primary rear facing camera with a resolution of at
+         * least 12 megapixels supporting video capture at 4k@30fps
+         */
+        public static PrimaryCameraRequirement createRearPrimaryCamera() {
+            RequiredMeasurement<Boolean> hasPrimaryCamera = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_AVAILABLE)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, true)
+                .addRequiredValue(Build.VERSION_CODES.S, true)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            RequiredMeasurement<Long> cameraResolution = RequiredMeasurement
+                .<Long>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_RESOLUTION)
+                .setPredicate(RequirementConstants.LONG_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION)
+                .addRequiredValue(Build.VERSION_CODES.S, MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION)
+                .build();
+
+            RequiredMeasurement<Boolean> videoSizeReqSatisfied = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, true)
+                .addRequiredValue(Build.VERSION_CODES.S, true)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            RequiredMeasurement<Double> videoFps = RequiredMeasurement
+                .<Double>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 29.9)
+                .addRequiredValue(Build.VERSION_CODES.S, 29.9)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 29.9)
+                .build();
+
+            return new PrimaryCameraRequirement(RequirementConstants.R7_5__H_1_1,
+                    hasPrimaryCamera, cameraResolution, videoSizeReqSatisfied,
+                    videoFps);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-2] MUST have a primary front facing camera with a resolution of
+         * at least 4 megapixels supporting video capture at 1080p@30fps.
+         */
+        public static PrimaryCameraRequirement createFrontPrimaryCamera() {
+            RequiredMeasurement<Boolean> hasPrimaryCamera = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_AVAILABLE)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, true)
+                .addRequiredValue(Build.VERSION_CODES.S, true)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            RequiredMeasurement<Long> cameraResolution = RequiredMeasurement
+                .<Long>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_RESOLUTION)
+                .setPredicate(RequirementConstants.LONG_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION)
+                .addRequiredValue(Build.VERSION_CODES.S, MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU,
+                        MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION)
+                .build();
+
+            RequiredMeasurement<Boolean> videoSizeReqSatisfied = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, true)
+                .addRequiredValue(Build.VERSION_CODES.S, true)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            RequiredMeasurement<Double> videoFps = RequiredMeasurement
+                .<Double>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 29.9)
+                .addRequiredValue(Build.VERSION_CODES.S, 29.9)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 29.9)
+                .build();
+
+            return new PrimaryCameraRequirement(RequirementConstants.R7_5__H_1_2,
+                    hasPrimaryCamera, cameraResolution, videoSizeReqSatisfied,
+                    videoFps);
+        }
+    }
+
+    public static class CameraTimestampSourceRequirement extends Requirement {
+        private static final String TAG = CameraTimestampSourceRequirement.class.getSimpleName();
+        private static final int TIMESTAMP_REALTIME =
+                CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME;
+
+        private CameraTimestampSourceRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearCameraTimestampSource(Integer timestampSource) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_TIMESTAMP_SOURCE,
+                    timestampSource);
+        }
+
+        public void setFrontCameraTimestampSource(Integer timestampSource) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_TIMESTAMP_SOURCE,
+                    timestampSource);
+        }
+        /**
+         * [2.2.7.2/7.5/H-1-4] MUST support CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME
+         * for both primary cameras.
+         */
+        public static CameraTimestampSourceRequirement createTimestampSourceReq() {
+            RequiredMeasurement<Integer> rearTimestampSource = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.REAR_CAMERA_TIMESTAMP_SOURCE)
+                .setPredicate(RequirementConstants.INTEGER_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, TIMESTAMP_REALTIME)
+                .addRequiredValue(Build.VERSION_CODES.S, TIMESTAMP_REALTIME)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, TIMESTAMP_REALTIME)
+                .build();
+            RequiredMeasurement<Integer> frontTimestampSource = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_TIMESTAMP_SOURCE)
+                .setPredicate(RequirementConstants.INTEGER_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, TIMESTAMP_REALTIME)
+                .addRequiredValue(Build.VERSION_CODES.S, TIMESTAMP_REALTIME)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, TIMESTAMP_REALTIME)
+                .build();
+
+            return new CameraTimestampSourceRequirement(RequirementConstants.R7_5__H_1_4,
+                    rearTimestampSource, frontTimestampSource);
+        }
+    }
+
+    public static class CameraLatencyRequirement extends Requirement {
+        private static final String TAG = CameraTimestampSourceRequirement.class.getSimpleName();
+
+        private CameraLatencyRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearCameraLatency(float latency) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_LATENCY, latency);
+        }
+
+        public void setFrontCameraLatency(float latency) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_LATENCY, latency);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-5] MUST have camera2 JPEG capture latency < 1000ms for 1080p resolution
+         * as measured by the CTS camera PerformanceTest under ITS lighting conditions
+         * (3000K) for both primary cameras.
+         */
+        public static CameraLatencyRequirement createJpegLatencyReq() {
+            RequiredMeasurement<Float> rearJpegLatency = RequiredMeasurement
+                .<Float>builder()
+                .setId(RequirementConstants.REAR_CAMERA_LATENCY)
+                .setPredicate(RequirementConstants.FLOAT_LTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 1000.0f)
+                .addRequiredValue(Build.VERSION_CODES.S, 1000.0f)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1000.0f)
+                .build();
+            RequiredMeasurement<Float> frontJpegLatency = RequiredMeasurement
+                .<Float>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_LATENCY)
+                .setPredicate(RequirementConstants.FLOAT_LTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 1000.0f)
+                .addRequiredValue(Build.VERSION_CODES.S, 1000.0f)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1000.0f)
+                .build();
+
+            return new CameraLatencyRequirement(RequirementConstants.R7_5__H_1_5,
+                    rearJpegLatency, frontJpegLatency);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-6] MUST have camera2 startup latency (open camera to first
+         * preview frame) < 600ms as measured by the CTS camera PerformanceTest under ITS lighting
+         * conditions (3000K) for both primary cameras.
+         */
+        public static CameraLatencyRequirement createLaunchLatencyReq() {
+            RequiredMeasurement<Float> rearLaunchLatency = RequiredMeasurement
+                .<Float>builder()
+                .setId(RequirementConstants.REAR_CAMERA_LATENCY)
+                .setPredicate(RequirementConstants.FLOAT_LTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 600.0f)
+                .addRequiredValue(Build.VERSION_CODES.S, 600.0f)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 600.0f)
+                .build();
+            RequiredMeasurement<Float> frontLaunchLatency = RequiredMeasurement
+                .<Float>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_LATENCY)
+                .setPredicate(RequirementConstants.FLOAT_LTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 600.0f)
+                .addRequiredValue(Build.VERSION_CODES.S, 600.0f)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 600.0f)
+                .build();
+
+            return new CameraLatencyRequirement(RequirementConstants.R7_5__H_1_6,
+                    rearLaunchLatency, frontLaunchLatency);
+        }
+    }
+
+    public static class CameraRawRequirement extends Requirement {
+        private static final String TAG = CameraRawRequirement.class.getSimpleName();
+
+        private CameraRawRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearRawSupported(boolean rearRawSupported) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_RAW_SUPPORTED,
+                    rearRawSupported);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-8] MUST support CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_RAW and
+         * android.graphics.ImageFormat.RAW_SENSOR for the primary back camera.
+         */
+        public static CameraRawRequirement createRawReq() {
+            RequiredMeasurement<Boolean> requirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.REAR_CAMERA_RAW_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.S, true)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new CameraRawRequirement(RequirementConstants.R7_5__H_1_8, requirement);
+        }
+    }
+
+    public static class Camera240FpsRequirement extends Requirement {
+        private static final String TAG = Camera240FpsRequirement.class.getSimpleName();
+
+        private Camera240FpsRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRear240FpsSupported(boolean rear240FpsSupported) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_240FPS_SUPPORTED,
+                    rear240FpsSupported);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-9] MUST have a rear-facing primary camera supporting 720p or 1080p @ 240fps.
+         */
+        public static Camera240FpsRequirement create240FpsReq() {
+            RequiredMeasurement<Boolean> requirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.REAR_CAMERA_240FPS_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new Camera240FpsRequirement(RequirementConstants.R7_5__H_1_9, requirement);
+        }
+    }
+
+    public static class UltraWideZoomRatioRequirement extends Requirement {
+        private static final String TAG =
+                UltraWideZoomRatioRequirement.class.getSimpleName();
+
+        private UltraWideZoomRatioRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearUltraWideZoomRatioReqMet(boolean ultrawideZoomRatioReqMet) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET,
+                    ultrawideZoomRatioReqMet);
+        }
+
+        public void setFrontUltraWideZoomRatioReqMet(boolean ultrawideZoomRatioReqMet) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET,
+                    ultrawideZoomRatioReqMet);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-10] MUST have min ZOOM_RATIO < 1.0 for the primary cameras if
+         * there is an ultrawide RGB camera facing the same direction.
+         */
+        public static UltraWideZoomRatioRequirement createUltrawideZoomRatioReq() {
+            RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.REAR_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+            RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new UltraWideZoomRatioRequirement(RequirementConstants.R7_5__H_1_10,
+                    rearRequirement, frontRequirement);
+        }
+    }
+
+    public static class ConcurrentRearFrontRequirement extends Requirement {
+        private static final String TAG = ConcurrentRearFrontRequirement.class.getSimpleName();
+
+        private ConcurrentRearFrontRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setConcurrentRearFrontSupported(boolean concurrentRearFrontSupported) {
+            this.setMeasuredValue(RequirementConstants.CONCURRENT_REAR_FRONT_SUPPORTED,
+                    concurrentRearFrontSupported);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-11] MUST implement concurrent front-back streaming on primary cameras.
+         */
+        public static ConcurrentRearFrontRequirement createConcurrentRearFrontReq() {
+            RequiredMeasurement<Boolean> requirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.CONCURRENT_REAR_FRONT_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new ConcurrentRearFrontRequirement(RequirementConstants.R7_5__H_1_11,
+                    requirement);
+        }
+    }
+
+    public static class PreviewStabilizationRequirement extends Requirement {
+        private static final String TAG =
+                PreviewStabilizationRequirement.class.getSimpleName();
+
+        private PreviewStabilizationRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearPreviewStabilizationSupported(boolean supported) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_PREVIEW_STABILIZATION_SUPPORTED,
+                    supported);
+        }
+
+        public void setFrontPreviewStabilizationSupported(boolean supported) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_PREVIEW_STABILIZATION_SUPPORTED,
+                    supported);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-12] MUST support CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION
+         * for both primary front and primary back camera.
+         */
+        public static PreviewStabilizationRequirement createPreviewStabilizationReq() {
+            RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.REAR_CAMERA_PREVIEW_STABILIZATION_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+            RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_PREVIEW_STABILIZATION_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new PreviewStabilizationRequirement(RequirementConstants.R7_5__H_1_12,
+                    rearRequirement, frontRequirement);
+        }
+    }
+
+    public static class LogicalMultiCameraRequirement extends Requirement {
+        private static final String TAG =
+                LogicalMultiCameraRequirement.class.getSimpleName();
+
+        private LogicalMultiCameraRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearLogicalMultiCameraReqMet(boolean reqMet) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET,
+                    reqMet);
+        }
+
+        public void setFrontLogicalMultiCameraReqMet(boolean reqMet) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET,
+                    reqMet);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-13] MUST support LOGICAL_MULTI_CAMERA capability for the primary
+         * cameras if there are greater than 1 RGB cameras facing the same direction.
+         */
+        public static LogicalMultiCameraRequirement createLogicalMultiCameraReq() {
+            RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.REAR_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+            RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new LogicalMultiCameraRequirement(RequirementConstants.R7_5__H_1_13,
+                    rearRequirement, frontRequirement);
+        }
+    }
+
+    public static class StreamUseCaseRequirement extends Requirement {
+        private static final String TAG =
+                StreamUseCaseRequirement.class.getSimpleName();
+
+        private StreamUseCaseRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearStreamUseCaseSupported(boolean supported) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_STREAM_USECASE_SUPPORTED,
+                    supported);
+        }
+
+        public void setFrontStreamUseCaseSupported(boolean supported) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_STREAM_USECASE_SUPPORTED,
+                    supported);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-14] MUST support STREAM_USE_CASE capability for both primary
+         * front and primary back camera.
+         */
+        public static StreamUseCaseRequirement createStreamUseCaseReq() {
+            RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.REAR_CAMERA_STREAM_USECASE_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+            RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_STREAM_USECASE_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new StreamUseCaseRequirement(RequirementConstants.R7_5__H_1_14,
+                    rearRequirement, frontRequirement);
+        }
+    }
+
+    public <R extends Requirement> R addRequirement(R req) {
         if (!this.mRequirements.add(req)) {
             throw new IllegalStateException("Requirement " + req.id() + " already added");
         }
@@ -1000,16 +1487,69 @@
         return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_10());
     }
 
+    public PrimaryCameraRequirement addPrimaryRearCameraReq() {
+        return this.addRequirement(PrimaryCameraRequirement.createRearPrimaryCamera());
+    }
+
+    public PrimaryCameraRequirement addPrimaryFrontCameraReq() {
+        return this.addRequirement(PrimaryCameraRequirement.createFrontPrimaryCamera());
+    }
+
+    public CameraTimestampSourceRequirement addR7_5__H_1_4() {
+        return this.addRequirement(CameraTimestampSourceRequirement.createTimestampSourceReq());
+    }
+
+    public CameraLatencyRequirement addR7_5__H_1_5() {
+        return this.addRequirement(CameraLatencyRequirement.createJpegLatencyReq());
+    }
+
+    public CameraLatencyRequirement addR7_5__H_1_6() {
+        return this.addRequirement(CameraLatencyRequirement.createLaunchLatencyReq());
+    }
+
+    public CameraRawRequirement addR7_5__H_1_8() {
+        return this.addRequirement(CameraRawRequirement.createRawReq());
+    }
+
+    public Camera240FpsRequirement addR7_5__H_1_9() {
+        return this.addRequirement(Camera240FpsRequirement.create240FpsReq());
+    }
+
+    public UltraWideZoomRatioRequirement addR7_5__H_1_10() {
+        return this.addRequirement(UltraWideZoomRatioRequirement.createUltrawideZoomRatioReq());
+    }
+
+    public ConcurrentRearFrontRequirement addR7_5__H_1_11() {
+        return this.addRequirement(ConcurrentRearFrontRequirement.createConcurrentRearFrontReq());
+    }
+
+    public PreviewStabilizationRequirement addR7_5__H_1_12() {
+        return this.addRequirement(PreviewStabilizationRequirement.createPreviewStabilizationReq());
+    }
+
+    public LogicalMultiCameraRequirement addR7_5__H_1_13() {
+        return this.addRequirement(LogicalMultiCameraRequirement.createLogicalMultiCameraReq());
+    }
+
+    public StreamUseCaseRequirement addR7_5__H_1_14() {
+        return this.addRequirement(StreamUseCaseRequirement.createStreamUseCaseReq());
+    }
+
     public void submitAndCheck() {
-        boolean perfClassMet = true;
-        for (Requirement req: this.mRequirements) {
-            perfClassMet &= req.writeLogAndCheck(this.mTestName);
-        }
+        boolean perfClassMet = submit();
 
         // check performance class
         assumeTrue("Build.VERSION.MEDIA_PERFORMANCE_CLASS is not declared", Utils.isPerfClass());
         assertThat(perfClassMet).isTrue();
-
-        this.mRequirements.clear(); // makes sure report isn't submitted twice
     }
+
+    public boolean submit() {
+        boolean perfClassMet = true;
+        for (Requirement req: this.mRequirements) {
+            perfClassMet &= req.writeLogAndCheck(this.mTestName);
+        }
+        this.mRequirements.clear(); // makes sure report isn't submitted twice
+        return perfClassMet;
+    }
+
 }
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java b/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
index d93cb2e..ad0d0d5 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
@@ -16,8 +16,6 @@
 
 package android.mediapc.cts.common;
 
-import android.os.Build;
-
 import java.util.function.BiPredicate;
 
 public class RequirementConstants {
@@ -54,8 +52,13 @@
     public static final String R7_5__H_1_4 = "r7_5__h_1_4"; // 7.5/H-1-4
     public static final String R7_5__H_1_5 = "r7_5__h_1_5"; // 7.5/H-1-5
     public static final String R7_5__H_1_6 = "r7_5__h_1_6"; // 7.5/H-1-6
-    public static final String R7_5__H_1_7 = "r7_5__h_1_7"; // 7.5/H-1-7
     public static final String R7_5__H_1_8 = "r7_5__h_1_8"; // 7.5/H-1-8
+    public static final String R7_5__H_1_9 = "r7_5__h_1_9"; // 7.5/H-1-9
+    public static final String R7_5__H_1_10 = "r7_5__h_1_10"; // 7.5/H-1-10
+    public static final String R7_5__H_1_11 = "r7_5__h_1_11"; // 7.5/H-1-11
+    public static final String R7_5__H_1_12 = "r7_5__h_1_12"; // 7.5/H-1-12
+    public static final String R7_5__H_1_13 = "r7_5__h_1_13"; // 7.5/H-1-13
+    public static final String R7_5__H_1_14 = "r7_5__h_1_14"; // 7.5/H-1-14
     public static final String R7_1_1_1__H_1_1 = "r7_1_1_1__h_1_1"; // 7.1.1.1/H-1-1
     public static final String R7_1_1_3__H_1_1 = "r7_1_1_3__h_1_1"; // 7.1.1.3/H-1-1
     public static final String R7_6_1__H_1_1 = "r7_6_1__h_1_1"; // 7.6.1/H-1-1
@@ -90,14 +93,50 @@
     public static final String NUM_CRYPTO_HW_SECURE_ALL_SUPPORT =
         "number_crypto_hw_secure_all_support";
 
+    public static final String PRIMARY_CAMERA_AVAILABLE = "primary_camera_available";
+    public static final String PRIMARY_CAMERA_RESOLUTION = "primary_camera_resolution";
+    public static final String PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED =
+            "primary_camera_video_size_req_satisfied";
+    public static final String PRIMARY_CAMERA_VIDEO_FPS =
+            "primary_camera_video_fps";
+    public static final String REAR_CAMERA_HWL_LEVEL = "rear_primary_camera_hwl_level";
+    public static final String FRONT_CAMERA_HWL_LEVEL = "front_primary_camera_hwl_level";
+    public static final String REAR_CAMERA_TIMESTAMP_SOURCE =
+            "rear_primary_camera_timestamp_source";
+    public static final String FRONT_CAMERA_TIMESTAMP_SOURCE =
+            "front_primary_camera_timestamp_source";
+    public static final String REAR_CAMERA_LATENCY = "rear_camera_latency";
+    public static final String FRONT_CAMERA_LATENCY = "front_camera_latency";
+    public static final String REAR_CAMERA_RAW_SUPPORTED = "rear_camera_raw_supported";
+    public static final String REAR_CAMERA_240FPS_SUPPORTED = "rear_camera_240fps_supported";
+    public static final String REAR_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET =
+            "rear_camera_ultrawide_zoom_req_met";
+    public static final String FRONT_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET =
+            "front_camera_ultrawide_zoom_req_met";
+    public static final String CONCURRENT_REAR_FRONT_SUPPORTED = "rear_front_concurrent_camera";
+    public static final String REAR_CAMERA_PREVIEW_STABILIZATION_SUPPORTED =
+            "rear_camera_preview_stabilization_supported";
+    public static final String FRONT_CAMERA_PREVIEW_STABILIZATION_SUPPORTED =
+            "front_camera_preview_stabilization_supported";
+    public static final String REAR_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET =
+            "rear_camera_logical_multi_camera_req_met";
+    public static final String FRONT_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET =
+            "front_camera_logical_multi_camera_req_met";
+    public static final String REAR_CAMERA_STREAM_USECASE_SUPPORTED =
+            "rear_camera_stream_usecase_supported";
+    public static final String FRONT_CAMERA_STREAM_USECASE_SUPPORTED =
+            "front_camera_stream_usecase_supported";
+
     public enum Result {
         NA, MET, UNMET
     }
 
     public static final BiPredicate<Long, Long> LONG_GTE = RequirementConstants.gte();
     public static final BiPredicate<Long, Long> LONG_LTE = RequirementConstants.lte();
+    public static final BiPredicate<Float, Float> FLOAT_LTE = RequirementConstants.lte();
     public static final BiPredicate<Integer, Integer> INTEGER_GTE = RequirementConstants.gte();
     public static final BiPredicate<Integer, Integer> INTEGER_LTE = RequirementConstants.lte();
+    public static final BiPredicate<Integer, Integer> INTEGER_EQ = RequirementConstants.eq();
     public static final BiPredicate<Double, Double> DOUBLE_EQ = RequirementConstants.eq();
     public static final BiPredicate<Boolean, Boolean> BOOLEAN_EQ = RequirementConstants.eq();
     public static final BiPredicate<Double, Double> DOUBLE_GTE = RequirementConstants.gte();
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java b/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java
index ac03705..28a122b 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java
@@ -73,16 +73,24 @@
 
         Context context = InstrumentationRegistry.getInstrumentation().getContext();
         DisplayMetrics metrics = new DisplayMetrics();
-        WindowManager windowManager = context.getSystemService(WindowManager.class);
-        windowManager.getDefaultDisplay().getMetrics(metrics);
-        DISPLAY_DPI = metrics.densityDpi;
-        DISPLAY_LONG_PIXELS = Math.max(metrics.widthPixels, metrics.heightPixels);
-        DISPLAY_SHORT_PIXELS = Math.min(metrics.widthPixels, metrics.heightPixels);
+        // When used from ItsService, context will be null
+        if (context != null) {
+            WindowManager windowManager = context.getSystemService(WindowManager.class);
+            windowManager.getDefaultDisplay().getMetrics(metrics);
+            DISPLAY_DPI = metrics.densityDpi;
+            DISPLAY_LONG_PIXELS = Math.max(metrics.widthPixels, metrics.heightPixels);
+            DISPLAY_SHORT_PIXELS = Math.min(metrics.widthPixels, metrics.heightPixels);
 
-        ActivityManager activityManager = context.getSystemService(ActivityManager.class);
-        ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
-        activityManager.getMemoryInfo(memoryInfo);
-        TOTAL_MEMORY_MB = memoryInfo.totalMem / 1024 / 1024;
+            ActivityManager activityManager = context.getSystemService(ActivityManager.class);
+            ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
+            activityManager.getMemoryInfo(memoryInfo);
+            TOTAL_MEMORY_MB = memoryInfo.totalMem / 1024 / 1024;
+        } else {
+            DISPLAY_DPI = 0;
+            DISPLAY_LONG_PIXELS = 0;
+            DISPLAY_SHORT_PIXELS = 0;
+            TOTAL_MEMORY_MB = 0;
+        }
     }
 
     /**
diff --git a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
index 2508845..8da22f3 100644
--- a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
@@ -41,6 +41,7 @@
 import java.util.List;
 import java.util.UUID;
 import org.junit.Assume;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
@@ -58,6 +59,11 @@
     @Rule
     public final TestName mTestName = new TestName();
 
+    @Before
+    public void isPerformanceClassCandidate() {
+        Utils.assumeDeviceMeetsPerformanceClassPreconditions();
+    }
+
     static {
         mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_AVC);
         mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
diff --git a/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
index bbe26dc..2ee8b3b 100644
--- a/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
@@ -21,12 +21,14 @@
 import static android.mediapc.cts.CodecTestBase.SELECT_VIDEO;
 import static android.mediapc.cts.CodecTestBase.getMimesOfAvailableCodecs;
 import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
+import static org.junit.Assert.assertTrue;
 
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
 import android.media.MediaFormat;
 import android.mediapc.cts.common.PerformanceClassEvaluator;
+import android.mediapc.cts.common.Utils;
 import android.util.Log;
 import androidx.test.filters.LargeTest;
 import com.android.compatibility.common.util.CddTest;
@@ -35,6 +37,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
@@ -47,6 +50,11 @@
     @Rule
     public final TestName mTestName = new TestName();
 
+    @Before
+    public void isPerformanceClassCandidate() {
+        Utils.assumeDeviceMeetsPerformanceClassPreconditions();
+    }
+
     private Set<String> get4k60HwCodecSet(boolean isEncoder) throws IOException {
         Set<String> codecSet = new HashSet<>();
         Set<String> codecMediaTypes = getMimesOfAvailableCodecs(SELECT_VIDEO, SELECT_HARDWARE);
@@ -60,6 +68,7 @@
                         codec.getCodecInfo().getCapabilitiesForType(codecMediaType);
                 List<PerformancePoint> pps =
                         capabilities.getVideoCapabilities().getSupportedPerformancePoints();
+                assertTrue(hwVideoCodec + " doesn't advertise performance points", pps.size() > 0);
                 for (PerformancePoint pp : pps) {
                     if (pp.covers(PP4k60)) {
                         codecSet.add(hwVideoCodec);
diff --git a/tests/tests/assist/common/src/android/assist/common/Utils.java b/tests/tests/assist/common/src/android/assist/common/Utils.java
index 0ffcb271..98e8576 100755
--- a/tests/tests/assist/common/src/android/assist/common/Utils.java
+++ b/tests/tests/assist/common/src/android/assist/common/Utils.java
@@ -56,6 +56,7 @@
     public static final String COMPARE_SCREENSHOT_KEY = "compare_screenshot";
     public static final String DISPLAY_WIDTH_KEY = "display_width";
     public static final String DISPLAY_HEIGHT_KEY = "dislay_height";
+    public static final String DISPLAY_AREA_BOUNDS_KEY = "display_area_bounds";
     public static final String SCROLL_X_POSITION = "scroll_x_position";
     public static final String SCROLL_Y_POSITION = "scroll_y_position";
     public static final String SHOW_SESSION_FLAGS_TO_SET = "show_session_flags_to_set";
diff --git a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
index 7f35367..25c080b 100644
--- a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
+++ b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
@@ -56,6 +56,7 @@
     private int mCurColor;
     private int mDisplayHeight;
     private int mDisplayWidth;
+    private Rect mDisplayAreaBounds;
     private BroadcastReceiver mReceiver;
     private String mTestName;
     private View mContentView;
@@ -106,7 +107,7 @@
     public void onPrepareShow(Bundle args, int showFlags) {
         if (Utils.LIFECYCLE_NOUI.equals(args.getString(Utils.TESTCASE_TYPE, ""))) {
             setUiEnabled(false);
-        } else  {
+        } else {
             setUiEnabled(true);
         }
     }
@@ -122,6 +123,7 @@
         mCurColor = args.getInt(Utils.SCREENSHOT_COLOR_KEY);
         mDisplayHeight = args.getInt(Utils.DISPLAY_HEIGHT_KEY);
         mDisplayWidth = args.getInt(Utils.DISPLAY_WIDTH_KEY);
+        mDisplayAreaBounds = args.getParcelable(Utils.DISPLAY_AREA_BOUNDS_KEY);
         mRemoteCallback = args.getParcelable(Utils.EXTRA_REMOTE_CALLBACK);
         super.onShow(args, showFlags);
         if (mContentView == null) return; // Happens when ui is not enabled.
@@ -256,6 +258,11 @@
         int[] pixels = new int[size.x * size.y];
         screenshot.getPixels(pixels, 0, size.x, 0, 0, size.x, size.y);
 
+        // screenshot bitmap contains the screenshot for the entire physical display. A single
+        // physical display could have multiple display area with different applications.
+        // Let's grab the region of the display area from the original screenshot.
+        Bitmap displayAreaScreenshot = Bitmap.createBitmap(screenshot, mDisplayAreaBounds.left,
+                mDisplayAreaBounds.top, mDisplayAreaBounds.width(), mDisplayAreaBounds.height());
         int expectedColor = 0;
         for (int pixel : pixels) {
             // Check for roughly the same because there are rounding errors converting from the
@@ -267,7 +274,7 @@
             }
         }
 
-        int pixelCount = screenshot.getWidth() * screenshot.getHeight();
+        int pixelCount = displayAreaScreenshot.getWidth() * displayAreaScreenshot.getHeight();
         double colorRatio = (double) expectedColor / pixelCount;
         Log.i(TAG, "the ratio is " + colorRatio);
         return colorRatio >= 0.6;
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
index 44a3109..c89119b 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -35,9 +35,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.LocaleList;
 import android.os.RemoteCallback;
 import android.provider.Settings;
@@ -341,6 +341,8 @@
             Display.Mode dMode = mTestActivity.getWindowManager().getDefaultDisplay().getMode();
             mDisplaySize = new Point(dMode.getPhysicalWidth(), dMode.getPhysicalHeight());
         }
+        Rect bounds = mTestActivity.getWindowManager().getMaximumWindowMetrics().getBounds();
+        intent.putExtra(Utils.DISPLAY_AREA_BOUNDS_KEY, bounds);
         intent.putExtra(Utils.DISPLAY_WIDTH_KEY, mDisplaySize.x);
         intent.putExtra(Utils.DISPLAY_HEIGHT_KEY, mDisplaySize.y);
     }
diff --git a/tests/tests/bluetooth/AndroidTest.xml b/tests/tests/bluetooth/AndroidTest.xml
index 9a3075b..9818962 100644
--- a/tests/tests/bluetooth/AndroidTest.xml
+++ b/tests/tests/bluetooth/AndroidTest.xml
@@ -33,6 +33,6 @@
     <!-- Only run Cts Tests in MTS if the Bluetooth Mainline module is installed. -->
     <object type="module_controller"
             class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
-        <option name="mainline-module-package-name" value="com.google.android.bluetooth" />
+        <option name="mainline-module-package-name" value="com.android.btservices" />
     </object>
 </configuration>
diff --git a/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java b/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
index 49b72549..8bd1bb8 100644
--- a/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
+++ b/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
@@ -43,6 +43,9 @@
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiScrollable;
+import android.support.test.uiautomator.UiSelector;
 import android.support.test.uiautomator.Until;
 import android.util.Log;
 
@@ -140,7 +143,7 @@
                     } catch (Throwable t) {
                         if (scrollUps < 10) {
                             // The notification we search for is below the fold, scroll to find it
-                            swipeUp(uiDevice);
+                            scrollNotifications();
                             scrollUps++;
                             continue;
                         }
@@ -200,6 +203,18 @@
             50 /* numberOfSteps */);
     }
 
+    private boolean scrollNotifications() {
+        UiScrollable scrollable = new UiScrollable(new UiSelector().scrollable(true));
+        if (!scrollable.exists()) {
+            return false;
+        }
+        try {
+            return scrollable.scrollForward(50);
+        } catch (UiObjectNotFoundException e) {
+            return false;
+        }
+    }
+
     private boolean isRunningInVR() {
         final Context context = InstrumentationRegistry.getTargetContext();
         return ((context.getResources().getConfiguration().uiMode &
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
index 4766268..ef44528 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
@@ -41,6 +41,7 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
+import android.os.SystemProperties;
 import android.platform.test.annotations.LargeTest;
 import android.platform.test.annotations.RequiresDevice;
 import android.system.ErrnoException;
@@ -1012,6 +1013,9 @@
     public void testDecode10BitHEIFTo10BitBitmap() {
         assumeTrue(
             "Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
+        assumeTrue(
+            "Test needs VNDK at least T.",
+            SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
         assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
 
         BitmapFactory.Options opt = new BitmapFactory.Options();
@@ -1028,6 +1032,9 @@
     public void testDecode10BitHEIFTo8BitBitmap() {
         assumeTrue(
             "Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
+        assumeTrue(
+            "Test needs VNDK at least T.",
+            SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
         assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
 
         BitmapFactory.Options opt = new BitmapFactory.Options();
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 6741c07..b6689d8 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -49,6 +49,7 @@
 import android.media.MediaFormat;
 import android.net.Uri;
 import android.os.Build;
+import android.os.SystemProperties;
 import android.util.DisplayMetrics;
 import android.util.Size;
 import android.util.TypedValue;
@@ -246,6 +247,9 @@
     public void testDecode10BitHeif() {
         assumeTrue(
             "Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
+        assumeTrue(
+            "Test needs VNDK at least T.",
+            SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
         assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
 
         try {
diff --git a/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java b/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java
index 848d74c..c273a18 100644
--- a/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java
+++ b/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java
@@ -808,7 +808,7 @@
     }
 
     private MediaRecorder allocMediaRecorder() throws Exception {
-        final String outputPath = new File(Environment.getExternalStorageDirectory(),
+        final String outputPath = new File(mContext.getExternalFilesDir(null),
             "record.out").getAbsolutePath();
         mOutFile = new File(outputPath);
         MediaRecorder mediaRecorder = new MediaRecorder();
diff --git a/tests/tests/media/codec/AndroidTest.xml b/tests/tests/media/codec/AndroidTest.xml
index ce2b7ed..a2f5d2b 100644
--- a/tests/tests/media/codec/AndroidTest.xml
+++ b/tests/tests/media/codec/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaCodecTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaCodecTestCases" />
+        <option name="version" value="7.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaCodecTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaCodecTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaCodecTestCases" />
-        <option name="version" value="7.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.codec.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/common/src/android/media/cts/CodecState.java b/tests/tests/media/common/src/android/media/cts/CodecState.java
index 13e56f8..4aa9db4 100644
--- a/tests/tests/media/common/src/android/media/cts/CodecState.java
+++ b/tests/tests/media/common/src/android/media/cts/CodecState.java
@@ -169,13 +169,15 @@
         }
     }
 
-    public void start() {
+    public void startCodec() {
         mCodec.start();
         mCodecInputBuffers = mCodec.getInputBuffers();
         if (!mIsTunneled || mIsAudio) {
             mCodecOutputBuffers = mCodec.getOutputBuffers();
         }
+    }
 
+    public void play() {
         if (mAudioTrack != null) {
             mAudioTrack.play();
         }
@@ -358,7 +360,7 @@
                 return null;
             }
 
-            if (mIsTunneled && !mIsAudio) {
+            if (mIsTunneled) {
                 if (mFirstSampleTimeUs == -1) {
                     mFirstSampleTimeUs = sampleTime;
                 }
diff --git a/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java b/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
index 5e4df7f..888cf23 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
@@ -487,11 +487,13 @@
         }
 
         for (CodecState state : mVideoCodecStates.values()) {
-            state.start();
+            state.startCodec();
+            state.play();
         }
 
         for (CodecState state : mAudioCodecStates.values()) {
-            state.start();
+            state.startCodec();
+            state.play();
         }
 
         mDeltaTimeUs = -1;
diff --git a/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java b/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
index 0b495dd..879f561 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
@@ -44,11 +44,13 @@
     /** State the player starts in, before configuration. */
     private static final int STATE_IDLE = 1;
     /** State of the player during initial configuration. */
-    private static final int STATE_PREPARING = 2;
+    private static final int STATE_PREPARED = 2;
+    /** State of the player after starting the codecs */
+    private static final int STATE_STARTED = 3;
     /** State of the player during playback. */
-    private static final int STATE_PLAYING = 3;
-    /** State of the player when configured but not playing. */
-    private static final int STATE_PAUSED = 4;
+    private static final int STATE_PLAYING = 4;
+    /** State of the player when playback is paused. */
+    private static final int STATE_PAUSED = 5;
 
     private Boolean mThreadStarted = false;
     private byte[] mSessionId;
@@ -194,7 +196,12 @@
         return true;
     }
 
+    // Creates the extractors, identifies tracks and formats, and then calls MediaCodec.configure
     public boolean prepare() throws IOException {
+        if (mState != STATE_IDLE) {
+            throw new IllegalStateException("Expected STATE_IDLE, got " + mState);
+        }
+
         if (null == mAudioExtractor) {
             mAudioExtractor = new MediaExtractor();
             if (null == mAudioExtractor) {
@@ -237,9 +244,7 @@
             return false;
         }
 
-        synchronized (mState) {
-            mState = STATE_PAUSED;
-        }
+        mState = STATE_PREPARED;
         return true;
     }
 
@@ -306,70 +311,56 @@
         return format.containsKey(key) ? format.getInteger(key) : 0;
     }
 
-    public boolean start() {
+    // Calls MediaCodec.start
+    public void startCodec() {
         Log.d(TAG, "start");
 
-        synchronized (mState) {
-            if (mState == STATE_PLAYING || mState == STATE_PREPARING) {
-                return true;
-            } else if (mState == STATE_IDLE) {
-                mState = STATE_PREPARING;
-                return true;
-            } else if (mState != STATE_PAUSED) {
-                throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
-            }
-
-            for (CodecState state : mVideoCodecStates.values()) {
-                state.start();
-            }
-
-            for (CodecState state : mAudioCodecStates.values()) {
-                state.start();
-            }
-
-            mDeltaTimeUs = -1;
-            mState = STATE_PLAYING;
+        if (mState != STATE_PREPARED) {
+            throw new IllegalStateException("Expected STATE_PREAPRED, got " + mState);
         }
-        return false;
+
+        for (CodecState state : mVideoCodecStates.values()) {
+            state.startCodec();
+        }
+
+        for (CodecState state : mAudioCodecStates.values()) {
+            state.startCodec();
+        }
+
+        mDeltaTimeUs = -1;
+        mState = STATE_STARTED;
     }
 
-    public void startWork() throws IOException, Exception {
-        try {
-            // Just change state from STATE_IDLE to STATE_PREPARING.
-            start();
-            // Extract media information from uri asset, and change state to STATE_PAUSED.
-            prepare();
-            // Start CodecState, and change from STATE_PAUSED to STATE_PLAYING.
-            start();
-        } catch (IOException e) {
-            throw e;
+    // Starts the decoding threads and then starts AudioTrack playback
+    public void play() {
+        if (mState != STATE_STARTED) {
+            throw new IllegalStateException("Expected STATE_STARTED, got " + mState);
         }
+        mState = STATE_PLAYING;
 
         synchronized (mThreadStarted) {
             mThreadStarted = true;
             mThread.start();
         }
-    }
 
-    public void startThread() {
-        start();
-        synchronized (mThreadStarted) {
-            mThreadStarted = true;
-            mThread.start();
+        for (CodecState state : mVideoCodecStates.values()) {
+            state.play();
+        }
+
+        for (CodecState state : mAudioCodecStates.values()) {
+            state.play();
         }
     }
 
-    // Pauses the audio track
+    // Pauses playback by pausing the AudioTrack
     public void pause() {
         Log.d(TAG, "pause");
 
-        synchronized (mState) {
-            if (mState == STATE_PAUSED) {
-                return;
-            } else if (mState != STATE_PLAYING) {
-                throw new IllegalStateException();
-            }
+        if (mState != STATE_PLAYING) {
+            throw new IllegalStateException("Expected STATE_PLAYING, got " + mState);
+        }
 
+        synchronized (mState) {
             for (CodecState state : mVideoCodecStates.values()) {
                 state.pause();
             }
@@ -382,43 +373,60 @@
         }
     }
 
-    public void flush() {
-        Log.d(TAG, "flush");
+    // Resume playback when paused
+    public void resume() {
+        Log.d(TAG, "resume");
+
+        if (mState != STATE_PAUSED) {
+            throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
+        }
 
         synchronized (mState) {
-            if (mState == STATE_PLAYING || mState == STATE_PREPARING) {
-                return;
+            for (CodecState state : mVideoCodecStates.values()) {
+                state.play();
             }
 
             for (CodecState state : mAudioCodecStates.values()) {
-                state.flush();
+                state.play();
             }
 
-            for (CodecState state : mVideoCodecStates.values()) {
-                state.flush();
-            }
+            mState = STATE_PLAYING;
         }
     }
 
-    /** Seek all tracks to their very beginning.
+    public void flush() {
+        Log.d(TAG, "flush");
+
+        if (mState != STATE_PAUSED) {
+            throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
+        }
+
+        for (CodecState state : mAudioCodecStates.values()) {
+            state.flush();
+        }
+
+        for (CodecState state : mVideoCodecStates.values()) {
+            state.flush();
+        }
+    }
+
+    /** Seek all tracks to the first sample time.
      *
      * @param  presentationTimeOffsetUs The offset for the presentation time to start at.
      * @throws IllegalStateException  if the player is not paused
      */
     public void seekToBeginning(long presentationTimeOffsetUs) {
         Log.d(TAG, "seekToBeginning");
-        synchronized (mState) {
-            if (mState != STATE_PAUSED) {
-                throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
-            }
+        if (mState != STATE_PAUSED) {
+            throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
+        }
 
-            for (CodecState state : mVideoCodecStates.values()) {
-                state.seekToBeginning(presentationTimeOffsetUs);
-            }
+        for (CodecState state : mVideoCodecStates.values()) {
+            state.seekToBeginning(presentationTimeOffsetUs);
+        }
 
-            for (CodecState state : mAudioCodecStates.values()) {
-                state.seekToBeginning(presentationTimeOffsetUs);
-            }
+        for (CodecState state : mAudioCodecStates.values()) {
+            state.seekToBeginning(presentationTimeOffsetUs);
         }
     }
 
@@ -426,53 +434,50 @@
      * Enables or disables looping. Should be called after {@link #prepare()}.
      */
     public void setLoopEnabled(boolean enabled) {
-        synchronized (mState) {
-            if (mVideoCodecStates != null) {
-                for (CodecState state : mVideoCodecStates.values()) {
-                    state.setLoopEnabled(enabled);
-                }
-            }
+        if (mState != STATE_PREPARED) {
+            throw new IllegalStateException("Expected STATE_PREPARED, got " + mState);
+        }
 
-            if (mAudioCodecStates != null) {
-                for (CodecState state : mAudioCodecStates.values()) {
-                    state.setLoopEnabled(enabled);
-                }
-            }
+        for (CodecState state : mVideoCodecStates.values()) {
+            state.setLoopEnabled(enabled);
+        }
+
+        for (CodecState state : mAudioCodecStates.values()) {
+            state.setLoopEnabled(enabled);
         }
     }
 
     public void reset() {
-        synchronized (mState) {
-            if (mState == STATE_PLAYING) {
-                pause();
-            }
-            if (mVideoCodecStates != null) {
-                for (CodecState state : mVideoCodecStates.values()) {
-                    state.release();
-                }
-                mVideoCodecStates = null;
-            }
-
-            if (mAudioCodecStates != null) {
-                for (CodecState state : mAudioCodecStates.values()) {
-                    state.release();
-                }
-                mAudioCodecStates = null;
-            }
-
-            if (mAudioExtractor != null) {
-                mAudioExtractor.release();
-                mAudioExtractor = null;
-            }
-
-            if (mVideoExtractor != null) {
-                mVideoExtractor.release();
-                mVideoExtractor = null;
-            }
-
-            mDurationUs = -1;
-            mState = STATE_IDLE;
+        if (mState == STATE_PLAYING) {
+            pause();
         }
+        if (mVideoCodecStates != null) {
+            for (CodecState state : mVideoCodecStates.values()) {
+                state.release();
+            }
+            mVideoCodecStates = null;
+        }
+
+        if (mAudioCodecStates != null) {
+            for (CodecState state : mAudioCodecStates.values()) {
+                state.release();
+            }
+            mAudioCodecStates = null;
+        }
+
+        if (mAudioExtractor != null) {
+            mAudioExtractor.release();
+            mAudioExtractor = null;
+        }
+
+        if (mVideoExtractor != null) {
+            mVideoExtractor.release();
+            mVideoExtractor = null;
+        }
+
+        mDurationUs = -1;
+        mState = STATE_IDLE;
+
         synchronized (mThreadStarted) {
             mThreadStarted = false;
         }
@@ -607,6 +612,14 @@
         return mVideoCodecStates.get(0).getVideoTimeUs();
     }
 
+    public long getVideoSystemTimeNs() {
+        if (mVideoCodecStates == null || mVideoCodecStates.get(0) == null) {
+            return -1;
+        }
+        return mVideoCodecStates.get(0).getVideoTimeUs();
+
+    }
+
     /**
      * Returns the ordered list of video frame timestamps rendered in tunnel mode.
      *
@@ -643,39 +656,23 @@
     public Long queueOneVideoFrame() {
         Log.d(TAG, "queueOneVideoFrame");
 
-        if (mVideoCodecStates == null || !(mState == STATE_PLAYING || mState == STATE_PAUSED)) {
-            return null;
+        if (mState != STATE_STARTED && mState != STATE_PAUSED) {
+            throw new IllegalStateException("Expected STARTED or PAUSED, got " + mState);
         }
 
         Long result = null;
-        for (CodecState state : mVideoCodecStates.values()) {
-            Long timestamp = state.doSomeWork(true /* mustWait */);
-            if (timestamp != null) {
-                result = timestamp;
+        if (mVideoCodecStates != null) {
+            for (CodecState state : mVideoCodecStates.values()) {
+                Long timestamp = state.doSomeWork(true /* mustWait */);
+                if (timestamp != null) {
+                    result = timestamp;
+                }
             }
         }
         return result;
     }
 
     /**
-     * Resume playback when paused.
-     *
-     * @throws IllegalStateException if playback is not paused or if there is no configured audio
-     *                               track.
-     */
-    public void resume() {
-        Log.d(TAG, "resume");
-        if (mAudioTrackState == null) {
-            throw new IllegalStateException("Resuming playback with no audio track");
-        }
-        if (mState != STATE_PAUSED) {
-            throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
-        }
-        mAudioTrackState.playAudioTrack();
-        mState = STATE_PLAYING;
-    }
-
-    /**
      * Configure video peek for the video codecs attached to the player.
      */
     public void setVideoPeek(boolean enable) {
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 f98b3ab..20bf143 100644
--- a/tests/tests/media/common/src/android/media/cts/TestUtils.java
+++ b/tests/tests/media/common/src/android/media/cts/TestUtils.java
@@ -190,6 +190,7 @@
         if (name.startsWith("c2.android.")) {
             return true;
         }
+        Log.d(TAG, "Test mode MTS does not test codec " + name);
         return false;
     }
 
diff --git a/tests/tests/media/decoder/AndroidTest.xml b/tests/tests/media/decoder/AndroidTest.xml
index c7d4550..55fe608 100644
--- a/tests/tests/media/decoder/AndroidTest.xml
+++ b/tests/tests/media/decoder/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaDecoderTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaDecoderTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaDecoderTestCases-1.1" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaDecoderTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaDecoderTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.decoder.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
index 145cfaf..c982376 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
@@ -25,7 +25,6 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.media.MediaFormat;
-import android.media.cts.MediaCodecTunneledPlayer;
 import android.media.cts.MediaHeavyPresubmitTest;
 import android.media.cts.TestArgs;
 import android.os.Environment;
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
index a424edb..9926f04 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
@@ -73,6 +73,7 @@
 import androidx.test.filters.SdkSuppress;
 
 import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.DynamicConfigDeviceSide;
@@ -124,10 +125,10 @@
     private static final int CONFIG_MODE_NONE = 0;
     private static final int CONFIG_MODE_QUEUE = 1;
 
-    private static final int CODEC_ALL = 0; // All codecs must support
-    private static final int CODEC_ANY = 1; // At least one codec must support
-    private static final int CODEC_DEFAULT = 2; // Default codec must support
-    private static final int CODEC_OPTIONAL = 3; // Codec support is optional
+    public static final int CODEC_ALL = 0; // All codecs must support
+    public static final int CODEC_ANY = 1; // At least one codec must support
+    public static final int CODEC_DEFAULT = 2; // Default codec must support
+    public static final int CODEC_OPTIONAL = 3; // Codec support is optional
 
     short[] mMasterBuffer;
     static final String mInpPrefix = WorkDir.getMediaDirString();
@@ -141,8 +142,6 @@
     private DisplayManager mDisplayManager;
     static final Map<String, String> sDefaultDecoders = new HashMap<>();
 
-    private static boolean mIsAtLeastS = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S);
-
     protected static AssetFileDescriptor getAssetFileDescriptorFor(final String res)
             throws FileNotFoundException {
         File inpFile = new File(mInpPrefix + res);
@@ -3884,11 +3883,10 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
 
-        // starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -3921,8 +3919,8 @@
     /**
      * Test tunneled video playback mode with HEVC if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledVideoPlaybackHevc() throws Exception {
         tunneledVideoPlayback(MediaFormat.MIMETYPE_VIDEO_HEVC,
                     "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
@@ -3931,8 +3929,8 @@
     /**
      * Test tunneled video playback mode with AVC if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledVideoPlaybackAvc() throws Exception {
         tunneledVideoPlayback(MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
@@ -3941,8 +3939,8 @@
     /**
      * Test tunneled video playback mode with VP9 if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledVideoPlaybackVp9() throws Exception {
         tunneledVideoPlayback(MediaFormat.MIMETYPE_VIDEO_VP9,
                     "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
@@ -3966,11 +3964,10 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
 
-        // starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -3990,8 +3987,8 @@
     /**
      * Test tunneled video playback flush with HEVC if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledVideoFlushHevc() throws Exception {
         testTunneledVideoFlush(MediaFormat.MIMETYPE_VIDEO_HEVC,
                 "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
@@ -4000,8 +3997,8 @@
     /**
      * Test tunneled video playback flush with AVC if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledVideoFlushAvc() throws Exception {
         testTunneledVideoFlush(MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
@@ -4010,23 +4007,19 @@
     /**
      * Test tunneled video playback flush with VP9 if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledVideoFlushVp9() throws Exception {
         testTunneledVideoFlush(MediaFormat.MIMETYPE_VIDEO_VP9,
                 "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
     }
 
     /**
-     * Test tunneled video peek renders the first frame when on
+     * Test that the first frame is rendered when video peek is on in tunneled mode.
      *
      * TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
      */
     private void testTunneledVideoPeekOn(String mimeType, String videoName) throws Exception {
-        if (!MediaUtils.check(mIsAtLeastS, "testTunneledVideoPeekOn requires Android 12")) {
-            return;
-        }
-
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                     "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
@@ -4040,9 +4033,8 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
-        mMediaCodecPlayer.start();
+        mMediaCodecPlayer.startCodec();
         mMediaCodecPlayer.setVideoPeek(true); // Enable video peek
 
         // Assert that onFirstTunnelFrameReady is called
@@ -4061,30 +4053,30 @@
     }
 
     /**
-     * Test tunneled video peek with HEVC renders the first frame when on
+     * Test that the first frame is rendered when video peek is on for HEVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
     public void testTunneledVideoPeekOnHevc() throws Exception {
         testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_HEVC,
                 "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
     }
 
     /**
-     * Test tunneled video peek with AVC renders the first frame when on
+     * Test that the first frame is rendered when video peek is on for AVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
     public void testTunneledVideoPeekOnAvc() throws Exception {
         testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
     }
 
     /**
-     * Test tunneled video peek with VP9 renders the first frame when on
+     * Test that the first frame is rendered when video peek is on for VP9 in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
     public void testTunneledVideoPeekOnVp9() throws Exception {
         testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_VP9,
                 "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
@@ -4092,15 +4084,11 @@
 
 
     /**
-     * Test tunneled video peek doesn't render the first frame when off and then turned on
+     * Test that peek off doesn't render the first frame until turned on in tunneled mode.
      *
      * TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
      */
     private void testTunneledVideoPeekOff(String mimeType, String videoName) throws Exception {
-        if (!MediaUtils.check(mIsAtLeastS, "testTunneledVideoPeekOff requires Android 12")) {
-            return;
-        }
-
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                     "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
@@ -4114,9 +4102,8 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
-        mMediaCodecPlayer.start();
+        mMediaCodecPlayer.startCodec();
         mMediaCodecPlayer.setVideoPeek(false); // Disable video peek
 
         // Assert that onFirstTunnelFrameReady is called
@@ -4142,75 +4129,40 @@
     }
 
     /**
-     * Test tunneled video peek with HEVC doesn't render the first frame when off and then turned on
+     * Test that peek off doesn't render the first frame until turned on for HEC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
     public void testTunneledVideoPeekOffHevc() throws Exception {
         testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_HEVC,
                 "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
     }
 
     /**
-     * Test tunneled video peek with AVC doesn't render the first frame when off and then turned on
+     * Test that peek off doesn't render the first frame until turned on for AVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
     public void testTunneledVideoPeekOffAvc() throws Exception {
         testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
     }
 
     /**
-     * Test tunneled video peek with VP9 doesn't render the first frame when off and then turned on
+     * Test that peek off doesn't render the first frame until turned on for VP9 in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
     public void testTunneledVideoPeekOffVp9() throws Exception {
         testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_VP9,
                 "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
     }
 
-    /**
-     * Test tunneled audio PTS gaps with HEVC if supported.
-     * If there exist PTS Gaps in AudioTrack playback, the framePosition returned by
-     * AudioTrack#getTimestamp must not advance for any silent frames rendered to fill the
-     * gap.
-     */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
-    @Test
-    public void testTunneledAudioPtsGapsHevc() throws Exception {
-        testTunneledAudioPtsGaps(MediaFormat.MIMETYPE_VIDEO_HEVC,
-                "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
-    }
-
-    /**
-     * Test tunneled audio PTS gaps with AVC if supported
-     * If there exist PTS Gaps in AudioTrack playback, the framePosition returned by
-     * AudioTrack#getTimestamp must not advance for any silent frames rendered to fill the
-     * gap.
-     */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
-    @Test
-    public void testTunneledAudioPtsGapsAvc() throws Exception {
-        testTunneledAudioPtsGaps(MediaFormat.MIMETYPE_VIDEO_AVC,
-                "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
-    }
-
-    /**
-     * Test tunneled audio PTS gaps with VP9 if supported
-     * If there exist PTS Gaps in AudioTrack playback, the framePosition returned by
-     * AudioTrack#getTimestamp must not advance for any silent frames rendered to fill the
-     * gap.
-     */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
-    @Test
-    public void testTunneledAudioPtsGapsVp9() throws Exception {
-        testTunneledAudioPtsGaps(MediaFormat.MIMETYPE_VIDEO_VP9,
-                "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
-    }
-
-    private void testTunneledAudioPtsGaps(String mimeType, String fileName) throws Exception {
+   /**
+    * Test that audio timestamps don't progress during audio PTS gaps in tunneled mode.
+    */
+   private void testTunneledAudioProgressWithPtsGaps(String mimeType, String fileName)
+            throws Exception {
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                     "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
@@ -4224,11 +4176,10 @@
         final Uri mediaUri = Uri.fromFile(new File(mInpPrefix, fileName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
 
-        // starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -4291,37 +4242,40 @@
     }
 
     /**
-     * Test tunneled audioTimestamp progress with underrun, with HEVC if supported
+     * Test that audio timestamps don't progress during audio PTS gaps for HEVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
-    public void testTunneledAudioTimestampProgressWithUnderrunHevc() throws Exception {
-        testTunneledAudioTimestampProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_HEVC,
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithPtsGapsHevc() throws Exception {
+        testTunneledAudioProgressWithPtsGaps(MediaFormat.MIMETYPE_VIDEO_HEVC,
                 "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
     }
 
     /**
-     * Test tunneled audioTimestamp progress with underrun, with AVC if supported.
+     * Test that audio timestamps don't progress during audio PTS gaps for AVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
-    public void testTunneledAudioTimestampProgressWithUnderrunAvc() throws Exception {
-        testTunneledAudioTimestampProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_AVC,
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithPtsGapsAvc() throws Exception {
+        testTunneledAudioProgressWithPtsGaps(MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
     }
 
     /**
-     *  Test tunneled audioTimestamp progress with underrun, with VP9 if supported.
+     * Test that audio timestamps don't progress during audio PTS gaps for VP9 in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
-    public void testTunneledAudioTimestampProgressWithUnderrunVp9() throws Exception {
-        testTunneledAudioTimestampProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_VP9,
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithPtsGapsVp9() throws Exception {
+        testTunneledAudioProgressWithPtsGaps(MediaFormat.MIMETYPE_VIDEO_VP9,
                 "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
     }
 
-    private void testTunneledAudioTimestampProgressWithUnderrun(
-            String mimeType, String fileName) throws Exception {
+    /**
+     * Test that audio timestamps stop progressing during underrun in tunneled mode.
+     */
+    private void testTunneledAudioProgressWithUnderrun(String mimeType, String fileName)
+            throws Exception {
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                 "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
@@ -4335,11 +4289,10 @@
         final Uri mediaUri = Uri.fromFile(new File(mInpPrefix, fileName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
 
-        // starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -4380,9 +4333,39 @@
     }
 
     /**
-     * Test accurate video rendering after a video MediaCodec flush.
+     * Test that audio timestamps stop progressing during underrun for HEVC in tunneled mode.
+     */
+    @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithUnderrunHevc() throws Exception {
+        testTunneledAudioProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_HEVC,
+                "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
+    }
+
+    /**
+     * Test that audio timestamps stop progressing during underrun for AVC in tunneled mode.
+     */
+    @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithUnderrunAvc() throws Exception {
+        testTunneledAudioProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_AVC,
+                "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
+    }
+
+    /**
+     * Test that audio timestamps stop progressing during underrun for VP9 in tunneled mode.
+     */
+    @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithUnderrunVp9() throws Exception {
+        testTunneledAudioProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_VP9,
+                "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
+    }
+
+    /**
+     * Test accurate video rendering after a flush in tunneled mode.
      *
-     * On some devices, queuing content when the player is paused, then triggering a flush, then
+     * Test On some devices, queuing content when the player is paused, then triggering a flush, then
      * queuing more content does not behave as expected. The queued content gets lost and the flush
      * is really only applied once playback has resumed.
      *
@@ -4390,10 +4373,6 @@
      */
     private void testTunneledAccurateVideoFlush(String mimeType, String videoName)
             throws Exception {
-        if (!MediaUtils.check(mIsAtLeastS, "testTunneledAccurateVideoFlush requires Android 12")) {
-            return;
-        }
-
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                     "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
@@ -4414,15 +4393,14 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
         // Video peek might interfere with the test: we want to ensure that queuing more data during
         // a pause does not cause displaying more video frames, which is precisely what video peek
         // does.
         mMediaCodecPlayer.setVideoPeek(false);
 
-        // starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -4434,22 +4412,72 @@
         assertNotEquals("Audio timestamp has a zero frame position",
                 mMediaCodecPlayer.getTimestamp().framePosition, 0);
 
+        // Allow some time for playback to commence
+        Thread.sleep(500);
+
         // Pause playback
         mMediaCodecPlayer.pause();
-        // Allow some time for playback to pause
-        Thread.sleep(maxDrainTimeMs);
 
-        // Verify that playback has paused
-        long pauseAudioFramePositionUs = mMediaCodecPlayer.getTimestamp().framePosition;
-        long pauseVideoPositionUs = mMediaCodecPlayer.getVideoTimeUs();
-        Thread.sleep(maxDrainTimeMs);
-        assertEquals(mMediaCodecPlayer.getTimestamp().framePosition, pauseAudioFramePositionUs);
+        // Wait for audio to pause
+        AudioTimestamp pauseAudioTimestamp;
+        {
+            AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+            long startTimeMs = System.currentTimeMillis();
+            do {
+                // If it takes longer to pause, the UX won't feel responsive to the user
+                int audioPauseTimeoutMs = 250;
+                assertTrue(String.format("No audio pause after %d milliseconds",
+                                audioPauseTimeoutMs),
+                        System.currentTimeMillis() - startTimeMs < audioPauseTimeoutMs);
+                pauseAudioTimestamp = currentAudioTimestamp;
+                Thread.sleep(50);
+                currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+            } while (currentAudioTimestamp.framePosition != pauseAudioTimestamp.framePosition);
+        }
+        long pauseAudioSystemTimeMs = pauseAudioTimestamp.nanoTime / 1000 / 1000;
+
+        // Wait for video to pause
+        long pauseVideoSystemTimeNs;
+        long pauseVideoPositionUs;
+        {
+            long currentVideoSystemTimeNs = mMediaCodecPlayer.getCurrentRenderedSystemTimeNano();
+            long startTimeMs = System.currentTimeMillis();
+            do {
+                int videoUnderrunTimeoutMs = 2000;
+                assertTrue(String.format("No video pause after %d milliseconds",
+                                videoUnderrunTimeoutMs),
+                        System.currentTimeMillis() - startTimeMs < videoUnderrunTimeoutMs);
+                pauseVideoSystemTimeNs = currentVideoSystemTimeNs;
+                Thread.sleep(250); // onFrameRendered can get delayed in the Framework
+                currentVideoSystemTimeNs = mMediaCodecPlayer.getCurrentRenderedSystemTimeNano();
+            } while (currentVideoSystemTimeNs != pauseVideoSystemTimeNs);
+            pauseVideoPositionUs = mMediaCodecPlayer.getVideoTimeUs();
+        }
+        long pauseVideoSystemTimeMs = pauseVideoSystemTimeNs / 1000 / 1000;
+
+        // Video should not continue running for a long period of time after audio pauses
+        long pauseVideoToleranceMs = 500;
+        assertTrue(String.format(
+                        "Video ran %d milliseconds longer than audio (video:%d audio:%d)",
+                        pauseVideoToleranceMs, pauseVideoSystemTimeMs, pauseAudioSystemTimeMs),
+                pauseVideoSystemTimeMs - pauseAudioSystemTimeMs < pauseVideoToleranceMs);
+
+        // Verify that playback stays paused
+        Thread.sleep(500);
+        assertEquals(mMediaCodecPlayer.getTimestamp().framePosition, pauseAudioTimestamp.framePosition);
+        assertEquals(mMediaCodecPlayer.getCurrentRenderedSystemTimeNano(), pauseVideoSystemTimeNs);
         assertEquals(mMediaCodecPlayer.getVideoTimeUs(), pauseVideoPositionUs);
 
-        // Verify audio and video are in sync
-        assertTrue(String.format("Video pts (%d) is ahead of audio pts (%d)",
-                        pauseVideoPositionUs, pauseAudioFramePositionUs),
-                pauseVideoPositionUs <= pauseAudioFramePositionUs);
+        // Verify audio and video are roughly in sync when paused
+        long framePosition = mMediaCodecPlayer.getTimestamp().framePosition;
+        long playbackRateFps = mMediaCodecPlayer.getAudioTrack().getPlaybackRate();
+        long pauseAudioPositionMs = pauseAudioTimestamp.framePosition * 1000 / playbackRateFps;
+        long pauseVideoPositionMs = pauseVideoPositionUs / 1000;
+        long deltaMs = pauseVideoPositionMs - pauseAudioPositionMs;
+        assertTrue(String.format(
+                        "Video is %d milliseconds out of sync from audio (video:%d audio:%d)",
+                        deltaMs, pauseVideoPositionMs, pauseAudioPositionMs),
+                deltaMs > -80 && deltaMs < pauseVideoToleranceMs);
 
         // Flush both audio and video pipelines
         mMediaCodecPlayer.flush();
@@ -4493,8 +4521,8 @@
     /**
      * Test accurate video rendering after a video MediaCodec flush with HEVC if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledAccurateVideoFlushHevc() throws Exception {
         testTunneledAccurateVideoFlush(MediaFormat.MIMETYPE_VIDEO_HEVC,
                 "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
@@ -4503,8 +4531,8 @@
     /**
      * Test accurate video rendering after a video MediaCodec flush with AVC if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledAccurateVideoFlushAvc() throws Exception {
         testTunneledAccurateVideoFlush(MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
@@ -4513,49 +4541,18 @@
     /**
      * Test accurate video rendering after a video MediaCodec flush with VP9 if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledAccurateVideoFlushVp9() throws Exception {
         testTunneledAccurateVideoFlush(MediaFormat.MIMETYPE_VIDEO_VP9,
                 "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
     }
 
     /**
-     * Test tunneled audioTimestamp progress with HEVC if supported
+     * Test that audio timestamps stop progressing during pause in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
-    @Test
-    public void testTunneledAudioTimestampProgressHevc() throws Exception {
-        testTunneledAudioTimestampProgress(MediaFormat.MIMETYPE_VIDEO_HEVC,
-                "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
-    }
-
-    /**
-     * Test tunneled audioTimestamp progress with AVC if supported
-     */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
-    @Test
-    public void testTunneledAudioTimestampProgressAvc() throws Exception {
-        testTunneledAudioTimestampProgress(MediaFormat.MIMETYPE_VIDEO_AVC,
-                "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
-    }
-
-    /**
-     * Test tunneled audioTimestamp progress with VP9 if supported
-     */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
-    @Test
-    public void testTunneledAudioTimestampProgressVp9() throws Exception {
-        testTunneledAudioTimestampProgress(MediaFormat.MIMETYPE_VIDEO_VP9,
-                "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
-    }
-
-    /**
-     * Test that AudioTrack timestamps don't advance after pause.
-     */
-    private void
-    testTunneledAudioTimestampProgress(String mimeType, String videoName) throws Exception
-    {
+    private void testTunneledAudioProgressWithPause(String mimeType, String videoName)
+            throws Exception {
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                     "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
@@ -4568,11 +4565,10 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
 
-        // starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -4604,14 +4600,43 @@
         assertEquals(audioTimestampAfterPause.nanoTime, mMediaCodecPlayer.getTimestamp().nanoTime);
     }
 
+
     /**
-     * Test tunneled audio underrun, if supported.
-     *
-     * Underrun test with lower pts after underrun.
+     * Test that audio timestamps stop progressing during pause for HEVC in tunneled mode.
+     */
+    @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithPauseHevc() throws Exception {
+        testTunneledAudioProgressWithPause(MediaFormat.MIMETYPE_VIDEO_HEVC,
+                "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
+    }
+
+    /**
+     * Test that audio timestamps stop progressing during pause for AVC in tunneled mode.
+     */
+    @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithPauseAvc() throws Exception {
+        testTunneledAudioProgressWithPause(MediaFormat.MIMETYPE_VIDEO_AVC,
+                "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
+    }
+
+    /**
+     * Test that audio timestamps stop progressing during pause for VP9 in tunneled mode.
+     */
+    @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithPauseVp9() throws Exception {
+        testTunneledAudioProgressWithPause(MediaFormat.MIMETYPE_VIDEO_VP9,
+                "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
+    }
+
+    /**
+     * Test that audio underrun pauses video and resumes in-sync in tunneled mode.
      *
      * TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
      */
-    private void tunneledAudioUnderrun(String mimeType, String videoName, int frameRate)
+    private void tunneledAudioUnderrun(String mimeType, String videoName)
             throws Exception {
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                 "No tunneled video playback codec found for MIME " + mimeType)) {
@@ -4625,11 +4650,10 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
 
-        // Starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -4645,36 +4669,39 @@
         mMediaCodecPlayer.simulateAudioUnderrun(true);
 
         // Wait for audio underrun
-        final int audioUnderrunTimeoutMs = 1000; // Arbitrary upper time limit on loop time duration
-        long startTimeMs = System.currentTimeMillis();
-        AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
         AudioTimestamp underrunAudioTimestamp;
-        do {
-            assertTrue(String.format("No audio underrun after %d milliseconds",
-                            System.currentTimeMillis() - startTimeMs),
-                    System.currentTimeMillis() - startTimeMs < audioUnderrunTimeoutMs);
-            underrunAudioTimestamp = currentAudioTimestamp;
-            Thread.sleep(50);
-            currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
-        } while (currentAudioTimestamp.framePosition != underrunAudioTimestamp.framePosition);
+        {
+            AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+            long startTimeMs = System.currentTimeMillis();
+            do {
+                int audioUnderrunTimeoutMs = 1000;
+                assertTrue(String.format("No audio underrun after %d milliseconds",
+                                System.currentTimeMillis() - startTimeMs),
+                        System.currentTimeMillis() - startTimeMs < audioUnderrunTimeoutMs);
+                underrunAudioTimestamp = currentAudioTimestamp;
+                Thread.sleep(50);
+                currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+            } while (currentAudioTimestamp.framePosition != underrunAudioTimestamp.framePosition);
+        }
 
+        // Wait until video playback pauses due to underrunning audio
+        long pausedVideoTimeUs = -1;
+        {
+            long currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+            long startTimeMs = System.currentTimeMillis();
+            do {
+                int videoPauseTimeoutMs = 2000;
+                assertTrue(String.format("No video pause after %d milliseconds",
+                                videoPauseTimeoutMs),
+                        System.currentTimeMillis() - startTimeMs < videoPauseTimeoutMs);
+                pausedVideoTimeUs = currentVideoTimeUs;
+                Thread.sleep(250); // onFrameRendered messages can get delayed in the Framework
+                currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+            } while (currentVideoTimeUs != pausedVideoTimeUs);
+        }
 
-        // Wait until video playback stalls
-        final int videoUnderrunTimeoutMs = 1000;
-        startTimeMs = System.currentTimeMillis();
-        long currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
-        long underrunVideoTimeUs = -1;
-        do {
-            assertTrue(String.format("No video underrun after %d milliseconds",
-                            videoUnderrunTimeoutMs),
-                    System.currentTimeMillis() - startTimeMs < videoUnderrunTimeoutMs);
-            underrunVideoTimeUs = currentVideoTimeUs;
-            Thread.sleep(50);
-            currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
-        } while (currentVideoTimeUs != underrunVideoTimeUs);
-
-        // Retrieve index for the video rendered frame at the time of underrun
-        int underrunVideoRenderedTimestampIndex =
+        // Retrieve index for the video rendered frame at the time of video pausing
+        int pausedVideoRenderedTimestampIndex =
                 mMediaCodecPlayer.getRenderedVideoFrameTimestampList().size() - 1;
 
         // Resume audio buffering with a negative offset, in order to simulate a desynchronisation.
@@ -4683,35 +4710,38 @@
         mMediaCodecPlayer.simulateAudioUnderrun(false);
 
         // Wait until audio playback resumes
-        final int audioResumeTimeoutMs = 1000;
-        startTimeMs = System.currentTimeMillis();
-        currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
         AudioTimestamp postResumeAudioTimestamp;
-        do {
-            assertTrue(String.format("Audio has not resumed after %d milliseconds",
-                            audioResumeTimeoutMs),
-                    System.currentTimeMillis() - startTimeMs < audioResumeTimeoutMs);
-            postResumeAudioTimestamp = currentAudioTimestamp;
-            Thread.sleep(50);
-            currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
-        } while(currentAudioTimestamp.framePosition == postResumeAudioTimestamp.framePosition);
+        {
+            AudioTimestamp previousAudioTimestamp;
+            long startTimeMs = System.currentTimeMillis();
+            do {
+                int audioResumeTimeoutMs = 1000;
+                assertTrue(String.format("Audio has not resumed after %d milliseconds",
+                                audioResumeTimeoutMs),
+                        System.currentTimeMillis() - startTimeMs < audioResumeTimeoutMs);
+                previousAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+                Thread.sleep(50);
+                postResumeAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+            } while (postResumeAudioTimestamp.framePosition == previousAudioTimestamp.framePosition);
+        }
 
         // Now that audio playback has resumed, wait until video playback resumes
-        // We care about the timestamp of the first output frame, rather than the exact time the
-        // video resumed, which is why we only start polling after we are sure audio playback has
-        // resumed.
-        final int videoResumeTimeoutMs = 1000;
-        startTimeMs = System.currentTimeMillis();
-        currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
-        long resumeVideoTimeUs = -1;
-        do {
-            assertTrue(String.format("Video has not resumed after %d milliseconds",
-                            videoResumeTimeoutMs),
-                    System.currentTimeMillis() - startTimeMs < videoResumeTimeoutMs);
-            resumeVideoTimeUs = currentVideoTimeUs;
-            Thread.sleep(50);
-            currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
-        } while (currentVideoTimeUs == resumeVideoTimeUs);
+        {
+            // We actually don't care about trying to capture the exact time video resumed, because
+            // we can just look at the historical list of rendered video timestamps
+            long postResumeVideoTimeUs;
+            long previousVideoTimeUs;
+            long startTimeMs = System.currentTimeMillis();
+            do {
+                int videoResumeTimeoutMs = 2000;
+                assertTrue(String.format("Video has not resumed after %d milliseconds",
+                                videoResumeTimeoutMs),
+                        System.currentTimeMillis() - startTimeMs < videoResumeTimeoutMs);
+                previousVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+                Thread.sleep(50);
+                postResumeVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+            } while (postResumeVideoTimeUs == previousVideoTimeUs);
+        }
 
         // The system time when rendering the first audio frame after the resume
         long playbackRateFps = mMediaCodecPlayer.getAudioTrack().getPlaybackRate();
@@ -4721,52 +4751,74 @@
         long resumeAudioSystemTimeNs = postResumeAudioTimestamp.nanoTime - (long) elapsedTimeNs;
         long resumeAudioSystemTimeMs = resumeAudioSystemTimeNs / 1000 / 1000;
 
-        // The system time when rendering the first video frame after the resume
+        // The system time when rendering the first video frame after video playback resumes
         long resumeVideoSystemTimeMs = mMediaCodecPlayer.getRenderedVideoFrameSystemTimeList()
-                .get(underrunVideoRenderedTimestampIndex + 1) / 1000 / 1000;
+                .get(pausedVideoRenderedTimestampIndex + 1) / 1000 / 1000;
 
-        // Verify that audio and video are in-sync after resume time
+        // Verify that video resumes in a reasonable amount of time after audio resumes
         // Note: Because a -100ms PTS gap is introduced, the video should resume 100ms later
         resumeAudioSystemTimeMs += 100;
-        long vsyncMs = 1000 / frameRate;
-        long avSyncOffsetMs = resumeAudioSystemTimeMs - resumeVideoSystemTimeMs;
+        long resumeDeltaMs = resumeVideoSystemTimeMs - resumeAudioSystemTimeMs;
+        assertTrue(String.format("Video started %s milliseconds before audio resumed "
+                        + "(video:%d audio:%d)", resumeDeltaMs * -1, resumeVideoSystemTimeMs,
+                        resumeAudioSystemTimeMs),
+                resumeDeltaMs > 0); // video is expected to start after audio resumes
         assertTrue(String.format(
-                        "Audio is %d milliseconds out of sync of video (audio:%d video:%d)",
-                        avSyncOffsetMs, resumeAudioSystemTimeMs, resumeVideoSystemTimeMs),
-                Math.abs(avSyncOffsetMs) <= vsyncMs);
+                        "Video started %d milliseconds after audio resumed (video:%d audio:%d)",
+                        resumeDeltaMs, resumeVideoSystemTimeMs, resumeAudioSystemTimeMs),
+                resumeDeltaMs <= 600); // video starting 300ms after audio is barely noticeable
+
+        // Determine the system time of the audio frame that matches the presentation timestamp of
+        // the resumed video frame
+        long resumeVideoPresentationTimeUs = mMediaCodecPlayer.getRenderedVideoFrameTimestampList()
+                .get(pausedVideoRenderedTimestampIndex + 1);
+        long matchingAudioFramePosition = resumeVideoPresentationTimeUs * playbackRateFps / 1000 / 1000;
+        playedFrames = matchingAudioFramePosition - postResumeAudioTimestamp.framePosition;
+        elapsedTimeNs = playedFrames * (1000.0 * 1000.0 * 1000.0 / playbackRateFps);
+        long matchingAudioSystemTimeNs = postResumeAudioTimestamp.nanoTime + (long) elapsedTimeNs;
+        long matchingAudioSystemTimeMs = matchingAudioSystemTimeNs / 1000 / 1000;
+
+        // Verify that video and audio are in sync at the time when video resumes
+        // Note: Because a -100ms PTS gap is introduced, the video should resume 100ms later
+        matchingAudioSystemTimeMs += 100;
+        long avSyncOffsetMs =  resumeVideoSystemTimeMs - matchingAudioSystemTimeMs;
+        assertTrue(String.format("Video is %d milliseconds out of sync of audio after resuming "
+                        + "(video:%d, audio:%d)", avSyncOffsetMs, resumeVideoSystemTimeMs,
+                        matchingAudioSystemTimeMs),
+                // some leniency in AV sync is required because Android TV STB/OTT OEMs often have
+                // to tune for imperfect downstream TVs (that have processing delays on the video)
+                // by knowingly producing HDMI output that has audio and video mildly out of sync
+                Math.abs(avSyncOffsetMs) <= 80);
     }
 
     /**
-     * Test tunneled audio underrun with HEVC if supported
+     * Test that audio underrun pauses video and resumes in-sync for HEVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledAudioUnderrunHevc() throws Exception {
         tunneledAudioUnderrun(MediaFormat.MIMETYPE_VIDEO_HEVC,
-                "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv",
-                25);
+                "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
     }
 
     /**
-     * Test tunneled audio underrun with AVC if supported
+     * Test that audio underrun pauses video and resumes in-sync for AVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledAudioUnderrunAvc() throws Exception {
         tunneledAudioUnderrun(MediaFormat.MIMETYPE_VIDEO_AVC,
-                "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4",
-                25);
+                "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
     }
 
     /**
-     * Test tunneled audio underrun with VP9 if supported
+     * Test that audio underrun pauses video and resumes in-sync for VP9 in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledAudioUnderrunVp9() throws Exception {
         tunneledAudioUnderrun(MediaFormat.MIMETYPE_VIDEO_VP9,
-                "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm",
-                30);
+                "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
     }
 
     private void sleepUntil(Supplier<Boolean> supplier, Duration maxWait) throws Exception {
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java
index f34f9e2..0857809 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java
@@ -81,9 +81,9 @@
                         AudioFormat.CHANNEL_OUT_QUAD | AudioFormat.CHANNEL_OUT_FRONT_CENTER},
                 {"noise_6ch_44khz_aot5_dr_sbr_sig2_mp4.m4a", 6, AudioFormat.CHANNEL_OUT_5POINT1},
         };
-
-        for (Object [] sample: samples) {
-            for (String codecName : DecoderTest.codecsFor((String)sample[0] /* resource */)) {
+        for (Object[] sample: samples) {
+            for (String codecName : DecoderTest.codecsFor((String)sample[0] /* resource */,
+                    DecoderTest.CODEC_DEFAULT)) {
                 // verify correct number of channels is observed without downmixing
                 AudioParameter chanParams = new AudioParameter();
                 decodeUpdateFormat(codecName, (String) sample[0] /*resource*/, chanParams,
diff --git a/tests/tests/media/drmframework/AndroidTest.xml b/tests/tests/media/drmframework/AndroidTest.xml
index c6e311d..28aaadc 100644
--- a/tests/tests/media/drmframework/AndroidTest.xml
+++ b/tests/tests/media/drmframework/AndroidTest.xml
@@ -26,6 +26,11 @@
         <option name="dynamic-config-name" value="CtsMediaDrmFrameworkTestCases" />
         <option name="version" value="9.0_r1"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaDrmFrameworkTestCases" />
+        <option name="version" value="7.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaDrmFrameworkTestCases-1.0" />
@@ -35,11 +40,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaDrmFrameworkTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaDrmFrameworkTestCases" />
-        <option name="version" value="7.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.drmframework.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java b/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
index 1a1a46f..2c1d9c5 100644
--- a/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
+++ b/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
@@ -26,7 +26,6 @@
 import android.media.UnsupportedSchemeException;
 import android.media.cts.AudioManagerStub;
 import android.media.cts.AudioManagerStubHelper;
-import android.media.cts.CodecState;
 import android.media.cts.ConnectionStatus;
 import android.media.cts.IConnectionStatus;
 import android.media.cts.InputSurface;
diff --git a/tests/tests/media/encoder/AndroidTest.xml b/tests/tests/media/encoder/AndroidTest.xml
index 65d8d6d..4de5615 100644
--- a/tests/tests/media/encoder/AndroidTest.xml
+++ b/tests/tests/media/encoder/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaEncoderTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaEncoderTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaEncoderTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaEncoderTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaEncoderTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.encoder.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/encoder/src/android/media/encoder/cts/VideoEncoderTest.java b/tests/tests/media/encoder/src/android/media/encoder/cts/VideoEncoderTest.java
index 4afc7aa..74aa214 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
@@ -43,6 +43,7 @@
 import android.media.cts.OutputSurface;
 import android.media.cts.Preconditions;
 import android.media.cts.TestArgs;
+import android.media.cts.TestUtils;
 import android.net.Uri;
 import android.platform.test.annotations.AppModeFull;
 import android.util.Log;
@@ -1301,6 +1302,10 @@
                 if (TestArgs.shouldSkipCodec(encoder)) {
                     continue;
                 }
+                if (!TestUtils.isTestableCodecInCurrentMode(encoder)) {
+                    Log.d(TAG, "Skipping tests for codec: " + encoder);
+                    continue;
+                }
                 CodecCapabilities caps = getCodecCapabities(encoder, mediaType, true);
                 assertNotNull(caps);
                 EncoderSize encoderSize = new EncoderSize(encoder, mediaType, caps);
diff --git a/tests/tests/media/extractor/AndroidTest.xml b/tests/tests/media/extractor/AndroidTest.xml
index 007a65b..fbe2d48 100644
--- a/tests/tests/media/extractor/AndroidTest.xml
+++ b/tests/tests/media/extractor/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaExtractorTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaExtractorTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaExtractorTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaExtractorTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaExtractorTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.extractor.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/misc/AndroidTest.xml b/tests/tests/media/misc/AndroidTest.xml
index 58cea2c..4a2ffaf 100644
--- a/tests/tests/media/misc/AndroidTest.xml
+++ b/tests/tests/media/misc/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaMiscTestCases" />
         <option name="version" value="9.0_r1"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaMiscTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaMiscTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaMiscTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaMiscTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.misc.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/muxer/AndroidTest.xml b/tests/tests/media/muxer/AndroidTest.xml
index 502f2ca..0c361e9 100644
--- a/tests/tests/media/muxer/AndroidTest.xml
+++ b/tests/tests/media/muxer/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaMuxerTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaMuxerTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaMuxerTestCases-1.1" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaMuxerTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaMuxerTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.muxer.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/player/AndroidTest.xml b/tests/tests/media/player/AndroidTest.xml
index e3e8b02..a0041ac 100644
--- a/tests/tests/media/player/AndroidTest.xml
+++ b/tests/tests/media/player/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaPlayerTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaPlayerTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaPlayerTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaPlayerTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaPlayerTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.player.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/os/Android.bp b/tests/tests/os/Android.bp
index 8bc8222..c50c6a7 100644
--- a/tests/tests/os/Android.bp
+++ b/tests/tests/os/Android.bp
@@ -40,6 +40,7 @@
         "hamcrest-library",
         "modules-utils-build_system",
         "platformprotosnano",
+        "safety-center-internal-data",
     ],
     jni_uses_platform_apis: true,
     jni_libs: [
diff --git a/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt b/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
index 4b91ee0..f49e065 100644
--- a/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
+++ b/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
@@ -50,17 +50,23 @@
 import com.android.compatibility.common.util.click
 import com.android.compatibility.common.util.depthFirstSearch
 import com.android.compatibility.common.util.textAsString
+import java.io.InputStream
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import org.hamcrest.Matcher
 import org.hamcrest.Matchers
 import org.junit.Assert
 import org.junit.Assert.assertThat
 import org.junit.Assert.assertTrue
-import java.io.InputStream
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
 
 private const val BROADCAST_TIMEOUT_MS = 60000L
 
+const val PROPERTY_SAFETY_CENTER_ENABLED = "safety_center_is_enabled"
+const val HIBERNATION_BOOT_RECEIVER_CLASS_NAME =
+    "com.android.permissioncontroller.hibernation.HibernationOnBootReceiver"
+const val ACTION_SET_UP_HIBERNATION =
+    "com.android.permissioncontroller.action.SET_UP_HIBERNATION"
+
 const val SYSUI_PKG_NAME = "com.android.systemui"
 const val NOTIF_LIST_ID = "com.android.systemui:id/notification_stack_scroller"
 const val CLEAR_ALL_BUTTON_ID = "dismiss_text"
@@ -82,35 +88,37 @@
 fun runBootCompleteReceiver(context: Context, testTag: String) {
     val pkgManager = context.packageManager
     val permissionControllerPkg = pkgManager.permissionControllerPackageName
+    var permissionControllerSetupIntent = Intent(ACTION_SET_UP_HIBERNATION).apply {
+        setPackage(permissionControllerPkg)
+        setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+    }
     val receivers = pkgManager.queryBroadcastReceivers(
-        Intent(Intent.ACTION_BOOT_COMPLETED), /* flags= */ 0)
-    for (ri in receivers) {
-        val pkg = ri.activityInfo.packageName
-        if (pkg == permissionControllerPkg) {
-            val permissionControllerSetupIntent = Intent()
-                .setClassName(pkg, ri.activityInfo.name)
-                .setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
-                .setPackage(permissionControllerPkg)
-            val countdownLatch = CountDownLatch(1)
-            Log.d(testTag, "Sending boot complete broadcast directly to ${ri.activityInfo.name} " +
-                "in package $permissionControllerPkg")
-            context.sendOrderedBroadcast(
-                permissionControllerSetupIntent,
-                /* receiverPermission= */ null,
-                object : BroadcastReceiver() {
-                    override fun onReceive(context: Context?, intent: Intent?) {
-                        countdownLatch.countDown()
-                        Log.d(testTag, "Broadcast received by $permissionControllerPkg")
-                    }
-                },
-                Handler.createAsync(Looper.getMainLooper()),
-                Activity.RESULT_OK,
-                /* initialData= */ null,
-                /* initialExtras= */ null)
-            assertTrue("Timed out while waiting for boot receiver broadcast to be received",
-                countdownLatch.await(BROADCAST_TIMEOUT_MS, TimeUnit.MILLISECONDS))
+        permissionControllerSetupIntent, /* flags= */ 0)
+    if (receivers.size == 0) {
+        // May be on an older, pre-built PermissionController. In this case, try sending directly.
+        permissionControllerSetupIntent = Intent().apply {
+            setPackage(permissionControllerPkg)
+            setClassName(permissionControllerPkg, HIBERNATION_BOOT_RECEIVER_CLASS_NAME)
+            setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
         }
     }
+    val countdownLatch = CountDownLatch(1)
+    Log.d(testTag, "Sending boot complete broadcast directly to $permissionControllerPkg")
+    context.sendOrderedBroadcast(
+        permissionControllerSetupIntent,
+        /* receiverPermission= */ null,
+        object : BroadcastReceiver() {
+            override fun onReceive(context: Context?, intent: Intent?) {
+                countdownLatch.countDown()
+                Log.d(testTag, "Broadcast received by $permissionControllerPkg")
+            }
+        },
+        Handler.createAsync(Looper.getMainLooper()),
+        Activity.RESULT_OK,
+        /* initialData= */ null,
+        /* initialExtras= */ null)
+    assertTrue("Timed out while waiting for boot receiver broadcast to be received",
+        countdownLatch.await(BROADCAST_TIMEOUT_MS, TimeUnit.MILLISECONDS))
 }
 
 fun runAppHibernationJob(context: Context, tag: String) {
@@ -197,6 +205,12 @@
         threshold.toString(), action)
 }
 
+inline fun <T> withSafetyCenterEnabled(action: () -> T): T {
+    return withDeviceConfig(
+        DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_SAFETY_CENTER_ENABLED,
+        true.toString(), action)
+}
+
 fun awaitAppState(pkg: String, stateMatcher: Matcher<Int>) {
     val context: Context = InstrumentationRegistry.getTargetContext()
     eventually {
diff --git a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
index b724be8..1d81e44 100644
--- a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
+++ b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
@@ -28,8 +28,11 @@
 import android.content.res.Resources
 import android.net.Uri
 import android.os.Build
+import android.os.UserHandle
 import android.platform.test.annotations.AppModeFull
 import android.provider.DeviceConfig
+import android.safetycenter.SafetyCenterIssue
+import android.safetycenter.SafetyCenterManager
 import android.support.test.uiautomator.By
 import android.support.test.uiautomator.BySelector
 import android.support.test.uiautomator.UiObject2
@@ -54,6 +57,13 @@
 import com.android.compatibility.common.util.depthFirstSearch
 import com.android.compatibility.common.util.uiDump
 import com.android.modules.utils.build.SdkLevel
+import com.android.safetycenter.internaldata.SafetyCenterIds
+import com.android.safetycenter.internaldata.SafetyCenterIssueId
+import com.android.safetycenter.internaldata.SafetyCenterIssueKey
+import java.lang.reflect.Modifier
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.atomic.AtomicReference
+import java.util.regex.Pattern
 import org.hamcrest.CoreMatchers.containsString
 import org.hamcrest.CoreMatchers.containsStringIgnoringCase
 import org.hamcrest.CoreMatchers.equalTo
@@ -71,10 +81,6 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import java.lang.reflect.Modifier
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.atomic.AtomicReference
-import java.util.regex.Pattern
 
 private const val READ_CALENDAR = "android.permission.READ_CALENDAR"
 private const val BLUETOOTH_CONNECT = "android.permission.BLUETOOTH_CONNECT"
@@ -103,6 +109,8 @@
     companion object {
         const val LOG_TAG = "AutoRevokeTest"
         private const val STORE_EXACT_TIME_KEY = "permission_changes_store_exact_time"
+        private const val UNUSED_APPS_SOURCE_ID = "AndroidPermissionAutoRevoke"
+        private const val UNUSED_APPS_ISSUE_ID = "unused_apps_issue"
 
         @JvmStatic
         @BeforeClass
@@ -126,7 +134,11 @@
 
         // Wake up the device
         runShellCommandOrThrow("input keyevent KEYCODE_WAKEUP")
-        runShellCommandOrThrow("input keyevent 82")
+        if ("false".equals(runShellCommandOrThrow("cmd lock_settings get-disabled"))) {
+            // Unlock screen only when it's lock settings enabled to prevent showing "wallpaper
+            // picker" which may cover another UI elements on freeform window configuration.
+            runShellCommandOrThrow("input keyevent 82")
+        }
 
         if (isAutomotiveDevice()) {
             supportedApkPath = APK_PATH_S_APP
@@ -434,6 +446,88 @@
         }
     }
 
+    @AppModeFull(reason = "Uses separate apps for testing")
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+    @Test
+    fun testAutoRevoke_showsUpInSafetyCenter() {
+        withSafetyCenterEnabled {
+            withUnusedThresholdMs(3L) {
+                withDummyApp {
+                    startAppAndAcceptPermission()
+
+                    killDummyApp()
+
+                    // Run
+                    runAppHibernationJob(context, LOG_TAG)
+
+                    // Verify
+                    val safetyCenterManager =
+                        context.getSystemService(SafetyCenterManager::class.java)!!
+                    eventually {
+                        val issues = ArrayList<SafetyCenterIssue>()
+                        runWithShellPermissionIdentity {
+                            val safetyCenterData = safetyCenterManager!!.safetyCenterData
+                            issues.addAll(safetyCenterData.issues)
+                        }
+                        val issueId = SafetyCenterIds.encodeToString(
+                                SafetyCenterIssueId.newBuilder()
+                                        .setSafetyCenterIssueKey(SafetyCenterIssueKey.newBuilder()
+                                                .setSafetySourceId(UNUSED_APPS_SOURCE_ID)
+                                                .setSafetySourceIssueId(UNUSED_APPS_ISSUE_ID)
+                                                .setUserId(UserHandle.myUserId())
+                                                .build())
+                                        .setIssueTypeId(UNUSED_APPS_ISSUE_ID)
+                                        .build())
+                        assertTrue(issues.any { it.id == issueId })
+                    }
+                }
+            }
+        }
+    }
+
+    @AppModeFull(reason = "Uses separate apps for testing")
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+    @Test
+    fun testAutoRevoke_goToUnusedAppsPage_removesSafetyCenterIssue() {
+        withSafetyCenterEnabled {
+            withUnusedThresholdMs(3L) {
+                withDummyApp {
+                    startAppAndAcceptPermission()
+
+                    killDummyApp()
+
+                    // Run
+                    runAppHibernationJob(context, LOG_TAG)
+
+                    // Go to unused apps page
+                    openUnusedAppsNotification()
+                    waitFindObject(By.text(supportedAppPackageName))
+
+                    // Verify
+                    val safetyCenterManager =
+                        context.getSystemService(SafetyCenterManager::class.java)!!
+                    eventually {
+                        val issues = ArrayList<SafetyCenterIssue>()
+                        runWithShellPermissionIdentity {
+                            val safetyCenterData = safetyCenterManager!!.safetyCenterData
+                            issues.addAll(safetyCenterData.issues)
+                        }
+                        val issueId = SafetyCenterIds.encodeToString(
+                                SafetyCenterIssueId.newBuilder()
+                                        .setSafetyCenterIssueKey(SafetyCenterIssueKey.newBuilder()
+                                                .setSafetySourceId(UNUSED_APPS_SOURCE_ID)
+                                                .setSafetySourceIssueId(UNUSED_APPS_ISSUE_ID)
+                                                .setUserId(UserHandle.myUserId())
+                                                .build())
+                                        .setIssueTypeId(UNUSED_APPS_ISSUE_ID)
+                                        .build())
+                        assertFalse(issues.any { it.id == issueId })
+                    }
+                }
+            }
+        }
+    }
+
     private fun isAutomotiveDevice(): Boolean {
         return context.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
     }
diff --git a/tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt b/tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt
index 86a680e..28d58d6 100644
--- a/tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt
+++ b/tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt
@@ -58,7 +58,7 @@
 @RunWith(AndroidJUnit4::class)
 @AppModeFull(
     reason = "Cannot set system settings as instant app. Also we never show an accessibility " +
-            "notification for instant apps."
+        "notification for instant apps."
 )
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
 class AccessibilityPrivacySourceTest {
@@ -243,12 +243,27 @@
             "cmd jobscheduler reset-execution-quota -u " +
                 "${Process.myUserHandle().identifier} $permissionControllerPackage")
 
-        context.sendBroadcast(
-            Intent().apply {
-                setClassName(permissionControllerPackage, AccessibilityOnBootReceiver)
-                setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+        // Setup up permission controller again (simulate a reboot)
+        val permissionControllerSetupIntent =
+            Intent(ACTION_SET_UP_ACCESSIBILITY_CHECK).apply {
                 setPackage(permissionControllerPackage)
-            })
+                setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+            }
+
+        // Query for the setup broadcast receiver
+        val resolveInfos =
+            context.packageManager.queryBroadcastReceivers(permissionControllerSetupIntent, 0)
+
+        if (resolveInfos.size > 0) {
+            context.sendBroadcast(permissionControllerSetupIntent)
+        } else {
+            context.sendBroadcast(
+                Intent().apply {
+                    setClassName(permissionControllerPackage, AccessibilityOnBootReceiver)
+                    setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+                    setPackage(permissionControllerPackage)
+                })
+        }
 
         // Wait until jobs are set up
         TestUtils.eventually(
@@ -288,6 +303,8 @@
 
         private const val AccessibilityOnBootReceiver =
             "com.android.permissioncontroller.privacysources.AccessibilityOnBootReceiver"
+        private const val ACTION_SET_UP_ACCESSIBILITY_CHECK =
+            "com.android.permissioncontroller.action.SET_UP_ACCESSIBILITY_CHECK"
 
         @get:ClassRule
         @JvmStatic
diff --git a/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java b/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
index 6ce52b1..9daeff2 100644
--- a/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
@@ -17,7 +17,6 @@
 package android.permission.cts;
 
 import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
-import static android.content.Intent.ACTION_BOOT_COMPLETED;
 import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
 import static android.os.Process.myUserHandle;
 import static android.permission.cts.PermissionUtils.clearAppState;
@@ -114,6 +113,11 @@
     private static final String PROPERTY_JOB_SCHEDULER_RATE_LIMIT_WINDOW_MILLIS =
             "qc_rate_limiting_window_ms";
 
+    private static final String ACTION_SET_UP_NOTIFICATION_LISTENER_CHECK =
+            "com.android.permissioncontroller.action.SET_UP_NOTIFICATION_LISTENER_CHECK";
+    private static final String NotificationListenerOnBootReceiver =
+            "com.android.permissioncontroller.privacysources.SetupPeriodicNotificationListenerCheck";
+
     /**
      * ID for notification shown by
      * {@link com.android.permissioncontroller.privacysources.NotificationListenerCheck}.
@@ -374,19 +378,21 @@
         }, UNEXPECTED_TIMEOUT_MILLIS);
 
         // Setup up permission controller again (simulate a reboot)
-        Intent permissionControllerSetupIntent = null;
-        for (ResolveInfo ri : sContext.getPackageManager().queryBroadcastReceivers(
-                new Intent(ACTION_BOOT_COMPLETED), 0)) {
-            String pkg = ri.activityInfo.packageName;
+        Intent permissionControllerSetupIntent = new Intent(
+                ACTION_SET_UP_NOTIFICATION_LISTENER_CHECK).setPackage(
+                PERMISSION_CONTROLLER_PKG).setFlags(FLAG_RECEIVER_FOREGROUND);
 
-            if (pkg.equals(PERMISSION_CONTROLLER_PKG)) {
-                permissionControllerSetupIntent = new Intent()
-                        .setClassName(pkg, ri.activityInfo.name)
-                        .setFlags(FLAG_RECEIVER_FOREGROUND)
-                        .setPackage(PERMISSION_CONTROLLER_PKG);
+        // Query for the setup broadcast receiver
+        List<ResolveInfo> resolveInfos = sContext.getPackageManager().queryBroadcastReceivers(
+                permissionControllerSetupIntent, 0);
 
-                sContext.sendBroadcast(permissionControllerSetupIntent);
-            }
+        if (resolveInfos.size() > 0) {
+            sContext.sendBroadcast(permissionControllerSetupIntent);
+        } else {
+            sContext.sendBroadcast(new Intent()
+                    .setClassName(PERMISSION_CONTROLLER_PKG, NotificationListenerOnBootReceiver)
+                    .setFlags(FLAG_RECEIVER_FOREGROUND)
+                    .setPackage(PERMISSION_CONTROLLER_PKG));
         }
 
         // Wait until jobs are set up
diff --git a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
index b41fb08..ceb4ede 100644
--- a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -23,7 +23,6 @@
 import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
 import static android.content.Context.BIND_AUTO_CREATE;
 import static android.content.Context.BIND_NOT_FOREGROUND;
-import static android.content.Intent.ACTION_BOOT_COMPLETED;
 import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
 import static android.location.Criteria.ACCURACY_FINE;
 import static android.os.Process.myUserHandle;
@@ -41,7 +40,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
@@ -120,6 +118,8 @@
             "/data/local/tmp/cts/permissions/CtsAppThatAccessesLocationOnCommand.apk";
     private static final String TEST_APP_LOCATION_FG_ACCESS_APK =
             "/data/local/tmp/cts/permissions/AppThatDoesNotHaveBgLocationAccess.apk";
+    private static final String ACTION_SET_UP_LOCATION_ACCESS_CHECK =
+            "com.android.permissioncontroller.action.SET_UP_LOCATION_ACCESS_CHECK";
     private static final int LOCATION_ACCESS_CHECK_JOB_ID = 0;
     private static final int LOCATION_ACCESS_CHECK_NOTIFICATION_ID = 0;
 
@@ -153,6 +153,10 @@
 
     private static final String PERMISSION_CONTROLLER_PKG = sContext.getPackageManager()
             .getPermissionControllerPackageName();
+    private static final String LocationAccessCheckOnBootReceiver =
+            "com.android.permissioncontroller.permission.service"
+                    + ".LocationAccessCheck$SetupPeriodicBackgroundLocationAccessCheck";
+
 
     /**
      * The result of {@link #assumeCanGetFineLocation()}, so we don't have to run it over and over
@@ -389,6 +393,11 @@
      * Force a run of the location check.
      */
     private static void runLocationCheck() throws Throwable {
+        // If the job isn't setup, do it before running a location check
+        if (!isLocationAccessJobSetup(myUserHandle().getIdentifier())) {
+            setupLocationAccessCheckJob();
+        }
+
         // Sleep a little bit to make sure we don't have overlap in timing
         Thread.sleep(1000);
 
@@ -676,38 +685,47 @@
             }
         }, UNEXPECTED_TIMEOUT_MILLIS);
 
-        // Setup up permission controller again (simulate a reboot)
-        Intent permissionControllerSetupIntent = null;
-        for (ResolveInfo ri : sContext.getPackageManager().queryBroadcastReceivers(
-                new Intent(ACTION_BOOT_COMPLETED), 0)) {
-            String pkg = ri.activityInfo.packageName;
-
-            if (pkg.equals(PERMISSION_CONTROLLER_PKG)) {
-                permissionControllerSetupIntent = new Intent()
-                        .setClassName(pkg, ri.activityInfo.name)
-                        .setFlags(FLAG_RECEIVER_FOREGROUND)
-                        .setPackage(PERMISSION_CONTROLLER_PKG);
-
-                sContext.sendBroadcast(permissionControllerSetupIntent);
-            }
-        }
+        setupLocationAccessCheckJob();
 
         // Wait until jobs are set up
         eventually(() -> {
-            JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
-
-            for (RegisteredJob job : dump.registeredJobs) {
-                if (job.dump.sourceUserId == currentUserId
-                        && job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)
-                        && job.dump.jobInfo.service.className.contains("LocationAccessCheck")) {
-                    return;
-                }
-            }
-
-            fail("Permission controller jobs not found");
+            assertTrue("LocationAccessCheck job not found",
+                    isLocationAccessJobSetup(currentUserId));
         }, UNEXPECTED_TIMEOUT_MILLIS);
     }
 
+    private static boolean isLocationAccessJobSetup(int currentUserId) throws Exception {
+        JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
+        for (RegisteredJob job : dump.registeredJobs) {
+            if (job.dump.sourceUserId == currentUserId
+                    && job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)
+                    && job.dump.jobInfo.service.className.contains("LocationAccessCheck")) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static void setupLocationAccessCheckJob() {
+        // Setup location access check
+        Intent permissionControllerSetupIntent = new Intent(
+                ACTION_SET_UP_LOCATION_ACCESS_CHECK).setPackage(
+                PERMISSION_CONTROLLER_PKG).setFlags(FLAG_RECEIVER_FOREGROUND);
+
+        // Query for the setup broadcast receiver
+        List<ResolveInfo> resolveInfos = sContext.getPackageManager().queryBroadcastReceivers(
+                permissionControllerSetupIntent, 0);
+
+        if (resolveInfos.size() > 0) {
+            sContext.sendBroadcast(permissionControllerSetupIntent);
+        } else {
+            sContext.sendBroadcast(new Intent()
+                    .setClassName(PERMISSION_CONTROLLER_PKG, LocationAccessCheckOnBootReceiver)
+                    .setFlags(FLAG_RECEIVER_FOREGROUND)
+                    .setPackage(PERMISSION_CONTROLLER_PKG));
+        }
+    }
+
     /**
      * Unregister {@link NotificationListener}.
      */
diff --git a/tests/tests/permission/src/android/permission/cts/SafetyCenterUtils.kt b/tests/tests/permission/src/android/permission/cts/SafetyCenterUtils.kt
index f057b21..931ecd1 100644
--- a/tests/tests/permission/src/android/permission/cts/SafetyCenterUtils.kt
+++ b/tests/tests/permission/src/android/permission/cts/SafetyCenterUtils.kt
@@ -67,7 +67,7 @@
     @JvmStatic
     fun assertSafetyCenterStarted() {
         // CollapsingToolbar title can't be found by text, so using description instead.
-        waitFindObject(By.desc("Security & Privacy"))
+        waitFindObject(By.desc("Security & privacy"))
     }
 
     @JvmStatic
diff --git a/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
index 6693aa3..8bd15373 100644
--- a/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
@@ -20,6 +20,7 @@
 import android.os.Build
 import androidx.test.filters.SdkSuppress
 import com.android.compatibility.common.util.SystemUtil
+import org.junit.Assume
 import org.junit.Test
 
 /**
@@ -96,6 +97,8 @@
 
     @Test
     fun testWhenVisualIsDeniedManuallyThenShouldDenyAllPermissions() {
+        // TODO: Re-enable after b/239249703 is fixed
+        Assume.assumeFalse("skip on TV due to flaky", isTv)
         installPackage(APP_APK_PATH_23)
         grantAppPermissions(android.Manifest.permission.READ_MEDIA_VIDEO, targetSdk = 23)
         revokeAppPermissions(android.Manifest.permission.READ_MEDIA_VIDEO, targetSdk = 23)
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt
index 5355fdc..7d0ba79 100644
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt
@@ -45,6 +45,7 @@
 private const val TIMELINE_7_DAYS_DESCRIPTION = "in the past 7 days"
 private const val DASHBOARD_7_DAYS_DESCRIPTION = "7 days"
 private const val PRIV_DASH_7_DAY_ENABLED = "privacy_dashboard_7_day_toggle"
+private const val REFRESH = "Refresh"
 
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
 class PermissionHistoryTest : BasePermissionHubTest() {
@@ -100,9 +101,22 @@
         waitFindObject(By.textContains(APP_LABEL_1))
 
         openPermissionDashboard()
-        waitFindObject(By.res("android:id/title").textContains("Microphone")).click()
-        waitFindObject(By.textContains(micLabel))
-        waitFindObject(By.textContains(APP_LABEL_1))
+
+        SystemUtil.eventually {
+            try {
+                waitFindObject(By.hasChild(By.textContains("Microphone"))
+                        .hasChild(By.textStartsWith("Used by")))
+                        .click()
+                waitFindObject(By.textContains(micLabel))
+                waitFindObject(By.textContains(APP_LABEL_1))
+            } catch (e: Exception) {
+                // Sometimes the dashboard was in the state from previous failed tests.
+                // Clicking the refresh button to get the most recent access.
+                waitFindObject(By.descContains(REFRESH)).click()
+                throw e
+            }
+        }
+
         pressBack()
         pressBack()
     }
diff --git a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
index 598a59a..872a243 100644
--- a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
+++ b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
@@ -78,6 +78,8 @@
 private const val UNEXPECTED_TIMEOUT_MILLIS = 1000
 private const val TIMEOUT_MILLIS: Long = 20000
 private const val TV_MIC_INDICATOR_WINDOW_TITLE = "MicrophoneCaptureIndicator"
+private const val MIC_LABEL_NAME = "microphone_toggle_label_qs"
+private const val CAMERA_LABEL_NAME = "camera_toggle_label_qs"
 
 class CameraMicIndicatorsPermissionTest {
     private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
@@ -90,11 +92,9 @@
 
     private val isTv = packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
     private val isCar = packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+    private val micLabel = getPermissionControllerString(MIC_LABEL_NAME)
+    private val cameraLabel = getPermissionControllerString(CAMERA_LABEL_NAME)
     private var wasEnabled = false
-    private val micLabel = packageManager.getPermissionGroupInfo(
-        Manifest.permission_group.MICROPHONE, 0).loadLabel(packageManager).toString()
-    private val cameraLabel = packageManager.getPermissionGroupInfo(
-        Manifest.permission_group.CAMERA, 0).loadLabel(packageManager).toString()
     private var isScreenOn = false
     private var screenTimeoutBeforeTest: Long = 0L
 
@@ -520,4 +520,18 @@
             automatorMethod(remainingTime)
         }
     }
+
+    private fun getPermissionControllerString(resourceName: String): String {
+        val permissionControllerPkg = context.packageManager.permissionControllerPackageName
+        try {
+            val permissionControllerContext =
+                context.createPackageContext(permissionControllerPkg, 0)
+            val resourceId =
+                permissionControllerContext.resources.getIdentifier(
+                    resourceName, "string", "com.android.permissioncontroller")
+            return permissionControllerContext.getString(resourceId)
+        } catch (e: PackageManager.NameNotFoundException) {
+            throw RuntimeException(e)
+        }
+    }
 }
\ No newline at end of file
diff --git a/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt b/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt
index 8cff38a..67fa1bc 100644
--- a/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt
+++ b/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt
@@ -25,6 +25,7 @@
 import android.content.ContextParams
 import android.content.Intent
 import android.content.pm.PackageManager.FEATURE_LEANBACK
+import android.content.pm.PackageManager.FEATURE_TELEPHONY
 import android.net.Uri
 import android.os.Bundle
 import android.os.Process
@@ -44,6 +45,7 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
 import org.junit.Before
 import org.junit.Test
 import org.mockito.ArgumentMatcher
@@ -105,6 +107,7 @@
     @Throws(Exception::class)
     fun testSelfSmsAccess() {
         assumeNotTv()
+        assumeHasTelephony()
         testSelfAccess(Telephony.Sms.CONTENT_URI,
                 Manifest.permission.READ_SMS)
     }
@@ -178,6 +181,7 @@
     @Throws(Exception::class)
     fun testUntrustedSmsAccessAttributeToAnother() {
         assumeNotTv()
+        assumeHasTelephony()
         testUntrustedAccessAttributeToAnother(Telephony.Sms.CONTENT_URI,
                 Manifest.permission.READ_SMS)
     }
@@ -225,6 +229,7 @@
     @Throws(Exception::class)
     fun testUntrustedSmsAccessAttributeToAnotherThroughIntermediary() {
         assumeNotTv()
+        assumeHasTelephony()
         testUntrustedAccessAttributeToAnotherThroughIntermediary(
                 Telephony.Sms.CONTENT_URI,
                 Manifest.permission.READ_SMS)
@@ -323,6 +328,7 @@
     @Throws(Exception::class)
     fun testTrustedAccessSmsAttributeToAnother() {
         assumeNotTv()
+        assumeHasTelephony()
         testTrustedAccessAttributeToAnother(Telephony.Sms.CONTENT_URI,
                 Manifest.permission.READ_SMS)
     }
@@ -666,6 +672,7 @@
             get() = InstrumentationRegistry.getInstrumentation()
 
         private val isTv = context.packageManager.hasSystemFeature(FEATURE_LEANBACK)
+        private val isTel = context.packageManager.hasSystemFeature(FEATURE_TELEPHONY)
 
         fun ensureAuxiliaryAppsNotRunningAndNoResidualProcessState() {
             SystemUtil.runShellCommand("am force-stop $RECEIVER_PACKAGE_NAME")
@@ -1178,5 +1185,6 @@
         }
 
         private fun assumeNotTv() = assumeFalse(isTv)
+        private fun assumeHasTelephony() = assumeTrue(isTel)
     }
 }
diff --git a/tests/tests/preference/src/android/preference/cts/PreferenceActivityLegacyFlowTest.java b/tests/tests/preference/src/android/preference/cts/PreferenceActivityLegacyFlowTest.java
index 29cf672..782f30c 100644
--- a/tests/tests/preference/src/android/preference/cts/PreferenceActivityLegacyFlowTest.java
+++ b/tests/tests/preference/src/android/preference/cts/PreferenceActivityLegacyFlowTest.java
@@ -103,7 +103,8 @@
     }
 
     private void assertScreenshotsAreEqual(Bitmap before, Bitmap after) {
-        assertTrue("Screenshots do not match!", BitmapUtils.compareBitmaps(before, after));
+        // TODO(b/227553681): remove the precision=0.99 arg so it does a pixel-by-pixel check
+        assertTrue("Screenshots do not match!", BitmapUtils.compareBitmaps(before, after, 0.99));
     }
 
     private void assertTextShown(String text) {
diff --git a/tests/tests/provider/OWNERS b/tests/tests/provider/OWNERS
index 1e318ea..7c9a6b2 100644
--- a/tests/tests/provider/OWNERS
+++ b/tests/tests/provider/OWNERS
@@ -1,7 +1,13 @@
-# Bug component: 655625
-
-include platform/frameworks/base:/core/java/android/os/storage/OWNERS
-
 tgunn@google.com
 nicksauer@google.com
 nona@google.com
+
+# Storage team ownership
+
+# Bug component: 655625 = per-file *MediaStore*
+
+per-file *MediaStore* = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
+per-file Android.bp = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
+per-file AndroidManifest.xml = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
+per-file AndroidTest.xml = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
+per-file OWNERS = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
diff --git a/tests/tests/security/res/raw/cve_2022_22087.mkv b/tests/tests/security/res/raw/cve_2022_22087.mkv
new file mode 100644
index 0000000..0b25fe4
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_22087.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_25657.mkv b/tests/tests/security/res/raw/cve_2022_25657.mkv
new file mode 100644
index 0000000..3d5f70e
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_25657.mkv
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/LocationDisabledAppOpsTest.java b/tests/tests/security/src/android/security/cts/LocationDisabledAppOpsTest.java
new file mode 100644
index 0000000..c6b7e35
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/LocationDisabledAppOpsTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.location.LocationManager;
+import android.os.PackageTagsList;
+import android.os.Process;
+import android.os.UserHandle;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class LocationDisabledAppOpsTest extends StsExtraBusinessLogicTestCase {
+
+    private final Context mContext = InstrumentationRegistry.getContext();
+    private LocationManager mLm;
+    private AppOpsManager mAom;
+
+    @Before
+    public void setUp() {
+        mLm = mContext.getSystemService(LocationManager.class);
+        mAom = mContext.getSystemService(AppOpsManager.class);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 231496105)
+    public void testLocationAppOpIsIgnoredForAppsWhenLocationIsDisabled() {
+        PackageTagsList ignoreList = mLm.getIgnoreSettingsAllowlist();
+
+        UserHandle[] userArr = {UserHandle.SYSTEM};
+        runWithShellPermissionIdentity(() -> {
+            userArr[0] = UserHandle.of(ActivityManager.getCurrentUser());
+        });
+
+        UserHandle user = userArr[0];
+
+        boolean wasEnabled = mLm.isLocationEnabledForUser(user);
+
+        try {
+            runWithShellPermissionIdentity(() -> {
+                mLm.setLocationEnabledForUser(false, user);
+            });
+            List<PackageInfo> pkgs =
+                    mContext.getPackageManager().getInstalledPackagesAsUser(
+                            0, user.getIdentifier());
+
+            eventually(() -> {
+                List<String> bypassedNoteOps = new ArrayList<>();
+                List<String> bypassedCheckOps = new ArrayList<>();
+                for (PackageInfo pi : pkgs) {
+                    ApplicationInfo ai = pi.applicationInfo;
+                    if (ai.uid != Process.SYSTEM_UID) {
+                        final int[] mode = {MODE_ALLOWED};
+                        runWithShellPermissionIdentity(() -> {
+                            mode[0] = mAom.noteOpNoThrow(
+                                    OPSTR_FINE_LOCATION, ai.uid, ai.packageName);
+                        });
+                        if (mode[0] == MODE_ALLOWED && !ignoreList.containsAll(pi.packageName)) {
+                            bypassedNoteOps.add(pi.packageName);
+                        }
+
+
+                        mode[0] = MODE_ALLOWED;
+                        runWithShellPermissionIdentity(() -> {
+                            mode[0] = mAom
+                                    .checkOpNoThrow(OPSTR_FINE_LOCATION, ai.uid, ai.packageName);
+                        });
+                        if (mode[0] == MODE_ALLOWED && !ignoreList.includes(pi.packageName)) {
+                            bypassedCheckOps.add(pi.packageName);
+                        }
+
+                    }
+                }
+
+                String msg = "";
+                if (!bypassedNoteOps.isEmpty()) {
+                    msg += "Apps which still have access from noteOp " + bypassedNoteOps;
+                }
+                if (!bypassedCheckOps.isEmpty()) {
+                    msg += (msg.isEmpty() ? "" : "\n\n")
+                            +  "Apps which still have access from checkOp " + bypassedCheckOps;
+                }
+                if (!msg.isEmpty()) {
+                    Assert.fail(msg);
+                }
+            });
+        } finally {
+            runWithShellPermissionIdentity(() -> {
+                mLm.setLocationEnabledForUser(wasEnabled, user);
+            });
+        }
+    }
+
+}
+
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index cdb27a8..f0d4ab3 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -1809,6 +1809,18 @@
      before any existing test methods
      ***********************************************************/
     @Test
+    @AsbSecurityTest(cveBugId = 223209610)
+    public void testStagefright_cve_2022_22087() throws Exception {
+         doStagefrightTest(R.raw.cve_2022_22087);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 228101835)
+    public void testStagefright_cve_2022_25657() throws Exception {
+         doStagefrightTest(R.raw.cve_2022_25657);
+    }
+
+    @Test
     @AsbSecurityTest(cveBugId = 231156126)
     public void testStagefright_cve_2022_22059() throws Exception {
          doStagefrightTest(R.raw.cve_2022_22059);
diff --git a/tests/tests/systemui/Android.bp b/tests/tests/systemui/Android.bp
index e33d8fc..3a68e4d 100644
--- a/tests/tests/systemui/Android.bp
+++ b/tests/tests/systemui/Android.bp
@@ -39,6 +39,7 @@
         "androidx.test.ext.junit",
         "androidx.test.uiautomator",
         "cts-wm-util",
+        "permission-test-util-lib",
         "ub-uiautomator",
     ],
     srcs: [
diff --git a/tests/tests/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml
index f55ed3f..d4ba3b3 100644
--- a/tests/tests/systemui/AndroidManifest.xml
+++ b/tests/tests/systemui/AndroidManifest.xml
@@ -26,6 +26,7 @@
     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
     <!-- Required by flickerlib to dump window states -->
     <uses-permission android:name="android.permission.DUMP"/>
+    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
 
     <application android:requestLegacyExternalStorage="true">
         <activity android:name=".LightBarActivity"
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
index ffa58ba..5079217 100644
--- a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
@@ -16,6 +16,9 @@
 
 package android.systemui.cts;
 
+import static android.Manifest.permission.POST_NOTIFICATIONS;
+import static android.Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL;
+import static android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS;
 import static android.server.wm.BarTestUtils.assumeHasColoredNavigationBar;
 import static android.server.wm.BarTestUtils.assumeHasColoredStatusBar;
 import static android.server.wm.BarTestUtils.assumeStatusBarContainsCutout;
@@ -33,7 +36,10 @@
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.Insets;
+import android.os.Process;
 import android.os.SystemClock;
+import android.permission.PermissionManager;
+import android.permission.cts.PermissionUtils;
 import android.platform.test.annotations.AppModeFull;
 import android.view.Gravity;
 import android.view.InputDevice;
@@ -45,6 +51,7 @@
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.SystemUtil;
 import com.android.compatibility.common.util.ThrowingRunnable;
 
 import org.junit.Rule;
@@ -244,22 +251,23 @@
     }
 
     private void runInNotificationSession(ThrowingRunnable task) throws Exception {
+        Context context = getInstrumentation().getContext();
+        String packageName = getInstrumentation().getTargetContext().getPackageName();
         try {
-            mNm = (NotificationManager) getInstrumentation().getContext()
-                    .getSystemService(Context.NOTIFICATION_SERVICE);
+            PermissionUtils.grantPermission(packageName, POST_NOTIFICATIONS);
+            mNm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
             NotificationChannel channel1 = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
                     NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW);
             mNm.createNotificationChannel(channel1);
 
             // post 10 notifications to ensure enough icons in the status bar
             for (int i = 0; i < 10; i++) {
-                Notification.Builder noti1 = new Notification.Builder(
-                        getInstrumentation().getContext(),
-                        NOTIFICATION_CHANNEL_ID)
-                        .setSmallIcon(R.drawable.ic_save)
-                        .setChannelId(NOTIFICATION_CHANNEL_ID)
-                        .setPriority(Notification.PRIORITY_LOW)
-                        .setGroup(NOTIFICATION_GROUP_KEY);
+                Notification.Builder noti1 =
+                        new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
+                                .setSmallIcon(R.drawable.ic_save)
+                                .setChannelId(NOTIFICATION_CHANNEL_ID)
+                                .setPriority(Notification.PRIORITY_LOW)
+                                .setGroup(NOTIFICATION_GROUP_KEY);
                 mNm.notify(NOTIFICATION_TAG, i, noti1.build());
             }
 
@@ -267,6 +275,16 @@
         } finally {
             mNm.cancelAll();
             mNm.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
+
+            // Use test API to prevent PermissionManager from killing the test process when revoking
+            // permission.
+            SystemUtil.runWithShellPermissionIdentity(
+                    () -> context.getSystemService(PermissionManager.class)
+                            .revokePostNotificationPermissionWithoutKillForTest(
+                                    packageName,
+                                    Process.myUserHandle().getIdentifier()),
+                    REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL,
+                    REVOKE_RUNTIME_PERMISSIONS);
         }
     }
 
diff --git a/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java b/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java
deleted file mode 100644
index b74678b..0000000
--- a/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java
+++ /dev/null
@@ -1,130 +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.systemui.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.server.wm.WindowManagerStateHelper;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.Until;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.compatibility.common.util.SystemUtil;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests related MediaOutputDialog:
- *
- * atest MediaDialogTest
- */
-@RunWith(AndroidJUnit4.class)
-public class MediaOutputDialogTest {
-
-    private static final int TIMEOUT = 5000;
-    private static final String ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG =
-            "com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG";
-    private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
-    public static final String EXTRA_PACKAGE_NAME = "package_name";
-    public static final String TEST_PACKAGE_NAME = "com.android.package.test";
-    private static final BySelector MEDIA_DIALOG_SELECTOR = By.res(SYSTEMUI_PACKAGE_NAME,
-            "media_output_dialog");
-    private WindowManagerStateHelper mWmState = new WindowManagerStateHelper();
-
-    private Context mContext;
-    private UiDevice mDevice;
-    private String mLauncherPackage;
-    private boolean mHasTouchScreen;
-    private ActivityManager mActivityManager;
-    private static final int DURATION_SCREEN_TOGGLE = 2000;
-
-    @Before
-    public void setUp() {
-        mContext = InstrumentationRegistry.getTargetContext();
-        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        final PackageManager packageManager = mContext.getPackageManager();
-
-        mHasTouchScreen = packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
-                || packageManager.hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);
-
-        Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
-        launcherIntent.addCategory(Intent.CATEGORY_HOME);
-        ResolveInfo resolveInfo = packageManager.resolveActivity(launcherIntent,
-                PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY));
-        assumeFalse("Skipping test: can't get resolve info", resolveInfo == null);
-        assumeFalse("Skipping test: not supported on automotive yet",
-                packageManager.hasSystemFeature(
-                        PackageManager.FEATURE_AUTOMOTIVE));
-        mLauncherPackage = resolveInfo.activityInfo.packageName;
-        mActivityManager = mContext.getSystemService(ActivityManager.class);
-    }
-
-    @Test
-    public void mediaOutputDialog_correctDialog() throws Exception {
-        prepareDevice();
-        assumeTrue(mHasTouchScreen);
-        try {
-            if (mActivityManager.isLowRamDevice()) {
-                SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
-                        "appops set " + SYSTEMUI_PACKAGE_NAME + " SYSTEM_ALERT_WINDOW allow");
-            }
-
-            launchMediaOutputDialog();
-
-            assertThat(mDevice.wait(Until.hasObject(MEDIA_DIALOG_SELECTOR), TIMEOUT)).isTrue();
-        } finally {
-            if (mActivityManager.isLowRamDevice()) {
-                SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
-                        "appops set " + SYSTEMUI_PACKAGE_NAME + " SYSTEM_ALERT_WINDOW ignore");
-            }
-        }
-    }
-
-    private void prepareDevice() throws Exception {
-        mDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
-        mDevice.executeShellCommand("wm dismiss-keyguard");
-        // Since the screen on/off intent is ordered, they will not be sent right now.
-        mWmState.waitForKeyguardGone();
-    }
-
-    private void launchMediaOutputDialog() {
-        mDevice.pressHome();
-        mDevice.wait(Until.hasObject(By.pkg(mLauncherPackage).depth(0)), TIMEOUT);
-
-        Intent intent = new Intent();
-        intent.setPackage(SYSTEMUI_PACKAGE_NAME)
-                .setAction(ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
-                .putExtra(EXTRA_PACKAGE_NAME, TEST_PACKAGE_NAME);
-
-        mContext.sendBroadcast(intent);
-    }
-
-}
diff --git a/tests/tests/telephony/OWNERS b/tests/tests/telephony/OWNERS
index 02848c8..89e4f4d 100644
--- a/tests/tests/telephony/OWNERS
+++ b/tests/tests/telephony/OWNERS
@@ -1,2 +1,17 @@
-file:platform/frameworks/opt/telephony:/OWNERS
-
+# Bug component: 20868
+amagup@google.com
+amallampati@google.com
+amruthr@google.com
+breadley@google.com
+chinmayd@google.com
+fionaxu@google.com
+huiwang@google.com
+jackyu@google.com
+jayachandranc@google.com
+linggm@google.com
+rgreenwalt@google.com
+sarahchin@google.com
+sasindran@google.com
+tgunn@google.com
+tjstuart@google.com
+xiaotonj@google.com
diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java
index f2523a4..0bed8a7 100644
--- a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java
@@ -34,6 +34,7 @@
 
 public class MockModemService extends Service {
     private static final String TAG = "MockModemService";
+    private static final String RESOURCE_PACKAGE_NAME = "android";
 
     public static final int TEST_TIMEOUT_MS = 30000;
     public static final String IRADIOCONFIG_INTERFACE = "android.telephony.mockmodem.iradioconfig";
@@ -233,9 +234,18 @@
     }
 
     public int getNumPhysicalSlots() {
-        int numPhysicalSlots =
+        int numPhysicalSlots = MockSimService.MOCK_SIM_SLOT_MIN;
+        int resourceId =
                 sContext.getResources()
-                        .getInteger(com.android.internal.R.integer.config_num_physical_slots);
+                        .getIdentifier(
+                                "config_num_physical_slots", "integer", RESOURCE_PACKAGE_NAME);
+
+        if (resourceId > 0) {
+            numPhysicalSlots = sContext.getResources().getInteger(resourceId);
+        } else {
+            Log.d(TAG, "Fail to get the resource Id, using default: " + numPhysicalSlots);
+        }
+
         if (numPhysicalSlots > MockSimService.MOCK_SIM_SLOT_MAX) {
             Log.d(
                     TAG,
@@ -245,6 +255,15 @@
                             + MockSimService.MOCK_SIM_SLOT_MAX
                             + ").");
             numPhysicalSlots = MockSimService.MOCK_SIM_SLOT_MAX;
+        } else if (numPhysicalSlots <= MockSimService.MOCK_SIM_SLOT_MIN) {
+            Log.d(
+                    TAG,
+                    "Number of physical Slot ("
+                            + numPhysicalSlots
+                            + ") < mock sim slot support. Reset to min number supported ("
+                            + MockSimService.MOCK_SIM_SLOT_MIN
+                            + ").");
+            numPhysicalSlots = MockSimService.MOCK_SIM_SLOT_MIN;
         }
 
         return numPhysicalSlots;
diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java
index 8183925..026710b 100644
--- a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java
@@ -63,6 +63,7 @@
     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_MIN = 1;
     public static final int MOCK_SIM_SLOT_MAX = 3;
 
     /* Default value definition */
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index 3757b63..d7bc9b1 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -109,6 +109,7 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.CarrierPrivilegeUtils;
 import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.ShellIdentityUtils;
@@ -283,6 +284,7 @@
     private static final int RADIO_HAL_VERSION_1_3 = makeRadioVersion(1, 3);
     private static final int RADIO_HAL_VERSION_1_5 = makeRadioVersion(1, 5);
     private static final int RADIO_HAL_VERSION_1_6 = makeRadioVersion(1, 6);
+    private static final int RADIO_HAL_VERSION_2_0 = makeRadioVersion(2, 0);
 
     static {
         EMERGENCY_NUMBER_SOURCE_SET = new HashSet<Integer>();
@@ -1250,23 +1252,49 @@
     private static final String ISO_COUNTRY_CODE_PATTERN = "[a-z]{2}";
 
     @Test
+    @ApiTest(apis = "android.telephony.TelephonyManager#getNetworkCountryIso")
     public void testGetNetworkCountryIso() {
         assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
 
         String countryCode = mTelephonyManager.getNetworkCountryIso();
-        assertTrue("Country code '" + countryCode + "' did not match "
-                + ISO_COUNTRY_CODE_PATTERN,
-                Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
+        ServiceState serviceState = mTelephonyManager.getServiceState();
+        if (serviceState != null && (serviceState.getState()
+                == ServiceState.STATE_IN_SERVICE || serviceState.getState()
+                == ServiceState.STATE_EMERGENCY_ONLY)) {
+            assertTrue("Country code '" + countryCode + "' did not match "
+                    + ISO_COUNTRY_CODE_PATTERN,
+                    Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
+        } else {
+            assertTrue("Country code could be empty when out of service",
+                    Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)
+                    || TextUtils.isEmpty(countryCode));
+        }
+
+        int[] allSubs = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mSubscriptionManager, (sm) -> sm.getActiveSubscriptionIdList());
+        for (int i : allSubs) {
+            countryCode = mTelephonyManager.getNetworkCountryIso(
+                    SubscriptionManager.getSlotIndex(i));
+            serviceState = mTelephonyManager.createForSubscriptionId(i).getServiceState();
+
+            if (serviceState != null && (serviceState.getState()
+                    == ServiceState.STATE_IN_SERVICE || serviceState.getState()
+                    == ServiceState.STATE_EMERGENCY_ONLY)) {
+                assertTrue("Country code '" + countryCode + "' did not match "
+                        + ISO_COUNTRY_CODE_PATTERN + " for slot " + i,
+                        Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
+            } else {
+                assertTrue("Country code could be empty when out of service",
+                        Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)
+                        || TextUtils.isEmpty(countryCode));
+            }
+        }
 
         for (int i = 0; i < mTelephonyManager.getPhoneCount(); i++) {
-            SubscriptionInfo subscriptionInfo =
-                    mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(i);
-            if (subscriptionInfo != null) {
-                countryCode = mTelephonyManager.getNetworkCountryIso(i);
-                assertTrue("Country code '" + countryCode + "' did not match "
-                                + ISO_COUNTRY_CODE_PATTERN + " for slot " + i,
-                        Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
-            }
+            countryCode = mTelephonyManager.getNetworkCountryIso(i);
+            assertTrue("Country code must match " + ISO_COUNTRY_CODE_PATTERN + "or empty",
+                    Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)
+                    || TextUtils.isEmpty(countryCode));
         }
     }
 
@@ -1274,19 +1302,20 @@
     public void testSetSystemSelectionChannels() {
         assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
 
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         List<RadioAccessSpecifier> channels;
         try {
-            channels = ShellIdentityUtils.invokeMethodWithShellPermissions(
-                    mTelephonyManager, TelephonyManager::getSystemSelectionChannels);
+            uiAutomation.adoptShellPermissionIdentity();
+            channels = mTelephonyManager.getSystemSelectionChannels();
         } catch (IllegalStateException e) {
             // TODO (b/189255895): Allow ISE once API is enforced in IRadio 2.1.
             Log.d(TAG, "Skipping test since system selection channels are not available.");
             return;
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
         }
 
         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1);
-        final UiAutomation uiAutomation =
-                InstrumentationRegistry.getInstrumentation().getUiAutomation();
         try {
             uiAutomation.adoptShellPermissionIdentity();
             // This is a oneway binder call, meaning we may return before the permission check
@@ -1303,20 +1332,29 @@
             uiAutomation.dropShellPermissionIdentity();
         }
 
+        uiAutomation.adoptShellPermissionIdentity();
+
         // Try calling the API that doesn't provide feedback. We have no way of knowing if it
         // succeeds, so just make sure nothing crashes.
-        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
-                tp -> tp.setSystemSelectionChannels(Collections.emptyList()));
+        mTelephonyManager.setSystemSelectionChannels(Collections.emptyList());
 
         // Assert that we get back the value we set.
-        assertEquals(Collections.emptyList(),
-                ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
-                TelephonyManager::getSystemSelectionChannels));
+        assertEquals(Collections.emptyList(), mTelephonyManager.getSystemSelectionChannels());
 
-        // Reset the values back to the original.
-        List<RadioAccessSpecifier> finalChannels = channels;
-        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
-                tp -> tp.setSystemSelectionChannels(finalChannels));
+        try {
+            // Reset the values back to the original. Use callback to ensure we don't drop
+            // the shell permission until the original state is restored.
+            mTelephonyManager.setSystemSelectionChannels(channels,
+                    getContext().getMainExecutor(), queue::offer);
+            Boolean result = queue.poll(1000, TimeUnit.MILLISECONDS);
+            if (result == null || !result) {
+                Log.e(TAG, "Invalid response when resetting initial system selection channels.");
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Interrupted while resetting initial system selection channels.");
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
+        }
     }
 
     @Test
@@ -1729,6 +1767,10 @@
     @Test
     public void testRebootRadio() throws Throwable {
         assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
+        if (mRadioVersion <= RADIO_HAL_VERSION_2_0) {
+            Log.d(TAG, "Skipping test since rebootModem is not supported.");
+            return;
+        }
 
         TestThread t = new TestThread(() -> {
             Looper.prepare();
diff --git a/tests/tests/uidmigration/src/android/uidmigration/cts/SharedUserMigrationTest.kt b/tests/tests/uidmigration/src/android/uidmigration/cts/SharedUserMigrationTest.kt
index 1f7af46..94fc698 100644
--- a/tests/tests/uidmigration/src/android/uidmigration/cts/SharedUserMigrationTest.kt
+++ b/tests/tests/uidmigration/src/android/uidmigration/cts/SharedUserMigrationTest.kt
@@ -87,6 +87,11 @@
         assertTrue(pkgs.sameAs(Const.INSTALL_TEST_PKG2))
         pkgInfo = mPm.getPackageInfo(Const.INSTALL_TEST_PKG, FLAG_ZERO)
         assertNull(pkgInfo.sharedUserId)
+        // Upgrading an APK with sharedUserMaxSdkVersion set should not change its UID.
+        assertTrue(installPackage(InstallTest.APK4))
+        val newPkgInfo = mPm.getPackageInfo(Const.INSTALL_TEST_PKG, FLAG_ZERO)
+        assertNull(newPkgInfo.sharedUserId)
+        assertEquals(pkgInfo.applicationInfo.uid, newPkgInfo.applicationInfo.uid)
     }
 
     private fun testBestEffort(uid: Int) {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
index 7d73da9..f00f0b1 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
@@ -125,6 +125,8 @@
                     canvas.drawColor(Color.WHITE);
                     p.setColor(Color.BLACK);
                     p.setAntiAlias(false);
+                    // ensure the lines do not hit pixel edges
+                    canvas.translate(0.05f, 0.05f);
                     float[] pts = {
                             0, 0, 80, 80, 80, 0, 0, 80, 40, 50, 60, 50
                     };
diff --git a/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java b/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
index a4ef244..e0c172a 100644
--- a/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
@@ -21,12 +21,17 @@
 
 import android.app.Instrumentation;
 import android.graphics.Color;
+import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.uiautomator.UiDevice;
 import android.view.Gravity;
+import android.view.InputEvent;
+import android.view.MotionEvent;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.PopupWindow;
 
+import androidx.annotation.NonNull;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.filters.MediumTest;
@@ -40,7 +45,10 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+// @AppModeFull because GestureNavRule does not work for
+// instant mode tests (b/238975931)
 @MediumTest
+@AppModeFull
 @RunWith(AndroidJUnit4.class)
 public class BackInvokedOnWidgetsTest {
 
@@ -93,7 +101,45 @@
     private void doBackGesture() {
         int midHeight = mUiDevice.getDisplayHeight() / 2;
         int midWidth = mUiDevice.getDisplayWidth() / 2;
-        mUiDevice.swipe(0, midHeight, midWidth, midHeight, 100);
+        quickSwipe(0, midHeight, midWidth, midHeight, 10);
         mUiDevice.waitForIdle();
     }
+
+    private void injectInputEventUnSynced(@NonNull InputEvent event) {
+        mInstrumentation.getUiAutomation().injectInputEvent(event, false /* sync */,
+                false /* waitForAnimations */);
+    }
+
+    /**
+     * Injecting a sequence of motion event to simulate swipe without waiting for sync transaction.
+     */
+    private void quickSwipe(float startX, float startY, float endX, float endY, int steps) {
+        if (steps <= 0) {
+            steps = 1;
+        }
+        final long startDownTime = SystemClock.uptimeMillis();
+        MotionEvent firstDown = MotionEvent.obtain(startDownTime, startDownTime,
+                MotionEvent.ACTION_DOWN, startX, startY, 0);
+        injectInputEventUnSynced(firstDown);
+
+        // inject in every 5 ms.
+        final int delayMillis = 5;
+        long nextEventTime = startDownTime + delayMillis;
+        final float stepGapX = (endX - startX) / steps;
+        final float stepGapY = (endY - startY) / steps;
+        for (int i = 0; i < steps; i++) {
+            SystemClock.sleep(delayMillis);
+            final float nextX = startX + stepGapX * i;
+            final float nextY = startY + stepGapY * i;
+            MotionEvent move = MotionEvent.obtain(startDownTime, nextEventTime,
+                    MotionEvent.ACTION_MOVE, nextX, nextY, 0);
+            injectInputEventUnSynced(move);
+            nextEventTime += delayMillis;
+        }
+
+        SystemClock.sleep(delayMillis);
+        MotionEvent up = MotionEvent.obtain(startDownTime, nextEventTime,
+                MotionEvent.ACTION_UP, endX, endY, 0);
+        injectInputEventUnSynced(up);
+    }
 }
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
index f7322dd..464fb4c 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
@@ -274,6 +274,29 @@
                 new LinkedList<Integer>(Arrays.asList(waitSingleSync)));
     }
 
+    private NetworkInfo.DetailedState waitForNextNetworkState() {
+        assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
+        assertNotNull(mMySync.expectedNetworkInfo);
+        return mMySync.expectedNetworkInfo.getDetailedState();
+    }
+
+    private boolean waitForConnectedNetworkState() {
+        // The possible orders of network states are:
+        // * IDLE > CONNECTING > CONNECTED for lazy initialization
+        // * DISCONNECTED > CONNECTING > CONNECTED for previous group removal
+        // * CONNECTING > CONNECTED
+        NetworkInfo.DetailedState state = waitForNextNetworkState();
+        if (state == NetworkInfo.DetailedState.IDLE
+                || state == NetworkInfo.DetailedState.DISCONNECTED) {
+            state = waitForNextNetworkState();
+        }
+        if (state != NetworkInfo.DetailedState.CONNECTING) {
+            return false;
+        }
+        state = waitForNextNetworkState();
+        return state == NetworkInfo.DetailedState.CONNECTED;
+    }
+
     private boolean waitForServiceResponse(MyResponse waitResponse) {
         synchronized (waitResponse) {
             long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
@@ -508,21 +531,7 @@
         mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener);
         assertTrue(waitForServiceResponse(mMyResponse));
         assertTrue(mMyResponse.success);
-
-        // The first network state might be IDLE due to
-        // lazy initialization, but not CONNECTED.
-        for (int i = 0; i < 2; i++) {
-            assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
-            assertNotNull(mMySync.expectedNetworkInfo);
-            if (NetworkInfo.DetailedState.CONNECTED ==
-                    mMySync.expectedNetworkInfo.getDetailedState()) {
-                break;
-            }
-            assertEquals(NetworkInfo.DetailedState.IDLE,
-                    mMySync.expectedNetworkInfo.getDetailedState());
-        }
-        assertEquals(NetworkInfo.DetailedState.CONNECTED,
-                mMySync.expectedNetworkInfo.getDetailedState());
+        assertTrue(waitForConnectedNetworkState());
 
         resetResponse(mMyResponse);
         mWifiP2pManager.requestNetworkInfo(mWifiP2pChannel,
@@ -660,21 +669,7 @@
         mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener);
         assertTrue(waitForServiceResponse(mMyResponse));
         assertTrue(mMyResponse.success);
-
-        // The first network state might be IDLE due to
-        // lazy initialization, but not CONNECTED.
-        for (int i = 0; i < 2; i++) {
-            assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
-            assertNotNull(mMySync.expectedNetworkInfo);
-            if (NetworkInfo.DetailedState.CONNECTED ==
-                    mMySync.expectedNetworkInfo.getDetailedState()) {
-                break;
-            }
-            assertEquals(NetworkInfo.DetailedState.IDLE,
-                    mMySync.expectedNetworkInfo.getDetailedState());
-        }
-        assertEquals(NetworkInfo.DetailedState.CONNECTED,
-                mMySync.expectedNetworkInfo.getDetailedState());
+        assertTrue(waitForConnectedNetworkState());
 
         resetResponse(mMyResponse);
         mWifiP2pManager.removeGroup(mWifiP2pChannel, mActionListener);
@@ -707,10 +702,7 @@
         mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener);
         assertTrue(waitForServiceResponse(mMyResponse));
         assertTrue(mMyResponse.success);
-        assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
-        assertNotNull(mMySync.expectedNetworkInfo);
-        assertEquals(NetworkInfo.DetailedState.CONNECTED,
-                mMySync.expectedNetworkInfo.getDetailedState());
+        assertTrue(waitForConnectedNetworkState());
 
         resetResponse(mMyResponse);
         mWifiP2pManager.removeGroup(mWifiP2pChannel, mActionListener);
@@ -812,21 +804,7 @@
         mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener);
         assertTrue(waitForServiceResponse(mMyResponse));
         assertTrue(mMyResponse.success);
-
-        // The first network state might be IDLE due to
-        // lazy initialization, but not CONNECTED.
-        for (int i = 0; i < 2; i++) {
-            assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
-            assertNotNull(mMySync.expectedNetworkInfo);
-            if (NetworkInfo.DetailedState.CONNECTED
-                    == mMySync.expectedNetworkInfo.getDetailedState()) {
-                break;
-            }
-            assertEquals(NetworkInfo.DetailedState.IDLE,
-                    mMySync.expectedNetworkInfo.getDetailedState());
-        }
-        assertEquals(NetworkInfo.DetailedState.CONNECTED,
-                mMySync.expectedNetworkInfo.getDetailedState());
+        assertTrue(waitForConnectedNetworkState());
 
         resetResponse(mMyResponse);
         MacAddress peerMacAddress = MacAddress.fromString(mTestWifiP2pPeerConfig.deviceAddress);
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyMultiInternetWifiNetworkTest.java b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyMultiInternetWifiNetworkTest.java
index b61f11d..314d097 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyMultiInternetWifiNetworkTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyMultiInternetWifiNetworkTest.java
@@ -151,6 +151,8 @@
                 () -> wifiManager.setScanThrottleEnabled(false));
 
         // Enable Wifi
+        sWasWifiEnabled = ShellIdentityUtils.invokeWithShellPermissions(
+                () -> wifiManager.isWifiEnabled());
         ShellIdentityUtils.invokeWithShellPermissions(() -> wifiManager.setWifiEnabled(true));
         // Make sure wifi is enabled
         PollingCheck.check("Wifi not enabled", DURATION_MILLIS, () -> wifiManager.isWifiEnabled());
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index dfc8031..d785d96 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -284,5 +284,6 @@
 
     <!-- b/237035040 -->
     <option name="compatibility:exclude-filter" value="CtsGraphicsTestCases android.graphics.cts.ImageDecoderTest#testDecode10BitHeifWithLowRam" />
+    <option name="compatibility:exclude-filter" value="CtsGraphicsTestCases[instant] android.graphics.cts.ImageDecoderTest#testDecode10BitHeifWithLowRam" />
 
 </configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
index bfbb35a..54d3f7e 100644
--- a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
@@ -117,4 +117,8 @@
 
     <!-- b/235453601 -->
     <option name="compatibility:exclude-filter" value="CtsMediaPerformanceClassTestCases android.mediapc.cts.MultiDecoderPerfTest" />
+
+    <!-- b/238155422 -->
+    <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.ConnectivityManagerTest#testSetAirplaneMode" />
+
 </configuration>