Merge "[WIP] Test unflattening android-cts.zip" into tm-dev
diff --git a/apps/CameraITS/build/scripts/gpylint_rcfile b/apps/CameraITS/build/scripts/gpylint_rcfile
index fe9f3d1..38c1693 100644
--- a/apps/CameraITS/build/scripts/gpylint_rcfile
+++ b/apps/CameraITS/build/scripts/gpylint_rcfile
@@ -61,9 +61,6 @@
 # Inject some known modules.
 inject-known-modules=no
 
-# The import path resolver
-resolver=blaze
-
 
 [REPORTS]
 
diff --git a/apps/CameraITS/tests/its_base_test.py b/apps/CameraITS/tests/its_base_test.py
index 0240682..9b29ab7 100644
--- a/apps/CameraITS/tests/its_base_test.py
+++ b/apps/CameraITS/tests/its_base_test.py
@@ -171,6 +171,7 @@
     self.tablet.adb.shell('am force-stop com.google.android.apps.photos')
     self.tablet.adb.shell('am force-stop com.android.gallery3d')
     self.tablet.adb.shell('am force-stop com.sec.android.gallery3d')
+    self.tablet.adb.shell('am force-stop com.miui.gallery')
 
   def set_tablet_landscape_orientation(self):
     """Sets the screen orientation to landscape.
diff --git a/apps/CameraITS/tests/scene0/test_tonemap_curve.py b/apps/CameraITS/tests/scene0/test_tonemap_curve.py
index 48c95a3..c8d79d5 100644
--- a/apps/CameraITS/tests/scene0/test_tonemap_curve.py
+++ b/apps/CameraITS/tests/scene0/test_tonemap_curve.py
@@ -34,7 +34,7 @@
 COLOR_CHECKER = {'BLACK': [0, 0, 0], 'RED': [1, 0, 0], 'GREEN': [0, 1, 0],
                  'BLUE': [0, 0, 1], 'MAGENTA': [1, 0, 1], 'CYAN': [0, 1, 1],
                  'YELLOW': [1, 1, 0], 'WHITE': [1, 1, 1]}
-DELTA = 0.0005  # crop on edge of color bars
+DELTA = 0.005  # crop on each edge of color bars
 RAW_TOL = 0.001  # 1 DN in [0:1] (1/(1023-64)
 RGB_VAR_TOL = 0.0039  # 1/255
 RGB_MEAN_TOL = 0.1
@@ -65,14 +65,14 @@
     x_norm = num / N_BARS + DELTA
     w_norm = 1 / N_BARS - 2 * DELTA
     logging.debug('x_norm: %.5f, w_norm: %.5f', x_norm, w_norm)
-  elif w_crop < w_orig:  # adject patch width to match vertical RAW crop
+  elif w_crop < w_orig:  # adjust patch width to match vertical RAW crop
     w_delta_edge = (w_orig - w_crop) / 2
     w_bar_orig = w_orig / N_BARS
     if num == 0:  # left-most bar
       x_norm = DELTA
       w_norm = (w_bar_orig - w_delta_edge) / w_crop - 2 * DELTA
     elif num == N_BARS:  # right-most bar
-      x_norm = (w_bar_orig*num - w_delta_edge)/w_crop + DELTA
+      x_norm = (w_bar_orig * num - w_delta_edge) / w_crop + DELTA
       w_norm = (w_bar_orig - w_delta_edge) / w_crop - 2 * DELTA
     else:  # middle bars
       x_norm = (w_bar_orig * num - w_delta_edge) / w_crop + DELTA
@@ -159,7 +159,6 @@
   color_variance_errs = []
   for n in range(N_BARS):
     x_norm, w_norm = get_yuv_patch_coordinates(n, raw_w, raw_w_cropped)
-    logging.debug('x_norm: %.3f', x_norm)
     raw_patch = image_processing_utils.get_image_patch(img_raw, x_norm, Y_NORM,
                                                        w_norm, H_NORM)
     yuv_patch = image_processing_utils.get_image_patch(img_yuv, x_norm, Y_NORM,
diff --git a/apps/CameraITS/tests/scene1_1/test_ae_af.py b/apps/CameraITS/tests/scene1_1/test_ae_af.py
index 09a1470..852c786 100644
--- a/apps/CameraITS/tests/scene1_1/test_ae_af.py
+++ b/apps/CameraITS/tests/scene1_1/test_ae_af.py
@@ -67,8 +67,8 @@
                                                      do_awb=three_a_req[2],
                                                      mono_camera=mono_camera)
 
-        except error_util.CameraItsError:
-          raise AssertionError(f'{k} did not converge.')
+        except error_util.CameraItsError as e_util:
+          raise AssertionError(f'{k} did not converge.') from e_util
 
         logging.debug('AWB gains: %s, xform: %s', str(awb_gains),
                       str(awb_xform))
diff --git a/apps/CameraITS/tests/scene1_1/test_capture_result.py b/apps/CameraITS/tests/scene1_1/test_capture_result.py
index 304a737..f3a9e9d 100644
--- a/apps/CameraITS/tests/scene1_1/test_capture_result.py
+++ b/apps/CameraITS/tests/scene1_1/test_capture_result.py
@@ -213,7 +213,7 @@
             metadata['android.tonemap.curve']['green'],
             metadata['android.tonemap.curve']['blue']]
   logging.debug('Tonemap: %s', str(curves[0][1::16]))
-  for j, c in enumerate(curves):
+  for _, c in enumerate(curves):
     if not c:
       raise AssertionError('c in curves is empty.')
     if not all([np.isclose(c[i], c[i+1], atol=ISCLOSE_ATOL)
diff --git a/apps/CameraITS/tests/scene1_2/test_raw_exposure.py b/apps/CameraITS/tests/scene1_2/test_raw_exposure.py
index 5bd44e8..bcf426d 100644
--- a/apps/CameraITS/tests/scene1_2/test_raw_exposure.py
+++ b/apps/CameraITS/tests/scene1_2/test_raw_exposure.py
@@ -85,15 +85,16 @@
   gb = [m[2] for m in means[1:]]
   b = [m[3] for m in means[1:]]
   pylab.figure('%s_%s' % (NAME, sens))
-  pylab.plot(exps, r, 'r.-')
-  pylab.plot(exps, b, 'b.-')
-  pylab.plot(exps, gr, 'g.-')
-  pylab.plot(exps, gb, 'k.-')
+  pylab.plot(exps, r, 'r.-', label='R')
+  pylab.plot(exps, gr, 'g.-', label='Gr')
+  pylab.plot(exps, gb, 'k.-', label='Gb')
+  pylab.plot(exps, b, 'b.-', label='B')
   pylab.xscale('log')
   pylab.yscale('log')
   pylab.title('%s ISO=%d' % (NAME, sens))
   pylab.xlabel('Exposure time (ms)')
   pylab.ylabel('Center patch pixel mean')
+  pylab.legend(loc='lower right', numpoints=1, fancybox=True)
   matplotlib.pyplot.savefig(
       '%s_s=%d.png' % (os.path.join(log_path, NAME), sens))
   pylab.clf()
diff --git a/apps/CameraITS/tests/scene1_2/test_raw_sensitivity.py b/apps/CameraITS/tests/scene1_2/test_raw_sensitivity.py
index 8c542ab..62a017b 100644
--- a/apps/CameraITS/tests/scene1_2/test_raw_sensitivity.py
+++ b/apps/CameraITS/tests/scene1_2/test_raw_sensitivity.py
@@ -63,7 +63,6 @@
           camera_properties_utils.per_frame_control(props) and
           not camera_properties_utils.mono_camera(props))
       name_with_log_path = os.path.join(self.log_path, NAME)
-      camera_fov = float(cam.calc_camera_fov(props))
 
       # Load chart for scene (chart_distance=0 for no chart scaling)
       its_session_utils.load_scene(
diff --git a/apps/CameraITS/tests/scene2_a/test_format_combos.py b/apps/CameraITS/tests/scene2_a/test_format_combos.py
index 7568da7..c05301b 100644
--- a/apps/CameraITS/tests/scene2_a/test_format_combos.py
+++ b/apps/CameraITS/tests/scene2_a/test_format_combos.py
@@ -147,7 +147,7 @@
               if STOP_AT_FIRST_FAILURE:
                 raise AssertionError(
                     f'Capture fail at combo req: {req_str}, fmt: {fmt_combo}, '
-                    f'burst: {burst_len}')
+                    f'burst: {burst_len}') from e
             n += 1
 
       num_fail = len(failures)
diff --git a/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py b/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
index e77a702..3959b42 100644
--- a/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
+++ b/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
@@ -148,7 +148,7 @@
       camera_properties_utils.skip_unless(
           first_api_level >= its_session_utils.ANDROID13_API_LEVEL,
           'First API level should be {} or higher. Found {}.'.format(
-            its_session_utils.ANDROID13_API_LEVEL, first_api_level))
+              its_session_utils.ANDROID13_API_LEVEL, first_api_level))
 
       supported_stabilization_modes = props[
           'android.control.availableVideoStabilizationModes'
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 eca64ef..06f3f12 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
@@ -182,7 +182,8 @@
 
           for hlg10_param in hlg10_params:
             video_recording_obj = cam.do_basic_recording(
-                profile_id, quality, _VIDEO_RECORDING_DURATION_SECONDS, 0, hlg10_param)
+                profile_id, quality, _VIDEO_RECORDING_DURATION_SECONDS, 0,
+                hlg10_param)
             logging.debug('video_recording_obj: %s', video_recording_obj)
             # TODO(ruchamk): Modify video recording object to send videoFrame
             # width and height instead of videoSize to avoid string operation
@@ -196,7 +197,8 @@
                                self.log_path])
             logging.debug('Recorded video is available at: %s',
                           self.log_path)
-            video_file_name = video_recording_obj['recordedOutputPath'].split('/')[-1]
+            video_file_name = video_recording_obj[
+                'recordedOutputPath'].split('/')[-1]
             logging.debug('video_file_name: %s', video_file_name)
 
             key_frame_files = []
@@ -208,7 +210,8 @@
             last_key_frame_file = video_processing_utils.get_key_frame_to_process(
                 key_frame_files)
             logging.debug('last_key_frame: %s', last_key_frame_file)
-            last_key_frame_path = os.path.join(self.log_path, last_key_frame_file)
+            last_key_frame_path = os.path.join(
+                self.log_path, last_key_frame_file)
 
             # Convert lastKeyFrame to numpy array
             np_image = image_processing_utils.convert_image_to_numpy_array(
@@ -222,7 +225,7 @@
 
             max_img_value = _MAX_8BIT_IMGS
             if hlg10_param:
-                max_img_value = _MAX_10BIT_IMGS
+              max_img_value = _MAX_10BIT_IMGS
 
             # Check pass/fail for fov coverage for all fmts in AR_CHECKED
             fov_chk_msg = image_fov_utils.check_fov(
@@ -232,7 +235,8 @@
                   os.path.join(self.log_path, _NAME), quality, width, height)
               fov_chk_quality_msg = f'Quality: {quality} {fov_chk_msg}'
               failed_fov.append(fov_chk_quality_msg)
-              image_processing_utils.write_image(np_image/max_img_value, img_name, True)
+              image_processing_utils.write_image(
+                  np_image/max_img_value, img_name, True)
 
             # Check pass/fail for aspect ratio.
             ar_chk_msg = image_fov_utils.check_ar(
@@ -242,14 +246,16 @@
               img_name = '%s_%s_w%d_h%d_ar.png' % (
                   os.path.join(self.log_path, _NAME), quality, width, height)
               failed_ar.append(ar_chk_msg)
-              image_processing_utils.write_image(np_image/max_img_value, img_name, True)
+              image_processing_utils.write_image(
+                  np_image/max_img_value, img_name, True)
 
             # Check pass/fail for crop.
             if run_crop_test:
               # Normalize the circle size to 1/4 of the image size, so that
               # circle size won't affect the crop test result
               crop_thresh_factor = ((min(ref_fov['w'], ref_fov['h']) / 4.0) /
-                                    max(ref_fov['circle_w'], ref_fov['circle_h']))
+                                    max(ref_fov['circle_w'],
+                                        ref_fov['circle_h']))
               crop_chk_msg = image_fov_utils.check_crop(
                   circle, cc_ct_gt, width, height,
                   f'{quality}', crop_thresh_factor)
diff --git a/apps/CameraITS/tests/scene6/test_zoom.py b/apps/CameraITS/tests/scene6/test_zoom.py
index c828ad5..d4fa21c 100644
--- a/apps/CameraITS/tests/scene6/test_zoom.py
+++ b/apps/CameraITS/tests/scene6/test_zoom.py
@@ -273,13 +273,13 @@
           if circle_cropped(circle, size):
             logging.debug('zoom %.2f is too large! Skip further captures', z)
             break
-        except AssertionError:
+        except AssertionError as e:
           if z/z_list[0] >= ZOOM_MAX_THRESH:
             break
           else:
             raise AssertionError(
                 f'No circle was detected for zoom ratio <= {ZOOM_MAX_THRESH}. '
-                'Please take pictures according to instructions carefully!')
+                'Take pictures according to instructions carefully!') from e
         test_data[i] = {'z': z, 'circle': circle, 'r_tol': radius_tol,
                         'o_tol': offset_tol, 'fl': cap_fl}
 
diff --git a/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py b/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
index 64b22d9..c6b852c 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
@@ -20,9 +20,9 @@
 
 from mobly import test_runner
 
+import its_base_test
 import camera_properties_utils
 import image_processing_utils
-import its_base_test
 import its_session_utils
 import sensor_fusion_utils
 import video_processing_utils
@@ -33,11 +33,11 @@
 _IMG_FORMAT = 'png'
 _MIN_PHONE_MOVEMENT_ANGLE = 5  # degrees
 _NAME = os.path.splitext(os.path.basename(__file__))[0]
-_NUM_ROTATIONS = 25
+_NUM_ROTATIONS = 12
 _START_FRAME = 30  # give 3A some frames to warm up
 _VIDEO_DELAY_TIME = 5.5  # seconds
 _VIDEO_DURATION = 5.5  # seconds
-_VIDEO_STABILIZATION_FACTOR = 0.6  # 60% of gyro movement allowed
+_VIDEO_STABILIZATION_FACTOR = 0.7  # 70% of gyro movement allowed
 _PREVIEW_STABILIZATION_MODE_PREVIEW = 2
 
 
@@ -86,7 +86,7 @@
   return recording_obj
 
 
-class PreviewStabilityTest(its_base_test.ItsBaseTest):
+class PreviewStabilizationTest(its_base_test.ItsBaseTest):
   """Tests if preview is stabilized.
 
   Camera is moved in sensor fusion rig on an arc of 15 degrees.
@@ -115,7 +115,7 @@
       camera_properties_utils.skip_unless(
           first_api_level >= its_session_utils.ANDROID13_API_LEVEL,
           'First API level should be {} or higher. Found {}.'.format(
-            its_session_utils.ANDROID13_API_LEVEL, first_api_level))
+              its_session_utils.ANDROID13_API_LEVEL, first_api_level))
 
       supported_stabilization_modes = props[
           'android.control.availableVideoStabilizationModes'
@@ -124,7 +124,7 @@
       camera_properties_utils.skip_unless(
           supported_stabilization_modes is not None
           and _PREVIEW_STABILIZATION_MODE_PREVIEW
-              in supported_stabilization_modes,
+          in supported_stabilization_modes,
           'Preview Stabilization not supported',
       )
 
@@ -137,9 +137,12 @@
       # Initialize rotation rig
       rot_rig['cntl'] = self.rotator_cntl
       rot_rig['ch'] = self.rotator_ch
+      if rot_rig['cntl'].lower() != 'arduino':
+        raise AssertionError(f'You must use the arduino controller for {_NAME}.')
 
       # List of video resolutions to test
       supported_preview_sizes = cam.get_supported_preview_sizes(self.camera_id)
+      supported_preview_sizes.remove(video_processing_utils.QCIF_SIZE)
       logging.debug('Supported preview resolutions: %s',
                     supported_preview_sizes)
 
@@ -201,10 +204,9 @@
             sensor_fusion_utils.calc_max_rotation_angle(gyro_rots, 'Gyro')
         )
         logging.debug(
-            'Max deflection (degrees): gyro: %.2f, camera: %.2f',
-            max_gyro_angles[-1],
-            max_camera_angles[-1],
-        )
+            'Max deflection (degrees) %s: video: %.3f, gyro: %.3f ratio: %.4f',
+            video_size, max_camera_angles[-1], max_gyro_angles[-1],
+            max_camera_angles[-1] / max_gyro_angles[-1])
 
         # Assert phone is moved enough during test
         if max_gyro_angles[-1] < _MIN_PHONE_MOVEMENT_ANGLE:
@@ -218,9 +220,10 @@
         if max_camera_angle >= max_gyro_angles[i] * _VIDEO_STABILIZATION_FACTOR:
           test_failures.append(
               f'{supported_preview_sizes[i]} video not stabilized enough! '
-              f'Max gyro angle: {max_gyro_angles[i]:.2f}, Max camera angle: '
-              f'{max_camera_angle:.2f}, stabilization factor THRESH: '
-              f'{_VIDEO_STABILIZATION_FACTOR}.')
+              f'Max video angle:  {max_camera_angle:.3f}, '
+              f'Max gyro angle: {max_gyro_angles[i]:.3f}, '
+              f'ratio: {max_camera_angle/max_gyro_angles[i]:.4f} '
+              f'THRESH: {_VIDEO_STABILIZATION_FACTOR}.')
 
       if test_failures:
         raise AssertionError(test_failures)
diff --git a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
index e6eec9f..1939935 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
@@ -337,7 +337,7 @@
           " smaller values of 'w', 'h', 'fps', or 'test_length'.")
 
     if replay:
-      events, frames, _, h = load_data()
+      events, frames, _, _ = load_data()
     else:
       with its_session_utils.ItsSession(
           device_id=self.dut.serial,
diff --git a/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py b/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
index 7046669..0be38b5 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
@@ -22,9 +22,9 @@
 from mobly import test_runner
 import numpy as np
 
+import its_base_test
 import camera_properties_utils
 import image_processing_utils
-import its_base_test
 import its_session_utils
 import sensor_fusion_utils
 import video_processing_utils
@@ -35,7 +35,7 @@
 _IMG_FORMAT = 'png'
 _MIN_PHONE_MOVEMENT_ANGLE = 5  # degrees
 _NAME = os.path.splitext(os.path.basename(__file__))[0]
-_NUM_ROTATIONS = 25
+_NUM_ROTATIONS = 12
 _RADS_TO_DEGS = 180/math.pi
 _SEC_TO_NSEC = 1E9
 _START_FRAME = 30  # give 3A 1s to warm up
@@ -115,7 +115,7 @@
   return recording_obj
 
 
-class VideoStabilityTest(its_base_test.ItsBaseTest):
+class VideoStabilizationTest(its_base_test.ItsBaseTest):
   """Tests if video is stabilized.
 
   Camera is moved in sensor fusion rig on an arc of 15 degrees.
@@ -140,8 +140,12 @@
       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)
+      supported_stabilization_modes = props[
+          'android.control.availableVideoStabilizationModes']
+
       camera_properties_utils.skip_unless(
-          first_api_level >= its_session_utils.ANDROID13_API_LEVEL)
+          first_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
       facing = props['android.lens.facing']
@@ -152,6 +156,8 @@
       # Initialize rotation rig
       rot_rig['cntl'] = self.rotator_cntl
       rot_rig['ch'] = self.rotator_ch
+      if rot_rig['cntl'].lower() != 'arduino':
+        raise AssertionError(f'You must use the arduino controller for {_NAME}.')
 
       # Create list of video qualities to test
       supported_video_qualities = cam.get_supported_video_qualities(
@@ -216,8 +222,10 @@
         gyro_rots = _conv_acceleration_to_movement(gyro_events)
         max_gyro_angles.append(sensor_fusion_utils.calc_max_rotation_angle(
             gyro_rots, 'Gyro'))
-        logging.debug('Max deflection (degrees): gyro: %.2f, camera: %.2f',
-                      max_gyro_angles[-1], max_camera_angles[-1])
+        logging.debug(
+            'Max deflection (degrees) %s: video: %.3f, gyro: %.3f, ratio: %.4f',
+            video_quality, max_camera_angles[-1], max_gyro_angles[-1],
+            max_camera_angles[-1] / max_gyro_angles[-1])
 
         # Assert phone is moved enough during test
         if max_gyro_angles[-1] < _MIN_PHONE_MOVEMENT_ANGLE:
@@ -231,9 +239,10 @@
         if max_camera_angle >= max_gyro_angles[i] * _VIDEO_STABILIZATION_FACTOR:
           test_failures.append(
               f'{tested_video_qualities[i]} video not stabilized enough! '
-              f'Max gyro angle: {max_gyro_angles[i]:.2f}, Max camera angle: '
-              f'{max_camera_angle:.2f}, stabilization factor THRESH: '
-              f'{_VIDEO_STABILIZATION_FACTOR}.')
+              f'Max video angle: {max_camera_angle:.3f}, '
+              f'Max gyro angle: {max_gyro_angles[i]:.3f}, '
+              f'ratio: {max_camera_angle}/{max_gyro_angles[-1]:.3f}, '
+              f'THRESH: {_VIDEO_STABILIZATION_FACTOR}.')
       if test_failures:
         raise AssertionError(test_failures)
 
diff --git a/apps/CameraITS/utils/image_processing_utils.py b/apps/CameraITS/utils/image_processing_utils.py
index d0bf08e..19d76c3 100644
--- a/apps/CameraITS/utils/image_processing_utils.py
+++ b/apps/CameraITS/utils/image_processing_utils.py
@@ -137,7 +137,7 @@
   # Cut out the 4x2b LSBs and put each in bits [1:0] of their own 8b words.
   lsbs = img[::, 4::5].reshape(h, w // 4)
   lsbs = numpy.right_shift(
-      numpy.packbits(numpy.unpackbits(lsbs).reshape(h, w // 4, 4, 2), 3), 6)
+      numpy.packbits(numpy.unpackbits(lsbs).reshape((h, w // 4, 4, 2)), 3), 6)
   # Pair the LSB bits group to 0th pixel instead of 3rd pixel
   lsbs = lsbs.reshape(h, w // 4, 4)[:, :, ::-1]
   lsbs = lsbs.reshape(h, w)
@@ -190,7 +190,7 @@
   # Cut out the 2x4b LSBs and put each in bits [3:0] of their own 8b words.
   lsbs = img[::, 2::3].reshape(h, w // 2)
   lsbs = numpy.right_shift(
-      numpy.packbits(numpy.unpackbits(lsbs).reshape(h, w // 2, 2, 4), 3), 4)
+      numpy.packbits(numpy.unpackbits(lsbs).reshape((h, w // 2, 2, 4)), 3), 4)
   # Pair the LSB bits group to pixel 0 instead of pixel 1
   lsbs = lsbs.reshape(h, w // 2, 2)[:, :, ::-1]
   lsbs = lsbs.reshape(h, w)
@@ -243,7 +243,7 @@
   img = Image.open(io.BytesIO(jpeg_buffer))
   w = img.size[0]
   h = img.size[1]
-  return numpy.array(img).reshape(h, w, 3) / 255.0
+  return numpy.array(img).reshape((h, w, 3)) / 255.0
 
 
 def convert_image_to_numpy_array(image_path):
@@ -453,7 +453,7 @@
   img = (((img.reshape(h, w, 3) - black_levels) * scale) * gains).clip(0.0, 1.0)
   if apply_ccm_raw_to_rgb:
     img = numpy.dot(
-        img.reshape(w * h, 3), ccm.T).reshape(h, w, 3).clip(0.0, 1.0)
+        img.reshape(w * h, 3), ccm.T).reshape((h, w, 3)).clip(0.0, 1.0)
   return img
 
 
@@ -938,7 +938,7 @@
     ref_image = [0.1, 0.2, 0.3]
     lut_max = 65536
     lut = numpy.array([i*2 for i in range(lut_max)])
-    x = numpy.array(ref_image).reshape(1, 1, 3)
+    x = numpy.array(ref_image).reshape((1, 1, 3))
     y = apply_lut_to_image(x, lut).reshape(3).tolist()
     y_ref = [i*2 for i in ref_image]
     self.assertTrue(numpy.allclose(y, y_ref, atol=1/lut_max))
diff --git a/apps/CameraITS/utils/its_session_utils.py b/apps/CameraITS/utils/its_session_utils.py
index 722f586..4a6cbf9 100644
--- a/apps/CameraITS/utils/its_session_utils.py
+++ b/apps/CameraITS/utils/its_session_utils.py
@@ -134,10 +134,10 @@
       try:
         socket_lock.bind((ItsSession.IPADDR, ItsSession.LOCK_PORT))
         break
-      except (socket.error, socket.timeout):
+      except (socket.error, socket.timeout) as socket_issue:
         if i == num_retries - 1:
-          raise error_util.CameraItsError(self._device_id,
-                                          'socket lock returns error')
+          raise error_util.CameraItsError(
+              self._device_id, 'socket lock returns error') from socket_issue
         else:
           time.sleep(retry_wait_time_sec)
 
@@ -545,8 +545,9 @@
       VideoRecordingObject: {
         'tag': 'recordingResponse',
         'objValue': {
-          'recordedOutputPath': '/storage/emulated/0/Android/data/com.android.cts.verifier'
-                                '/files/VideoITS/VID_20220324_080414_0_CIF_352x288.mp4',
+          'recordedOutputPath': '/storage/emulated/0/Android/data/'
+                                'com.android.cts.verifier/files/VideoITS/'
+                                'VID_20220324_080414_0_CIF_352x288.mp4',
           'quality': 'preview',
           'videoSize': '352x288'
         }
@@ -1478,8 +1479,8 @@
   try:
     build_sdk_version = int(subprocess.check_output(cmd.split()).rstrip())
     logging.debug('Build SDK version: %d', build_sdk_version)
-  except (subprocess.CalledProcessError, ValueError):
-    raise AssertionError('No build_sdk_version.')
+  except (subprocess.CalledProcessError, ValueError) as exp_errors:
+    raise AssertionError('No build_sdk_version.') from exp_errors
   return build_sdk_version
 
 
diff --git a/apps/CameraITS/utils/sensor_fusion_utils.py b/apps/CameraITS/utils/sensor_fusion_utils.py
index 0f83af9..327b233 100644
--- a/apps/CameraITS/utils/sensor_fusion_utils.py
+++ b/apps/CameraITS/utils/sensor_fusion_utils.py
@@ -146,8 +146,9 @@
     time.sleep(CANAKIT_CMD_TIME)  # This is critical for relay.
     canakit_serial_port.write(cmd_str.encode())
 
-  except IOError:
-    raise IOError(f'Port {CANAKIT_VID}:{CANAKIT_PID} is not open!')
+  except IOError as io_error:
+    raise IOError(
+        f'Port {CANAKIT_VID}:{CANAKIT_PID} is not open!') from io_error
 
 
 def canakit_set_relay_channel_state(canakit_port, ch, state):
diff --git a/apps/CameraITS/utils/video_processing_utils.py b/apps/CameraITS/utils/video_processing_utils.py
index b82e6c5..98d930b 100644
--- a/apps/CameraITS/utils/video_processing_utils.py
+++ b/apps/CameraITS/utils/video_processing_utils.py
@@ -33,6 +33,7 @@
     'LOW',
     'VGA'
 )
+QCIF_SIZE = '176x144'
 
 
 def extract_key_frames_from_video(log_path, video_file_name):
@@ -83,7 +84,7 @@
 
   logging.debug('Extracted key frames: %s', key_frame_files)
   logging.debug('Length of key_frame_files: %d', len(key_frame_files))
-  if not len(key_frame_files):
+  if not key_frame_files:
     raise AssertionError('No key frames extracted. Check source video.')
 
   return key_frame_files
@@ -142,7 +143,7 @@
   file_list = sorted(
       [_ for _ in os.listdir(log_path) if (_.endswith(img_format)
                                            and ffmpeg_image_name in _)])
-  if not len(file_list):
+  if not file_list:
     raise AssertionError('No frames extracted. Check source video.')
 
   return file_list
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 8bc47d7..35afa20 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -105,7 +105,9 @@
     <uses-permission android:name="android.permission.USE_EXACT_ALARM" />
 
     <!-- Needed for Wi-Fi Direct tests from T -->
-    <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
+    <uses-permission
+        android:name="android.permission.NEARBY_WIFI_DEVICES"
+        android:usesPermissionFlags="neverForLocation" />
 
     <!-- READ_LOGS User Consent Test from T -->
     <uses-permission android:name="android.permission.READ_LOGS" />
@@ -4143,10 +4145,10 @@
                  test parent : PresenceTestActivity
         -->
         <activity
-            android:name=".presence.NanPrecisionAndBiasTestActivity"
+            android:name=".presence.NanPrecisionTestActivity"
             android:configChanges="keyboardHidden|orientation|screenSize"
             android:exported="true"
-            android:label="@string/nan_precision_and_bias" >
+            android:label="@string/nan_precision" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
diff --git a/apps/CtsVerifier/res/layout-port/camera_video.xml b/apps/CtsVerifier/res/layout-port/camera_video.xml
new file mode 100644
index 0000000..2a90e67
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-port/camera_video.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" >
+
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="0dp"
+            android:layout_height="fill_parent"
+            android:layout_weight="2" >
+
+            <Spinner
+                android:id="@+id/cameras_selection"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"/>
+            <Spinner
+                android:id="@+id/resolution_selection"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"/>
+
+            <LinearLayout
+                android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1" >
+
+                <Button
+                    android:id="@+id/record_button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/record_button_text"/>
+                <Button
+                    android:id="@+id/next_button"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/next_button_text" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="2" >
+
+                <TextView
+                    android:id="@+id/status_label"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/status_ready"
+                    android:padding="2dp"
+                    android:textSize="16sp"
+                    android:gravity="center" />
+            </LinearLayout>
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" >
+
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="0dp"
+            android:layout_height="fill_parent"
+            android:layout_weight="3"
+            android:gravity="center" >
+
+            <TextureView
+                android:id="@+id/video_capture"
+                android:layout_height="0dp"
+                android:layout_width="fill_parent"
+                android:layout_weight="3" />
+            <TextView
+                android:id="@+id/camera_video_capture_label"
+                android:layout_height="wrap_content"
+                android:layout_width="fill_parent"
+                android:text="@string/video_capture_label"
+                android:padding="2dp"
+                android:textSize="16sp"
+                android:gravity="center" />
+
+        </LinearLayout>
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="0dp"
+            android:layout_height="fill_parent"
+            android:layout_weight="3"
+            android:gravity="center" >
+
+            <VideoView
+                android:id="@+id/video_playback"
+                android:layout_height="0dp"
+                android:layout_width="fill_parent"
+                android:layout_weight="3" />
+            <TextView
+                android:id="@+id/camera_video_playback_label"
+                android:layout_height="wrap_content"
+                android:layout_width="fill_parent"
+                android:text="@string/video_playback_label"
+                android:padding="2dp"
+                android:textSize="16sp"
+                android:gravity="center" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <include layout="@layout/pass_fail_buttons" />
+
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/audio_dev_notify.xml b/apps/CtsVerifier/res/layout/audio_dev_notify.xml
index e8f49ce..6fa178d 100644
--- a/apps/CtsVerifier/res/layout/audio_dev_notify.xml
+++ b/apps/CtsVerifier/res/layout/audio_dev_notify.xml
@@ -38,6 +38,12 @@
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical">
+      <Button
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:id="@+id/audio_dev_notification_connect_clearmsgs_btn"
+          android:text="@string/audio_dev_notification_clearmsgs"/>
+
       <TextView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
diff --git a/apps/CtsVerifier/res/layout/nan_precision.xml b/apps/CtsVerifier/res/layout/nan_precision.xml
new file mode 100644
index 0000000..b558725
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/nan_precision.xml
@@ -0,0 +1,92 @@
+<?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="number"
+                          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="number"
+                          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="number"
+                          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="number"
+                          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="number"
+                          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="number"
+                          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="number"
+                          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="number"
+                          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/nan_precision_and_bias.xml b/apps/CtsVerifier/res/layout/nan_precision_and_bias.xml
deleted file mode 100644
index 9e5782e..0000000
--- a/apps/CtsVerifier/res/layout/nan_precision_and_bias.xml
+++ /dev/null
@@ -1,72 +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_and_bias_instruction"
-                      android:id="@+id/nan_precision_and_bias_instruction"
-                      android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:scrollbars="vertical"/>
-            <LinearLayout android:orientation="vertical"
-                          android:layout_width="match_parent"
-                          android:layout_height="wrap_content">
-                <EditText android:id="@+id/distance_range_1m_gt"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="number"
-                          android:hint="@string/report_distance_range_1m_gt"/>
-                <EditText android:id="@+id/distance_range_3m_gt"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="number"
-                          android:hint="@string/report_distance_range_3m_gt"/>
-                <EditText android:id="@+id/distance_range_5m_gt"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="number"
-                          android:hint="@string/report_distance_range_5m_gt"/>
-                <EditText android:id="@+id/bias_meters"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_bias_meters"/>
-                <EditText android:id="@+id/slope"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_slope"/>
-                <EditText android:id="@+id/reference_device"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:hint="@string/report_reference_device"/>
-            </LinearLayout>
-
-            <include android:layout_width="match_parent"
-                     android:layout_height="wrap_content"
-                     layout="@layout/pass_fail_buttons"/>
-        </LinearLayout>
-    </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index d37bace..d595bef 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -6590,6 +6590,11 @@
         The Presence tests check whether or not a device is properly calibrated for BLE, NAN and UWB based on Presence requirements.
         \nAll tests are required to pass on every device, if the radio technology is supported
     </string>
+    <string name="presence_test_tv_info">
+        The Presence tests check whether or not a device is properly calibrated for BLE, NAN and UWB based on Presence requirements.
+        \nAll tests are required to pass on all Android T+ launched TV devices, if the radio technology is supported.
+        \nIf the TV device is launched on older Android letters, all tests will be disabled. Press Pass to pass this case.
+    </string>
     <string name="uwb_precision">Uwb Precision Test</string>
     <string name="uwb_short_range">Uwb Short Range Test</string>
     <string name="uwb_precision_instruction">
@@ -6651,22 +6656,28 @@
         \n3. Report the median (500th value); must be within [-57, -63] dBm to pass
         \n4. Report the reference device used
     </string>
-    <string name="nan_precision_and_bias_instruction">
-        1. Take 1000 ranging measurements at each of the ground truth points of 1m, 3m, and 5m. The Wifinanscan in Play Store is recommended for data collection.
-        \n2. For each point:
-        \n\t\ta. Compute and report the range (Range = 975th measurement - 25th measurement).
-        \n\t\tb. Range must be less than 2m for test to pass.
-        \n3. Using the same measurements collected in step 1, compute a least squares regression line.
-        \n4. Report the bias and slope.
-        \n5. Bias must be 0+/- 0.25m and slope must be 1+/- 0.05m for tests to pass.
-        \n6. Report reference device used. All fields must be filled before test can be passed.
+    <string name="nan_precision_instruction">
+        1. Take 1000 ranging measurements at each of the ground truth points of 10cm, 1m, 3m, and 5m. The WifiNanScan app in Play Store is recommended for data collection.
+        \n2. Report the bandwidth at which the data was collected. Must be either 160, 80, 40, 20 MHz.
+        \n2. For each ground truth point:
+        \n\t\ta. Must report the range at the 68th percentile (as calculated with the Cumulative Distribution Function), accurately to within:
+        \n\t\t\ti. +/-1 meters at 160 MHz bandwidth
+        \n\t\t\tii. +/-2 meters at 80 MHz bandwidth
+        \n\t\t\tiii. +/-4 meters at 40 MHz bandwidth
+        \n\t\t\tiv. +/-8 meters at 20 MHz bandwidth
+        \n4. Following the same instructions above, it is strongly recommended (but not required), to report the range at the 90th percentile as calculated with the Cumulative Distribution Function. If the range at 90th percentile is inputted, it must be within the expected range, and inputted for all distance ranges.
+        \n5. Report reference device used. All required fields must be filled before test can be passed.
     </string>
-    <string name="report_distance_range_1m_gt">Report Measurement Range at 1m</string>
-    <string name="report_distance_range_3m_gt">Report Measurement Range at 3m</string>
-    <string name="report_distance_range_5m_gt">Report Measurement Range at 5m</string>
-    <string name="report_bias_meters">Report Bias (meters)</string>
-    <string name="report_slope">Report Slope</string>
-    <string name="nan_precision_and_bias">Nan Precision and Bias Test</string>
+    <string name="report_nan_bandwidth_mhz">Bandwidth (MHz)</string>
+    <string name="report_distance_range_10cm_gt_68p">Measurement Range at 10cm (68th percentile)</string>
+    <string name="report_distance_range_1m_gt_68p">Measurement Range at 1m (68th percentile)</string>
+    <string name="report_distance_range_3m_gt_68p">Measurement Range at 3m (68th percentile)</string>
+    <string name="report_distance_range_5m_gt_68p">Measurement Range at 5m (68th percentile)</string>
+    <string name="report_distance_range_10cm_gt_90p">Measurement Range at 10cm (90th percentile)</string>
+    <string name="report_distance_range_1m_gt_90p">Measurement Range at 1m (90th percentile)</string>
+    <string name="report_distance_range_3m_gt_90p">Measurement Range at 3m (90th percentile)</string>
+    <string name="report_distance_range_5m_gt_90p">Measurement Range at 5m (90th percentile)</string>
+    <string name="nan_precision">Nan Precision Test</string>
     <string name="wifi_nan">WiFi NAN</string>
 
     <!-- Strings for AudioMicrophoneMuteToggleActivity -->
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/Utils.java b/apps/CtsVerifier/src/com/android/cts/verifier/Utils.java
new file mode 100644
index 0000000..b6071d8
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/Utils.java
@@ -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 com.android.cts.verifier;
+
+import android.content.ComponentName;
+
+/**
+ * Provides common helper methods.
+ */
+public final class Utils {
+
+    /**
+     * Helper to get {@link #flattenToShortString()} in a {@link ComponentName} reference that can
+     * be {@code null}.
+     *
+     * @hide
+     */
+    public static String flattenToShortString(ComponentName componentName) {
+        return componentName == null ? null : componentName.flattenToShortString();
+    }
+
+    private Utils() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java
index a6709e7..9a5f314 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java
@@ -81,6 +81,17 @@
         mInfoView.setText(mContext.getResources().getString(
                 R.string.audio_devices_notification_instructions));
 
+        findViewById(R.id.audio_dev_notification_connect_clearmsgs_btn)
+                .setOnClickListener(new View.OnClickListener() {
+                    public void onClick(View v) {
+                        mConnectView.setText("");
+                        mConnectReceived = false;
+                        mDisconnectView.setText("");
+                        mDisconnectReceived = false;
+                        calculatePass();
+                    }
+                });
+
         AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
         audioManager.registerAudioDeviceCallback(new TestAudioDeviceCallback(), null);
 
@@ -90,6 +101,8 @@
         setInfoResources(R.string.audio_in_devices_notifications_test,
                 R.string.audio_in_devices_infotext, -1);
         setPassFailButtonClickListeners();
+
+        calculatePass();
     }
 
     @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
index 7399f33..38d99b4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
@@ -129,6 +129,7 @@
             AudioDeviceInfo routedDevice = audioRecord.getRoutedDevice();
             CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
             mConnectedPeripheralName = deviceName.toString();
+
             int deviceType = routedDevice != null ? routedDevice.getType() : -1;
             textView.setText(msg + " - " +
                              deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
@@ -156,8 +157,6 @@
                     R.id.audio_routingnotification_testresult)).setText(
                             "Test PASSES - No peripheral support");
         }
-
-        stopRecording();
     }
 
     protected void storeTestResults() {
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 77744fb..a6bd4ad 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
@@ -111,9 +111,7 @@
     protected static final int NUM_TEST_PHASES = 5;
     protected int mTestPhase = 0;
 
-    // There is more distortion/variance with the Speaker/Mic path, so lower confidence is needed
-    private static final double CONFIDENCE_THRESHOLD_AMBIENT = 0.2;
-    // A cleaner signal for wired or USB loopback, so higher confidence is possible
+    private static final double CONFIDENCE_THRESHOLD_AMBIENT = 0.6;
     private static final double CONFIDENCE_THRESHOLD_WIRED = 0.6;
 
     public static final double LATENCY_NOT_MEASURED = 0.0;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java
index c0f98d1..5fb51c4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java
@@ -81,6 +81,17 @@
         mInfoView.setText(mContext.getResources().getString(
                 R.string.audio_devices_notification_instructions));
 
+        findViewById(R.id.audio_dev_notification_connect_clearmsgs_btn)
+                .setOnClickListener(new View.OnClickListener() {
+                    public void onClick(View v) {
+                        mConnectView.setText("");
+                        mConnectReceived = false;
+                        mDisconnectView.setText("");
+                        mDisconnectReceived = false;
+                        calculatePass();
+                    }
+                });
+
         AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
         audioManager.registerAudioDeviceCallback(new TestAudioDeviceCallback(), null);
 
@@ -90,6 +101,8 @@
         setInfoResources(R.string.audio_out_devices_notifications_test,
                 R.string.audio_out_devices_infotext, -1);
         setPassFailButtonClickListeners();
+
+        calculatePass();
     }
 
     @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
index e23ee17..591fe9b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
@@ -160,8 +160,6 @@
                     R.id.audio_routingnotification_testresult)).setText(
                     "Test PASSES - No peripheral support");
         }
-
-        stopPlayback();
     }
 
     protected void storeTestResults() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioWiredDeviceBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioWiredDeviceBaseActivity.java
index 8348393..97813af 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioWiredDeviceBaseActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioWiredDeviceBaseActivity.java
@@ -35,7 +35,7 @@
     private Button mSupportsBtn;
     private Button mDoesntSupportBtn;
 
-    protected boolean mSupportsWiredPeripheral;
+    protected boolean mSupportsWiredPeripheral = true;
     protected String mConnectedPeripheralName;
 
     protected abstract void enableTestButtons(boolean enabled);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
index 7411575..803c385 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
@@ -125,7 +125,7 @@
 
                         try {
                             startAdvertisingSet();
-                            testDisableAndEnableAdvertising();
+                            testEnableAndDisableAdvertising();
                             testSetAdvertisingData();
                             testSetAdvertisingParameters();
                             testPeriodicAdvertising();
@@ -180,18 +180,19 @@
         mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_START);
     }
 
-    private void testDisableAndEnableAdvertising() throws InterruptedException {
+    private void testEnableAndDisableAdvertising() throws InterruptedException {
         mCallback.reset();
 
-        mCallback.mAdvertisingSet.get().enableAdvertising(/* enable= */ false, /* duration= */ 1,
-                /* maxExtendedAdvertisingEvents= */ 1);
+        mCallback.mAdvertisingSet.get().enableAdvertising(/* enable= */ true, /* duration= */ 0,
+                /* maxExtendedAdvertisingEvents= */ 0);
+        assertTrue(mCallback.mAdvertisingEnabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingEnabledStatus.get());
+
+        mCallback.mAdvertisingSet.get().enableAdvertising(/* enable= */ false, /* duration= */ 0,
+                /* maxExtendedAdvertisingEvents= */ 0);
         assertTrue(mCallback.mAdvertisingDisabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingDisabledStatus.get());
 
-        mCallback.mAdvertisingSet.get().enableAdvertising(/* enable= */ true, /* duration= */ 1,
-                /* maxExtendedAdvertisingEvents= */ 1);
-        assertTrue(mCallback.mAdvertisingEnabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingEnabledStatus.get());
 
         mAllTestsPassed |= PASS_FLAG_ENABLE_DISABLE;
         mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_ENABLE_DISABLE);
@@ -222,8 +223,8 @@
     private void testSetAdvertisingParameters() throws InterruptedException {
         mCallback.reset();
 
-        mCallback.mAdvertisingSet.get().enableAdvertising(false, /* duration= */ 1,
-                /* maxExtendedAdvertisingEvents= */ 1);
+        mCallback.mAdvertisingSet.get().enableAdvertising(false, /* duration= */ 0,
+                /* maxExtendedAdvertisingEvents= */ 0);
         assertTrue(mCallback.mAdvertisingDisabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingDisabledStatus.get());
 
@@ -247,15 +248,11 @@
 
         mCallback.mAdvertisingSet.get().setAdvertisingParameters(
                 new AdvertisingSetParameters.Builder().build());
+
         assertTrue(mCallback.mAdvertisingParametersUpdatedLatch.await(TIMEOUT_MS,
                 TimeUnit.MILLISECONDS));
         assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingParametersUpdatedStatus.get());
 
-        // Let's make sure we disable periodic advertising
-        mCallback.mAdvertisingSet.get().setPeriodicAdvertisingEnabled(false);
-        assertTrue(mCallback.mPeriodicAdvertisingDisabledLatch.await(TIMEOUT_MS,
-                TimeUnit.MILLISECONDS));
-        assertEquals(ADVERTISE_SUCCESS, mCallback.mPeriodicAdvertisingDisabledStatus.get());
         mCallback.mAdvertisingSet.get().setPeriodicAdvertisingParameters(
                 new PeriodicAdvertisingParameters.Builder().build());
         assertTrue(mCallback.mPeriodicAdvertisingParamsUpdatedLatch.await(TIMEOUT_MS,
@@ -265,6 +262,13 @@
         mAllTestsPassed |= PASS_FLAG_SET_PERIODIC_ADVERTISING_PARAMS;
         mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_PARAMS);
 
+        // Enable advertising before periodicAdvertising
+        // If the advertising set is not currently enabled (see the
+        // HCI_LE_Set_Extended_Advertising_Enable command), the periodic
+        // advertising is not started until the advertising set is enabled.
+        mCallback.mAdvertisingSet.get().enableAdvertising(true, /* duration= */ 0,
+                /* maxExtendedAdvertisingEvents= */ 0);
+
         mCallback.mAdvertisingSet.get().setPeriodicAdvertisingEnabled(true);
         assertTrue(mCallback.mPeriodicAdvertisingEnabledLatch.await(TIMEOUT_MS,
                 TimeUnit.MILLISECONDS));
@@ -280,6 +284,9 @@
         mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_DATA);
 
         mCallback.mAdvertisingSet.get().setPeriodicAdvertisingEnabled(false);
+        // Disable advertising after periodicAdvertising
+        mCallback.mAdvertisingSet.get().enableAdvertising(false, /* duration= */ 0,
+                /* maxExtendedAdvertisingEvents= */ 0);
         assertTrue(mCallback.mPeriodicAdvertisingDisabledLatch.await(TIMEOUT_MS,
                 TimeUnit.MILLISECONDS));
         assertEquals(ADVERTISE_SUCCESS, mCallback.mPeriodicAdvertisingDisabledStatus.get());
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
index 406a305..e27ae0a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
@@ -23,6 +23,7 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.graphics.Color;
+import android.graphics.Matrix;
 import android.graphics.SurfaceTexture;
 import android.hardware.Camera;
 import android.hardware.Camera.PictureCallback;
@@ -183,8 +184,9 @@
                     SelectableResolution resolution = mSupportedResolutions.get(position);
                     switchToCamera(resolution, false);
 
-                    // It should be guaranteed that the FOV is correctly updated after setParameters().
-                    mReportedFovPrePictureTaken = mCamera.getParameters().getHorizontalViewAngle();
+                    // It should be guaranteed that the FOV is correctly updated after
+                    // setParameters().
+                    mReportedFovPrePictureTaken = getCameraFov(resolution.cameraId);
 
                     mResolutionSpinnerIndex = position;
                     startPreview();
@@ -271,8 +273,8 @@
     @Override
     public void onPictureTaken(byte[] data, Camera camera) {
         File pictureFile = getPictureFile(this);
-        Camera.Parameters params = mCamera.getParameters();
-        mReportedFovDegrees = params.getHorizontalViewAngle();
+
+        mReportedFovDegrees = getCameraFov(mSelectedResolution.cameraId);
 
         // Show error if FOV does not match the value reported before takePicture().
         if (mReportedFovPrePictureTaken != mReportedFovDegrees) {
@@ -436,6 +438,36 @@
         initializeCamera(true);
     }
 
+    private void setPreviewTransform(Size previewSize) {
+        int sensorRotation = mPreviewOrientation;
+        float selectedPreviewAspectRatio;
+        if (sensorRotation == 0 || sensorRotation == 180) {
+            selectedPreviewAspectRatio = (float) previewSize.width
+                / (float) previewSize.height;
+        } else {
+            selectedPreviewAspectRatio = (float) previewSize.height
+                / (float) previewSize.width;
+        }
+
+        Matrix transform = new Matrix();
+        float viewAspectRatio = (float) mPreviewView.getMeasuredWidth()
+                / (float) mPreviewView.getMeasuredHeight();
+        float scaleX = 1.0f, scaleY = 1.0f;
+        float translateX = 0, translateY = 0;
+        if (selectedPreviewAspectRatio > viewAspectRatio) {
+            scaleY = viewAspectRatio / selectedPreviewAspectRatio;
+            translateY = (float) mPreviewView.getMeasuredHeight() / 2
+                    - (float) mPreviewView.getMeasuredHeight() * scaleY / 2;
+        } else {
+            scaleX = selectedPreviewAspectRatio / viewAspectRatio;
+            translateX = (float) mPreviewView.getMeasuredWidth() / 2
+                    - (float) mPreviewView.getMeasuredWidth() * scaleX / 2;
+        }
+        transform.postScale(scaleX, scaleY);
+        transform.postTranslate(translateX, translateY);
+        mPreviewView.setTransform(transform);
+    }
+
     private void initializeCamera(boolean startPreviewAfterInit) {
         if (mCamera == null || mPreviewTexture == null) {
             return;
@@ -470,6 +502,7 @@
         if (selectedPreviewSize != null) {
             params.setPreviewSize(selectedPreviewSize.width, selectedPreviewSize.height);
             mCamera.setParameters(params);
+            setPreviewTransform(selectedPreviewSize);
             mCameraInitialized = true;
         }
 
@@ -561,21 +594,25 @@
         return result;
     }
 
+    private int getDisplayRotation() {
+        int displayRotation = getDisplay().getRotation();
+        int displayRotationDegrees = 0;
+        switch (displayRotation) {
+            case Surface.ROTATION_0: displayRotationDegrees = 0; break;
+            case Surface.ROTATION_90: displayRotationDegrees = 90; break;
+            case Surface.ROTATION_180: displayRotationDegrees = 180; break;
+            case Surface.ROTATION_270: displayRotationDegrees = 270; break;
+        }
+        return displayRotationDegrees;
+    }
+
     private void calculateOrientations(Activity activity,
             int cameraId, android.hardware.Camera camera) {
         android.hardware.Camera.CameraInfo info =
                 new android.hardware.Camera.CameraInfo();
         android.hardware.Camera.getCameraInfo(cameraId, info);
-        int rotation = activity.getWindowManager().getDefaultDisplay()
-                .getRotation();
-        int degrees = 0;
-        switch (rotation) {
-            case Surface.ROTATION_0: degrees = 0; break;
-            case Surface.ROTATION_90: degrees = 90; break;
-            case Surface.ROTATION_180: degrees = 180; break;
-            case Surface.ROTATION_270: degrees = 270; break;
-        }
 
+        int degrees = getDisplayRotation();
         if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
             mJpegOrientation = (info.orientation + degrees) % 360;
             mPreviewOrientation = (360 - mJpegOrientation) % 360;  // compensate the mirror
@@ -603,4 +640,12 @@
         }
         return false;
     }
+
+    private float getCameraFov(int cameraId) {
+        if (mPreviewOrientation == 0 || mPreviewOrientation == 180) {
+            return mCamera.getParameters().getHorizontalViewAngle();
+        } else {
+            return mCamera.getParameters().getVerticalViewAngle();
+        }
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 5706610..ef66b53 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -20,6 +20,8 @@
 import static android.app.admin.DevicePolicyManager.MAKE_USER_EPHEMERAL;
 import static android.app.admin.DevicePolicyManager.SKIP_SETUP_WIZARD;
 
+import static com.android.cts.verifier.Utils.flattenToShortString;
+
 import android.Manifest;
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -262,9 +264,9 @@
                 } break;
                 case COMMAND_SET_STATUSBAR_DISABLED: {
                     boolean enforced = intent.getBooleanExtra(EXTRA_ENFORCED, false);
-                    Log.d(TAG, "calling setStatusBarDisabled("
-                            + ComponentName.flattenToShortString(mAdmin) + ", " + enforced
-                            + ") using " + mDpm + " on user " + UserHandle.myUserId());
+                    Log.d(TAG, "calling setStatusBarDisabled(" + flattenToShortString(mAdmin)
+                            + ", " + enforced + ") using " + mDpm + " on user "
+                            + UserHandle.myUserId());
                     mDpm.setStatusBarDisabled(mAdmin, enforced);
                 } break;
                 case COMMAND_SET_LOCK_TASK_FEATURES: {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionAndBiasTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionAndBiasTestActivity.java
deleted file mode 100644
index 57b652b..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionAndBiasTestActivity.java
+++ /dev/null
@@ -1,197 +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 java.util.Arrays;
-import java.util.List;
-
-/**
- * Activity for testing that NAN measurements are within the acceptable range and fits a trend line
- * that has a bias and slope within the expected range
- * range.
- */
-public class NanPrecisionAndBiasTestActivity extends PassFailButtons.Activity {
-    private static final String TAG = NanPrecisionAndBiasTestActivity.class.getName();
-
-    // Report log schema
-    private static final String KEY_MEASUREMENT_RANGE_1M = "measurement_range_1m";
-    private static final String KEY_MEASUREMENT_RANGE_3M = "measurement_range_3m";
-    private static final String KEY_MEASUREMENT_RANGE_5M = "measurement_range_5m";
-    private static final String KEY_BIAS_METERS = "bias_meters";
-    private static final String KEY_SLOPE_METERS = "slope_meters";
-    private static final String KEY_REFERENCE_DEVICE = "reference_device";
-
-    // Thresholds
-    private static final int MAX_DISTANCE_RANGE_METERS = 2;
-    private static final double MIN_BIAS_METERS = -0.25;
-    private static final double MAX_BIAS_METERS = 0.25;
-    private static final double MIN_SLOPE = 0.95;
-    private static final double MAX_SLOPE = 1.05;
-
-    private EditText mMeasurementRange1mGt;
-    private EditText mMeasurementRange3mGt;
-    private EditText mMeasurementRange5mGt;
-    private EditText mBiasInput;
-    private EditText mSlopeInput;
-    private EditText mReferenceDeviceInput;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.nan_precision_and_bias);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        mMeasurementRange1mGt = (EditText) findViewById(R.id.distance_range_1m_gt);
-        mMeasurementRange3mGt = (EditText) findViewById(R.id.distance_range_3m_gt);
-        mMeasurementRange5mGt = (EditText) findViewById(R.id.distance_range_5m_gt);
-        mBiasInput = (EditText) findViewById(R.id.bias_meters);
-        mSlopeInput = (EditText) findViewById(R.id.slope);
-        mReferenceDeviceInput = (EditText) findViewById(R.id.reference_device);
-
-        DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
-                PackageManager.FEATURE_WIFI_AWARE);
-
-        mMeasurementRange1mGt.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange3mGt.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange5mGt.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mBiasInput.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mSlopeInput.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mReferenceDeviceInput.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-    }
-
-    private void checkTestInputs() {
-        getPassButton().setEnabled(checkMeasurementRangeInput()
-                && checkBiasInput() && checkSlopeInput()
-                && checkReferenceDeviceInput());
-    }
-
-    private boolean checkMeasurementRangeInput() {
-        String measurementRangeInput1mGt = mMeasurementRange1mGt.getText().toString();
-        String measurementRangeInput3mGt = mMeasurementRange3mGt.getText().toString();
-        String measurementRangeInput5mGt = mMeasurementRange1mGt.getText().toString();
-        List<String> measurementRangeList = Arrays.asList(measurementRangeInput1mGt,
-                measurementRangeInput3mGt, measurementRangeInput5mGt);
-
-        for (String input : measurementRangeList) {
-            if (input.isEmpty()) {
-                // Distance range must be inputted for all fields so fail early otherwise
-                return false;
-            }
-            int distanceRange = Integer.parseInt(input);
-            if (distanceRange > MAX_DISTANCE_RANGE_METERS) {
-                // All inputs must be in acceptable range so fail early otherwise
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private boolean checkBiasInput() {
-        String biasInput = mBiasInput.getText().toString();
-
-        if (!biasInput.isEmpty()) {
-            double bias = Double.parseDouble(biasInput);
-            // Bias must be inputted and within acceptable range before test can be passed.
-            return bias >= MIN_BIAS_METERS && bias <= MAX_BIAS_METERS;
-        }
-        return false;
-    }
-
-    private boolean checkSlopeInput() {
-        String slopeInput = mSlopeInput.getText().toString();
-
-        if (!slopeInput.isEmpty()) {
-            double slope = Double.parseDouble(slopeInput);
-            // Slope must be inputted and within acceptable range before test can be passed.
-            return slope >= MIN_SLOPE && slope <= MAX_SLOPE;
-        }
-        return false;
-    }
-
-    private boolean checkReferenceDeviceInput() {
-        // Reference device used must be inputted before test can be passed.
-        return !mReferenceDeviceInput.getText().toString().isEmpty();
-    }
-
-    @Override
-    public void recordTestResults() {
-        String measurementRange1mGt = mMeasurementRange1mGt.getText().toString();
-        String measurementRange3mGt = mMeasurementRange3mGt.getText().toString();
-        String measurementRange5mGt = mMeasurementRange5mGt.getText().toString();
-        String bias = mBiasInput.getText().toString();
-        String slope = mSlopeInput.getText().toString();
-        String referenceDevice = mReferenceDeviceInput.getText().toString();
-
-        if (!measurementRange1mGt.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 1m: " + measurementRange1mGt);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_1M,
-                    Integer.parseInt(measurementRange1mGt),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange3mGt.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 3m: " + measurementRange3mGt);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_3M,
-                    Integer.parseInt(measurementRange1mGt),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange5mGt.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 5m: " + measurementRange5mGt);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_5M,
-                    Integer.parseInt(measurementRange1mGt),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!bias.isEmpty()) {
-            Log.i(TAG, "NAN bias: " + bias);
-            getReportLog().addValue(KEY_BIAS_METERS, Double.parseDouble(bias),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!slope.isEmpty()) {
-            Log.i(TAG, "NAN slope: " + slope);
-            getReportLog().addValue(KEY_SLOPE_METERS, Double.parseDouble(slope),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!referenceDevice.isEmpty()) {
-            Log.i(TAG, "NAN Reference Device: " + referenceDevice);
-            getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-        getReportLog().submit();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionTestActivity.java
new file mode 100644
index 0000000..0256431
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionTestActivity.java
@@ -0,0 +1,270 @@
+/*
+ * 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 = 1;
+    private static final int MAX_DISTANCE_RANGE_METERS_80MHZ = 2;
+    private static final int MAX_DISTANCE_RANGE_METERS_40MHZ = 4;
+    private static final int MAX_DISTANCE_RANGE_METERS_20MHZ = 8;
+
+    // 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);
+
+        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 = mMeasurementRange1mGt90p.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;
+            }
+            int distanceRange = Integer.parseInt(input);
+            int bandwidth = Integer.parseInt(bandwidthInputMhz);
+            if (distanceRange < -BANDWIDTH_TO_THRESHOLD_MAP.get(bandwidth)
+                    || 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,
+                    Integer.parseInt(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,
+                    Integer.parseInt(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,
+                    Integer.parseInt(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,
+                    Integer.parseInt(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,
+                    Integer.parseInt(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,
+                    Integer.parseInt(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,
+                    Integer.parseInt(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,
+                    Integer.parseInt(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/PresenceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/PresenceTestActivity.java
index e8a0ccc..6776693 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/PresenceTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/presence/PresenceTestActivity.java
@@ -16,12 +16,18 @@
 
 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
@@ -29,8 +35,26 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.pass_fail_list);
         setPassFailButtonClickListeners();
-        setInfoResources(R.string.presence_test, R.string.presence_test_info, -1);
-        setTestListAdapter(
-                new ManifestTestListAdapter(this, PresenceTestActivity.class.getName()));
+
+        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/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 961dc1b..1acf65c 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
@@ -288,8 +288,6 @@
     }
 
     private void executeTest(Statement base, Description description) throws Throwable {
-        PermissionContextImpl permissionContext = null;
-
         String testName = description.getMethodName();
 
         try {
@@ -306,18 +304,13 @@
 
             mMinSdkVersionCurrentTest = mMinSdkVersion;
             List<Annotation> annotations = getAnnotations(description);
-            permissionContext = applyAnnotations(annotations, /* isTest= */ true);
+            applyAnnotations(annotations, /* isTest= */ true);
 
             Log.d(LOG_TAG, "Finished preparing state for test " + testName);
 
             base.evaluate();
         } finally {
             Log.d(LOG_TAG, "Tearing down state for test " + testName);
-
-            if (permissionContext != null) {
-                permissionContext.close();
-            }
-
             teardownNonShareableState();
             if (!mSkipTestTeardown) {
                 teardownShareableState();
@@ -326,9 +319,8 @@
         }
     }
 
-    private PermissionContextImpl applyAnnotations(List<Annotation> annotations, boolean isTest)
+    private void applyAnnotations(List<Annotation> annotations, boolean isTest)
             throws Throwable {
-        PermissionContextImpl permissionContext = null;
         Log.i(LOG_TAG, "Applying annotations: " + annotations);
         for (Annotation annotation : annotations) {
             Log.i(LOG_TAG, "Applying annotation " + annotation);
@@ -685,13 +677,7 @@
                 }
 
                 try {
-                    if (permissionContext == null) {
-                        permissionContext = TestApis.permissions().withAppOp(
-                                ensureHasAppOpAnnotation.value());
-                    } else {
-                        permissionContext = permissionContext.withAppOp(
-                                ensureHasAppOpAnnotation.value());
-                    }
+                    withAppOp(ensureHasAppOpAnnotation.value());
                 } catch (NeneException e) {
                     failOrSkip("Error getting appOp: " + e,
                             ensureHasAppOpAnnotation.failureMode());
@@ -704,13 +690,7 @@
                         (EnsureDoesNotHaveAppOp) annotation;
 
                 try {
-                    if (permissionContext == null) {
-                        permissionContext = TestApis.permissions().withoutAppOp(
-                                ensureDoesNotHaveAppOpAnnotation.value());
-                    } else {
-                        permissionContext = permissionContext.withoutAppOp(
-                                ensureDoesNotHaveAppOpAnnotation.value());
-                    }
+                    withoutAppOp(ensureDoesNotHaveAppOpAnnotation.value());
                 } catch (NeneException e) {
                     failOrSkip("Error denying appOp: " + e,
                             ensureDoesNotHaveAppOpAnnotation.failureMode());
@@ -736,13 +716,7 @@
                 }
 
                 try {
-                    if (permissionContext == null) {
-                        permissionContext = TestApis.permissions().withPermission(
-                                ensureHasPermissionAnnotation.value());
-                    } else {
-                        permissionContext = permissionContext.withPermission(
-                                ensureHasPermissionAnnotation.value());
-                    }
+                    withPermission(ensureHasPermissionAnnotation.value());
                 } catch (NeneException e) {
                     failOrSkip("Error getting permission: " + e,
                             ensureHasPermissionAnnotation.failureMode());
@@ -755,13 +729,7 @@
                         (EnsureDoesNotHavePermission) annotation;
 
                 try {
-                    if (permissionContext == null) {
-                        permissionContext = TestApis.permissions().withoutPermission(
-                                ensureDoesNotHavePermission.value());
-                    } else {
-                        permissionContext = permissionContext.withoutPermission(
-                                ensureDoesNotHavePermission.value());
-                    }
+                    withoutPermission(ensureDoesNotHavePermission.value());
                 } catch (NeneException e) {
                     failOrSkip("Error denying permission: " + e,
                             ensureDoesNotHavePermission.failureMode());
@@ -819,8 +787,6 @@
                 && !mHasRequirePermissionInstrumentation) {
             requireNoPermissionsInstrumentation("No reason to use instrumentation");
         }
-
-        return permissionContext;
     }
 
     private List<Annotation> getAnnotations(Description description) {
@@ -889,13 +855,16 @@
 
                 try {
                     TestApis.device().keepScreenOn(true);
-                    TestApis.device().setKeyguardEnabled(false);
+
+                    if (!Tags.hasTag(Tags.INSTANT_APP)) {
+                        TestApis.device().setKeyguardEnabled(false);
+                    }
                     TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_FALSE);
 
                     try {
                         List<Annotation> annotations =
                                 new ArrayList<>(getAnnotations(description));
-                        permissionContext = applyAnnotations(annotations, /* isTest= */ false);
+                        applyAnnotations(annotations, /* isTest= */ false);
                     } catch (AssumptionViolatedException e) {
                         Log.i(LOG_TAG, "Assumption failed during class setup", e);
                         mSkipTests = true;
@@ -927,7 +896,9 @@
                         teardownShareableState();
                     }
 
-                    TestApis.device().setKeyguardEnabled(true);
+                    if (!Tags.hasTag(Tags.INSTANT_APP)) {
+                        TestApis.device().setKeyguardEnabled(true);
+                    }
                     TestApis.device().keepScreenOn(false);
                     TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_DEFAULT);
                 }
@@ -1169,6 +1140,7 @@
     private RemotePolicyManager mPrimaryPolicyManager;
     private UserType mOtherUserType;
 
+    private PermissionContextImpl mPermissionContext = null;
     private final List<UserReference> mCreatedUsers = new ArrayList<>();
     private final List<UserBuilder> mRemovedUsers = new ArrayList<>();
     private final List<UserReference> mUsersSetPasswords = new ArrayList<>();
@@ -1669,6 +1641,10 @@
         mTestApps.clear();
 
         mTestAppProvider.restore();
+        if (mPermissionContext != null) {
+            mPermissionContext.close();
+            mPermissionContext = null;
+        }
     }
 
     private Set<TestAppInstance> mInstalledTestApps = new HashSet<>();
@@ -1738,7 +1714,6 @@
         }
 
         mCreatedUsers.clear();
-
         for (UserBuilder userBuilder : mRemovedUsers) {
             userBuilder.create();
         }
@@ -2471,4 +2446,36 @@
         }
         TestApis.bluetooth().setEnabled(false);
     }
+
+    private void withAppOp(String... appOp) {
+        if (mPermissionContext == null) {
+            mPermissionContext = TestApis.permissions().withAppOp(appOp);
+        } else {
+            mPermissionContext = mPermissionContext.withAppOp(appOp);
+        }
+    }
+
+    private void withoutAppOp(String... appOp) {
+        if (mPermissionContext == null) {
+            mPermissionContext = TestApis.permissions().withoutAppOp(appOp);
+        } else {
+            mPermissionContext = mPermissionContext.withoutAppOp(appOp);
+        }
+    }
+
+    private void withPermission(String... permission) {
+        if (mPermissionContext == null) {
+            mPermissionContext = TestApis.permissions().withPermission(permission);
+        } else {
+            mPermissionContext = mPermissionContext.withPermission(permission);
+        }
+    }
+
+    private void withoutPermission(String... permission) {
+        if (mPermissionContext == null) {
+            mPermissionContext = TestApis.permissions().withoutPermission(permission);
+        } else {
+            mPermissionContext = mPermissionContext.withoutPermission(permission);
+        }
+    }
 }
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/device/Device.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/device/Device.java
index d80ea2c..c36237c 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/device/Device.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/device/Device.java
@@ -36,14 +36,35 @@
     public static final Device sInstance = new Device();
     private static final UiDevice sDevice =
             UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-    private static final KeyguardManager.KeyguardLock sKeyguardLock =
-            TestApis.context().instrumentedContext().getSystemService(KeyguardManager.class)
-                    .newKeyguardLock("Nene");
+    private static final KeyguardManager sKeyguardManager =
+            TestApis.context().instrumentedContext()
+            .getSystemService(KeyguardManager.class);
+    private static KeyguardManager.KeyguardLock sKeyguardLock;
 
     private Device() {
 
     }
 
+    private KeyguardManager.KeyguardLock keyGuardLock() {
+        if (sKeyguardManager == null) {
+            if (TestApis.packages().instrumented().isInstantApp()) {
+                throw new NeneException("Cannot manage keyguard with instant app");
+            }
+
+            throw new NeneException("KeyguardManager cannot be found.");
+        }
+
+        if (sKeyguardLock == null) {
+            synchronized (Device.class) {
+                if (sKeyguardLock == null) {
+                    sKeyguardLock = sKeyguardManager.newKeyguardLock("Nene");
+                }
+            }
+        }
+
+        return sKeyguardLock;
+    }
+
     /**
      * Turn the screen on.
      */
@@ -91,9 +112,9 @@
     public void setKeyguardEnabled(boolean keyguardEnabled) {
         try (PermissionContext p = TestApis.permissions().withPermission(DISABLE_KEYGUARD)) {
             if (keyguardEnabled) {
-                sKeyguardLock.reenableKeyguard();
+                keyGuardLock().reenableKeyguard();
             } else {
-                sKeyguardLock.disableKeyguard();
+                keyGuardLock().disableKeyguard();
             }
         }
     }
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/InputDeviceInfo.kt b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/InputDeviceInfo.kt
index 2d109ba..a3e391d 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/InputDeviceInfo.kt
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/InputDeviceInfo.kt
@@ -16,9 +16,7 @@
 package com.android.compatibility.common.deviceinfo
 
 import android.content.Context
-
 import androidx.test.core.app.ApplicationProvider
-
 import com.android.compatibility.common.util.DeviceConfigStateManager
 import com.android.compatibility.common.util.DeviceInfoStore
 
@@ -35,10 +33,11 @@
         collectInputInfo(store, "input")
     }
 
-    private fun readDeviceConfig(namespace: String, name: String): String {
+    private fun readDeviceConfig(namespace: String, name: String, default: String): String {
         val context: Context = ApplicationProvider.getApplicationContext()
         val stateManager = DeviceConfigStateManager(context, namespace, name)
-        return stateManager.get()!!
+        val value = stateManager.get()
+        return if (value != null) value else default
     }
 
     /**
@@ -47,10 +46,15 @@
     private fun collectInputInfo(store: DeviceInfoStore, groupName: String) {
         store.startGroup(groupName)
 
-        val palmRejectionValue = readDeviceConfig("input_native_boot", "palm_rejection_enabled")
+        val palmRejectionValue = readDeviceConfig("input_native_boot", "palm_rejection_enabled", "")
         val palmRejectionEnabled = palmRejectionValue == "1" || palmRejectionValue == "true"
         store.addResult("palm_rejection_enabled", palmRejectionEnabled)
 
+        val velocityTrackerStrategyValue = readDeviceConfig(
+            "input_native_boot", "velocitytracker_strategy", "default"
+        )
+        store.addResult("velocitytracker_strategy", velocityTrackerStrategyValue)
+
         store.endGroup()
     }
 }
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 4904323..1993f30 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -706,6 +706,16 @@
                 "Lcom/android/internal/util/StateMachine;",
                 "Lcom/android/internal/util/State;"
             );
+
+    // TODO: b/234557765
+    private static final ImmutableSet<String> ADSERVICES_SANDBOX_APK_IN_APEX_BURNDOWN_LIST =
+            ImmutableSet.of(
+                // /apex/com.android.adservices/javalib/service-sdksandbox.jar
+                "Lcom/android/sdksandbox/ISdkSandboxManagerToSdkSandboxCallback;",
+                "Lcom/android/sdksandbox/ISdkSandboxService;",
+                "Lcom/android/sdksandbox/ISdkSandboxToSdkSandboxManagerCallback;"
+            );
+
     private static final ImmutableMap<String, ImmutableSet<String>> FULL_APK_IN_APEX_BURNDOWN =
         new ImmutableMap.Builder<String, ImmutableSet<String>>()
             .put("/apex/com.android.bluetooth/app/Bluetooth/Bluetooth.apk",
@@ -736,6 +746,10 @@
                 CELLBROADCAST_APK_IN_APEX_BURNDOWN_LIST)
             .put("/apex/com.android.cellbroadcast/priv-app/CellBroadcastServiceModule/CellBroadcastServiceModule.apk",
                 CELLBROADCAST_APK_IN_APEX_BURNDOWN_LIST)
+            .put("/apex/com.android.adservices/app/SdkSandbox/SdkSandbox.apk",
+                ADSERVICES_SANDBOX_APK_IN_APEX_BURNDOWN_LIST)
+            .put("/apex/com.android.adservices/app/SdkSandboxGoogle/SdkSandboxGoogle.apk",
+                ADSERVICES_SANDBOX_APK_IN_APEX_BURNDOWN_LIST)
             .build();
 
     /**
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/CtsSignatureQueryServiceTest_v2-tgt-33.apk b/hostsidetests/appsecurity/res/pkgsigverify/CtsSignatureQueryServiceTest_v2-tgt-33.apk
deleted file mode 100644
index 869f9a9..0000000
--- a/hostsidetests/appsecurity/res/pkgsigverify/CtsSignatureQueryServiceTest_v2-tgt-33.apk
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/CtsSignatureQueryService_v2-tgt-33.apk b/hostsidetests/appsecurity/res/pkgsigverify/CtsSignatureQueryService_v2-tgt-33.apk
index 69a5170..d5e7835 100644
--- a/hostsidetests/appsecurity/res/pkgsigverify/CtsSignatureQueryService_v2-tgt-33.apk
+++ b/hostsidetests/appsecurity/res/pkgsigverify/CtsSignatureQueryService_v2-tgt-33.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/CtsSignatureQueryService_v3-tgt-33.apk b/hostsidetests/appsecurity/res/pkgsigverify/CtsSignatureQueryService_v3-tgt-33.apk
deleted file mode 100644
index 2f03585..0000000
--- a/hostsidetests/appsecurity/res/pkgsigverify/CtsSignatureQueryService_v3-tgt-33.apk
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
index 6e64f03..3f353d0 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
@@ -777,12 +777,12 @@
         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
                 "verifySignatures_noRotation_succeeds");
 
-        assertInstallSucceeds("CtsSignatureQueryService_v2-tgt-33.apk");
+        assertInstallFromBuildSucceeds("CtsSignatureQueryService_v2-tgt-33.apk");
         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
                 "verifySignatures_withRotation_succeeds");
 
-        assertInstallSucceeds("CtsSignatureQueryService_v3-tgt-33.apk");
-        assertInstallSucceeds("CtsSignatureQueryServiceTest_v2-tgt-33.apk");
+        assertInstallFromBuildSucceeds("CtsSignatureQueryService_v3-tgt-33.apk");
+        assertInstallFromBuildSucceeds("CtsSignatureQueryServiceTest_v2-tgt-33.apk");
         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
                 "verifySignatures_withRotation_succeeds");
     }
@@ -800,12 +800,12 @@
         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
                 "verifySignatures_noRotation_succeeds");
 
-        assertInstallV4Succeeds("CtsSignatureQueryService_v2-tgt-33.apk");
+        assertInstallV4FromBuildSucceeds("CtsSignatureQueryService_v2-tgt-33.apk");
         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
                 "verifySignatures_withRotation_succeeds");
 
-        assertInstallV4Succeeds("CtsSignatureQueryService_v3-tgt-33.apk");
-        assertInstallV4Succeeds("CtsSignatureQueryServiceTest_v2-tgt-33.apk");
+        assertInstallV4FromBuildSucceeds("CtsSignatureQueryService_v3-tgt-33.apk");
+        assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest_v2-tgt-33.apk");
         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
                 "verifySignatures_withRotation_succeeds");
     }
diff --git a/hostsidetests/appsecurity/test-apps/KeyRotationTest/Android.bp b/hostsidetests/appsecurity/test-apps/KeyRotationTest/Android.bp
index ad62246..09eb4e9 100644
--- a/hostsidetests/appsecurity/test-apps/KeyRotationTest/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/KeyRotationTest/Android.bp
@@ -84,3 +84,49 @@
     lineage: ":ec-p256-por_1_2-default-caps",
     v4_signature: true,
 }
+
+// This is the second version of the test app signed with the rotated signing
+// key targeting SDK version 33 for rotation with an updated version number.
+// This app is intended to verify that an app continues to function as expected
+// after an update with a rotated key in the v3.1 block.
+android_test {
+    name: "CtsSignatureQueryService_v2-tgt-33",
+    defaults: ["cts_support_defaults"],
+    manifest: "AndroidManifest_v2.xml",
+    compile_multilib: "both",
+    min_sdk_version: "32",
+    sdk_version: "current",
+    static_libs: ["cts_signature_query_service"],
+    test_suites: [
+        "cts",
+        "general-tests",
+    ],
+    certificate: ":ec-p256_2",
+    additional_certificates: [":ec-p256"],
+    lineage: ":ec-p256-por_1_2-default-caps",
+    rotationMinSdkVersion: "33",
+    v4_signature: true,
+}
+
+// This is the third version of the test app signed with the same rotated
+// signing key as v2 and targeting SDK version 33 for rotation. This app
+// is intended to verify that an app can still be updated and function as
+// expected after the signing key has been rotated in the v3.1 block.
+android_test {
+    name: "CtsSignatureQueryService_v3-tgt-33",
+    defaults: ["cts_support_defaults"],
+    manifest: "AndroidManifest_v3.xml",
+    compile_multilib: "both",
+    min_sdk_version: "32",
+    sdk_version: "current",
+    static_libs: ["cts_signature_query_service"],
+    test_suites: [
+        "cts",
+        "general-tests",
+    ],
+    certificate: ":ec-p256_2",
+    additional_certificates: [":ec-p256"],
+    lineage: ":ec-p256-por_1_2-default-caps",
+    rotationMinSdkVersion: "33",
+    v4_signature: true,
+}
diff --git a/hostsidetests/appsecurity/test-apps/KeyRotationTest/ServiceTest/Android.bp b/hostsidetests/appsecurity/test-apps/KeyRotationTest/ServiceTest/Android.bp
index 74403bc..0b69677 100644
--- a/hostsidetests/appsecurity/test-apps/KeyRotationTest/ServiceTest/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/KeyRotationTest/ServiceTest/Android.bp
@@ -84,3 +84,39 @@
         enabled: false,
     },
 }
+
+// This is the instrumentation test package signed with the same signing key and
+// lineage as v2 and v3 of the CtsSignatureQueryService test app with rotation
+// targeting SDK version 33.
+android_test {
+    name: "CtsSignatureQueryServiceTest_v2-tgt-33",
+    defaults: ["cts_support_defaults"],
+    manifest: "AndroidManifest_v2.xml",
+    compile_multilib: "both",
+    min_sdk_version: "32",
+    sdk_version: "current",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "cts_signature_query_service",
+        "androidx.test.core",
+        "androidx.test.rules",
+    ],
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+    test_suites: [
+        "cts",
+        "general-tests",
+    ],
+    certificate: ":ec-p256_2",
+    additional_certificates: [":ec-p256"],
+    lineage: ":ec-p256-por_1_2-default-caps",
+    rotationMinSdkVersion: "33",
+    v4_signature: true,
+    // Disable dexpreopt and <uses-library> check for test
+    enforce_uses_libs: false,
+    dex_preopt: {
+        enabled: false,
+    },
+}
diff --git a/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java b/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java
index e7d954f..9affccb 100644
--- a/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java
+++ b/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java
@@ -82,6 +82,8 @@
     // Uses internal consts defined in BackgroundDexOptService only for testing purpose.
     private static final int STATUS_OK = 0;
     private static final int STATUS_CANCELLED = 1;
+    // We allow package level failure in dexopt, which will lead into this error state.
+    private static final int STATUS_DEX_OPT_FAILED = 5;
 
     private ITestDevice mDevice;
 
@@ -124,7 +126,7 @@
                 () -> getLastExecutionTime().duration >= 0);
 
         int status = getLastDexOptStatus();
-        assertThat(status).isAnyOf(STATUS_OK, STATUS_CANCELLED);
+        assertThat(status).isAnyOf(STATUS_OK, STATUS_DEX_OPT_FAILED, STATUS_CANCELLED);
         if (status == STATUS_CANCELLED) {
             assertThat(checkFinishedPostBootUpdate()).isFalse();
             // If cancelled, we can complete it by running it again.
@@ -177,7 +179,7 @@
                 () -> getLastExecutionTime().duration >= 0);
 
         int status = getLastDexOptStatus();
-        assertThat(status).isAnyOf(STATUS_OK, STATUS_CANCELLED);
+        assertThat(status).isAnyOf(STATUS_OK, STATUS_DEX_OPT_FAILED, STATUS_CANCELLED);
         if (status == STATUS_CANCELLED) {
             // If cancelled, we can complete it by running it again.
             completeIdleOptimization();
@@ -204,7 +206,7 @@
         assertThat(timeAfter.startTime).isAtLeast(timeBefore.deviceCurrentTime);
         assertThat(timeAfter.duration).isAtLeast(0);
         int status = getLastDexOptStatus();
-        assertThat(status).isEqualTo(STATUS_OK);
+        assertThat(status).isAnyOf(STATUS_OK, STATUS_DEX_OPT_FAILED);
     }
 
     private void completeIdleOptimization() throws Exception {
@@ -220,7 +222,7 @@
                 });
 
         int status = getLastDexOptStatus();
-        assertThat(status).isEqualTo(STATUS_OK);
+        assertThat(status).isAnyOf(STATUS_OK, STATUS_DEX_OPT_FAILED);
     }
 
     @After
diff --git a/hostsidetests/cpptools/Android.bp b/hostsidetests/cpptools/Android.bp
index 90bf3a7..f2a9ee5 100644
--- a/hostsidetests/cpptools/Android.bp
+++ b/hostsidetests/cpptools/Android.bp
@@ -29,4 +29,10 @@
         "cts",
         "general-tests",
     ],
+    data: [
+        ":CtsCppToolsApp",
+        ":CtsDomainSocket",
+    ],
+    data_device_bins_both: ["connector"],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 0d0bd8f..c87a7f8 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -32,6 +32,7 @@
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.cts.devicepolicy.DeviceAdminFeaturesCheckerRule.RequiresAdditionalFeatures;
+import com.android.cts.devicepolicy.DeviceAdminFeaturesCheckerRule.TemporarilyIgnoreOnHeadlessSystemUserMode;
 import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
 import com.android.tradefed.log.LogUtil.CLog;
 
@@ -342,6 +343,8 @@
         executeCreateAndManageUserTest("testCreateAndManageUser_RemoveRestrictionSet");
     }
 
+    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "220386262",
+            reason = "Often fails on automotive due to race condition")
     @Test
     public void testCreateAndManageUser_newUserDisclaimer() throws Exception {
         assumeCanStartNewUser();
diff --git a/hostsidetests/graphics/gpuprofiling/Android.bp b/hostsidetests/graphics/gpuprofiling/Android.bp
index ff441bc..b57dc9d 100644
--- a/hostsidetests/graphics/gpuprofiling/Android.bp
+++ b/hostsidetests/graphics/gpuprofiling/Android.bp
@@ -30,4 +30,9 @@
         "perfetto_config-full",
         "platform-test-annotations-host",
     ],
+    data: [
+        ":CtsGraphicsProfilingDataApp",
+    ],
+    data_device_bins_both: ["ctsgraphicsgpucountersinit"],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/multidevices/wifi_aware/AndroidTest.xml b/hostsidetests/multidevices/wifi_aware/AndroidTest.xml
index a1e242c..ccc79f0 100644
--- a/hostsidetests/multidevices/wifi_aware/AndroidTest.xml
+++ b/hostsidetests/multidevices/wifi_aware/AndroidTest.xml
@@ -17,6 +17,11 @@
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
 
+    <object class="com.android.tradefed.testtype.suite.module.DeviceFeatureModuleController"
+        type="module_controller">
+        <option name="required-feature" value="android.hardware.wifi.aware" />
+    </object>
+
     <device name="device1">
         <!-- For coverage to work, the APK should not be uninstalled until after coverage is pulled.
              So it's a lot easier to install APKs outside the python code.
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2022-20123/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2022-20123/Android.bp
new file mode 100644
index 0000000..cf02527
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2022-20123/Android.bp
@@ -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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "CVE-2022-20123",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_memutils",
+    ],
+    include_dirs: [
+        "packages/apps/Nfc/nci/jni/extns/pn54x/inc",
+        "packages/apps/Nfc/nci/jni/extns/pn54x/src/common",
+        "packages/apps/Nfc/nci/jni/extns/pn54x/src/mifare",
+        "system/nfc/src/gki/common",
+        "system/nfc/src/gki/ulinux",
+        "system/nfc/src/include",
+        "system/nfc/src/nfa/include",
+        "system/nfc/src/nfc/include",
+    ],
+    shared_libs: [
+        "libnfc_nci_jni",
+    ],
+    cflags: [
+        "-DCHECK_OVERFLOW",
+        "-DENABLE_SELECTIVE_OVERLOADING",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2022-20123/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2022-20123/poc.cpp
new file mode 100644
index 0000000..26c233e
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2022-20123/poc.cpp
@@ -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.
+ *
+ */
+
+#include <unistd.h>
+#include <vector>
+#include "../includes/common.h"
+#include "../includes/memutils.h"
+#include "phNxpExtns_MifareStd.h"
+
+bool testInProgress = false;
+char enable_selective_overload = ENABLE_NONE;
+struct sigaction new_action, old_action;
+
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+    if (testInProgress && info->si_signo == SIGSEGV) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    _exit(EXIT_FAILURE);
+}
+
+int main() {
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_action, &old_action);
+    constexpr int32_t size = 16;
+    constexpr int32_t index = 1;
+    enable_selective_overload = ENABLE_ALL;
+    std::vector<uint8_t> bufferVector(size);
+    uint8_t *buffer = bufferVector.data();
+    FAIL_CHECK(buffer);
+    buffer[size - 1] = phNciNfc_e_MfcAuthRsp;
+    phNxpExtns_MfcModuleInit();
+    testInProgress = true;
+    Mfc_RecvPacket(&buffer[size - 1], index);
+    enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;
+    testInProgress = false;
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2022-20147/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2022-20147/Android.bp
new file mode 100644
index 0000000..62741e7
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2022-20147/Android.bp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "CVE-2022-20147",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+         ":cts_hostsidetests_securitybulletin_memutils",
+    ],
+    compile_multilib: "64",
+    shared_libs: [
+        "libnfc-nci",
+    ],
+    include_dirs: [
+        "system/nfc/src/nfa/include/",
+        "system/nfc/src/nfc/include/",
+        "system/nfc/src/include/",
+        "system/nfc/src/gki/common/",
+        "system/nfc/src/gki/ulinux/",
+    ],
+    cflags: [
+        "-DCHECK_OVERFLOW",
+        "-DENABLE_SELECTIVE_OVERLOADING",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2022-20147/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2022-20147/poc.cpp
new file mode 100644
index 0000000..3d114e2
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2022-20147/poc.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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 "../includes/memutils.h"
+
+#include <nfa_dm_int.h>
+#include <rw_int.h>
+#include <unistd.h>
+
+constexpr size_t kBufferSize = 2;
+constexpr size_t kLengthVal = 0x30;
+char enable_selective_overload = ENABLE_NONE;
+bool testInProgress = false;
+
+struct sigaction new_action, old_action;
+
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+    if (testInProgress && info->si_signo == SIGSEGV) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    _exit(EXIT_FAILURE);
+}
+
+void poc_cback(tRW_EVENT, tRW_DATA*) {
+}
+
+int main() {
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_action, &old_action);
+
+    tNFC_ACTIVATE_DEVT p_activate_params = { };
+    p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+    p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+    RW_SetActivatedTagType(&p_activate_params, &poc_cback);
+    FAIL_CHECK(rw_cb.p_cback == &poc_cback);
+
+    enable_selective_overload = ENABLE_ALL;
+    uint8_t *buffer = (uint8_t *)malloc(kBufferSize * sizeof(uint8_t));
+    FAIL_CHECK(buffer);
+    buffer[0] = NFC_PMID_ATR_RES_GEN_BYTES;
+    buffer[1] = kLengthVal;
+
+    testInProgress = true;
+    nfa_dm_check_set_config(kBufferSize, buffer, false);
+    enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;
+    testInProgress = false;
+
+    free(buffer);
+
+    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 b2ed808..5532e46 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
@@ -53,6 +53,6 @@
         installPackage(TEST_APP);
         AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW",
                 device);
-        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testVulnerableActivityPresence"));
+        runDeviceTests(TEST_PKG, TEST_CLASS, "testVulnerableActivityPresence");
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java
new file mode 100644
index 0000000..8fbf443
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.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.regex.Pattern;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20123 extends SecurityTestCase {
+
+    /**
+     * b/221852424
+     * Vulnerability Behaviour: SIGSEGV in self
+     * Vulnerable Library: libnfc_nci_jni (As per AOSP code)
+     * Vulnerable Function: Mfc_RecvPacket (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 221852424)
+    @Test
+    public void testPocCVE_2022_20123() throws Exception {
+        AdbUtils.assumeHasNfc(getDevice());
+        assumeIsSupportedNfcDevice(getDevice());
+        String signals[] = {CrashUtils.SIGSEGV};
+        String binaryName = "CVE-2022-20123";
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+                .setBacktraceIncludes(
+                        new BacktraceFilterPattern("libnfc_nci_jni", "Mfc_RecvPacket"));
+        testConfig.config
+                .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
+        testConfig.config.setSignals(signals);
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java
new file mode 100644
index 0000000..45c6fb1
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20138 extends StsExtraBusinessLogicHostTestBase {
+    static final String TEST_APP = "CVE-2022-20138.apk";
+    static final String TEST_PKG = "android.security.cts.CVE_2022_20138";
+    static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+
+    @AsbSecurityTest(cveBugId = 210469972)
+    @Test
+    public void testPocCVE_2022_20138() throws Exception {
+        ITestDevice device = getDevice();
+        uninstallPackage(device, TEST_PKG);
+
+        /* Wake up the screen */
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+        installPackage(TEST_APP);
+        runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2022_20138");
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
new file mode 100644
index 0000000..41a727f
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
@@ -0,0 +1,63 @@
+/*
+ * 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.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.util.regex.Pattern;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20147 extends SecurityTestCase {
+    /**
+     * b/221216105
+     * Vulnerability Behaviour: SIGSEGV in self
+     * Vulnerable Library: libnfc-nci (As per AOSP code)
+     * Vulnerable Function: nfa_dm_check_set_config (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 221216105)
+    @Test
+    public void testPocCVE_2022_20147() {
+        try {
+            AdbUtils.assumeHasNfc(getDevice());
+            assumeIsSupportedNfcDevice(getDevice());
+            pocPusher.only64();
+            String signals[] = { CrashUtils.SIGSEGV };
+            String binaryName = "CVE-2022-20147";
+            AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName,
+                    getDevice());
+            testConfig.config = new CrashUtils.Config()
+                    .setProcessPatterns(Pattern.compile(binaryName))
+                    .setBacktraceIncludes(new BacktraceFilterPattern(
+                            "libnfc-nci", "nfa_dm_check_set_config"));
+            testConfig.config.setBacktraceExcludes(
+                    new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
+            testConfig.config.setSignals(signals);
+            AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java
new file mode 100644
index 0000000..1886a4a
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import 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_20230 extends StsExtraBusinessLogicHostTestBase {
+    public static final int USER_ID = 0;
+    static final String TEST_APP = "CVE-2022-20230.apk";
+    static final String TEST_PKG = "android.security.cts.CVE_2022_20230";
+    static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+    public static final String TEST_DEVICE_ADMIN_RECEIVER = TEST_PKG + ".PocDeviceAdminReceiver";
+
+    @AsbSecurityTest(cveBugId = 221859869)
+    @Test
+    public void testPocCVE_2022_20230() throws Exception {
+        try {
+            ITestDevice device = getDevice();
+
+            /* Wake up the screen */
+            AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+            installPackage(TEST_APP, "-t");
+
+            /* Set Device Admin Component */
+            AdbUtils.runCommandLine("dpm set-device-owner --user " + USER_ID + " '" + TEST_PKG + "/"
+                    + TEST_DEVICE_ADMIN_RECEIVER + "'", device);
+
+            runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2022_20230");
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index 06cf21a..c4d37b0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -238,7 +238,7 @@
     @Test
     @AsbSecurityTest(cveBugId = 36104177)
     public void testPocCVE_2017_0670() throws Exception {
-        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2017-0670", null, getDevice());
+        AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2017-0670", getDevice(), 60);
     }
 
     /**
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 6e36fb3..f986906 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
@@ -20,7 +20,9 @@
 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 android.content.Context;
 import android.content.Intent;
 import android.provider.Settings;
@@ -70,7 +72,11 @@
         Intent intent = new Intent();
         intent.setClassName(TEST_VULNERABLE_PKG, TEST_VULNERABLE_ACTIVITY);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        context.startActivity(intent);
+        try {
+            context.startActivity(intent);
+        } catch (ActivityNotFoundException e) {
+            assumeNoException("Activity not found on device", e);
+        }
     }
 
     @Before
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/Android.bp
new file mode 100644
index 0000000..7b74f57
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/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-20138",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+    ],
+    sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/AndroidManifest.xml
new file mode 100644
index 0000000..f1649cc
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2022_20138"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <application>
+        <receiver android:name=".PocReceiver"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.app.action.MANAGED_PROFILE_PROVISIONED" />
+            </intent-filter>
+        </receiver>
+    </application>
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2022_20138" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/res/values/integers.xml
new file mode 100644
index 0000000..622d66f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/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="userId">10</integer>
+    <integer name="queueSize">1</integer>
+    <integer name="timeoutMs">5000</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/res/values/strings.xml
new file mode 100644
index 0000000..b646fe6
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?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="failMessage">Device is vulnerable to b/210469972</string>
+    <string name="resultKey">result</string>
+    <string name="sharedPreferences">CVE_2022_20138_prefs</string>
+    <string name="failQueryReceivers">PocReceiver not found by queryBroadcastReceivers</string>
+    <string name="receiverNotFound">No broadcast receiver found for the intent %1$s</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/src/android/security/cts/CVE_2022_20138/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/src/android/security/cts/CVE_2022_20138/DeviceTest.java
new file mode 100644
index 0000000..a2534f1
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/src/android/security/cts/CVE_2022_20138/DeviceTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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_20138;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+    @Test
+    public void testCVE_2022_20138() {
+        try {
+            Context context = getApplicationContext();
+            Resources resources = context.getResources();
+            BlockingQueue<Boolean> blockingQueue =
+                    new ArrayBlockingQueue<>(resources.getInteger(R.integer.queueSize));
+
+            // Register a shared preferences listener to listen to any update made by PocReceiver
+            // to shared preferences.
+            SharedPreferences sharedPrefs = context.getSharedPreferences(
+                    context.getString(R.string.sharedPreferences), Context.MODE_APPEND);
+            OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+                @Override
+                public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+                        String key) {
+                    if (key.equals(context.getString(R.string.resultKey))) {
+                        blockingQueue.add(true);
+                    }
+                }
+            };
+            sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
+
+            // Send a broadcast using intent action
+            // DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED. This is allowed for our
+            // unprivileged app if vulnerability is active.
+            Intent intent = new Intent(DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            intent.putExtra(Intent.EXTRA_USER, resources.getInteger(R.integer.userId));
+
+            PackageManager packageManager = context.getPackageManager();
+            List<ResolveInfo> infos = packageManager.queryBroadcastReceivers(intent, 0);
+            assumeTrue(context.getString(R.string.receiverNotFound, intent), !infos.isEmpty());
+            String activityName = null;
+            for (ResolveInfo info : infos) {
+                if (info != null && info.activityInfo != null
+                        && info.activityInfo.packageName != null) {
+                    if (info.activityInfo.packageName.equals(context.getPackageName())) {
+                        activityName = info.activityInfo.name;
+                    }
+                }
+            }
+            assumeNotNull(context.getString(R.string.failQueryReceivers), activityName);
+            intent.setComponent(new ComponentName(context.getPackageName(), activityName));
+
+            context.sendBroadcast(intent);
+
+            // Wait on a result from PocReceiver
+            Boolean intentReceived = null;
+            intentReceived = blockingQueue.poll(resources.getInteger(R.integer.timeoutMs),
+                    TimeUnit.MILLISECONDS);
+
+            // If 'intentReceived' is non-null i.e. intent was received by the broadcast receiver,
+            // it means broadcast is sent without any restrictions, which indicates that
+            // vulnerability
+            // is active.
+            assertNull(context.getString(R.string.failMessage), intentReceived);
+        } catch (Exception e) {
+            if (e instanceof SecurityException && e.getMessage() != null && e.getMessage().trim()
+                    .contains(DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED)) {
+                return;
+            }
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/src/android/security/cts/CVE_2022_20138/PocReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/src/android/security/cts/CVE_2022_20138/PocReceiver.java
new file mode 100644
index 0000000..f3f285b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20138/src/android/security/cts/CVE_2022_20138/PocReceiver.java
@@ -0,0 +1,40 @@
+/*
+ * 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_20138;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+
+public class PocReceiver extends BroadcastReceiver {
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (intent != null && context != null && intent.getAction()
+                .equals(DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED)) {
+            SharedPreferences sh = context.getSharedPreferences(
+                    context.getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
+            if (sh != null) {
+                SharedPreferences.Editor edit = sh.edit();
+                edit.putBoolean(context.getString(R.string.resultKey), true);
+                edit.commit();
+            }
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/Android.bp
new file mode 100644
index 0000000..6a1d4d5
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+    name: "CVE-2022-20230",
+    defaults: [
+        "cts_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-20230/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/AndroidManifest.xml
new file mode 100644
index 0000000..0fc86cf
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/AndroidManifest.xml
@@ -0,0 +1,46 @@
+<?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_20230"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <application>
+        <activity
+            android:name=".PocActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <receiver android:name=".PocDeviceAdminReceiver"
+            android:exported="true"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data
+                android:name="android.app.device_admin"
+                android:resource="@xml/device_policies" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"></action>
+            </intent-filter>
+        </receiver>
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2022_20230" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/res/values/strings.xml
new file mode 100644
index 0000000..19614c3
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/res/values/strings.xml
@@ -0,0 +1,32 @@
+<?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="actionKeychainActivity">com.android.keychain.CHOOSER</string>
+    <string name="activityNotFoundMsg">The activity with intent was not found : </string>
+    <string name="activityNotStartedException">Unable to start the activity with intent : </string>
+    <string name="alias">Client</string>
+    <string name="certType">X.509</string>
+    <string name="dumpsysActivity">dumpsys activity</string>
+    <string name="failMessage">Vulnerable to b/221859869 !!</string>
+    <string name="keyType">RSA</string>
+    <string name="mResumedTrue">mResumed=true</string>
+    <string name="vulActivityNotRunningError">The activity %1$s is not currently running
+    on the device</string>
+    <string name="vulText">CVE 2022 20230</string>
+    <string name="vulTextPattern">.*CVE 2022 20230.*</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/res/xml/device_policies.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/res/xml/device_policies.xml
new file mode 100644
index 0000000..a826e80
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/res/xml/device_policies.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.
+  -->
+
+<device-admin>
+    <uses-policies>
+    </uses-policies>
+</device-admin>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/src/android/security/cts/CVE_2022_20230/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/src/android/security/cts/CVE_2022_20230/DeviceTest.java
new file mode 100644
index 0000000..2db6912
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/src/android/security/cts/CVE_2022_20230/DeviceTest.java
@@ -0,0 +1,361 @@
+/*
+ * 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_20230;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+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.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    static final int TIMEOUT_MS = 5000;
+    PocPolicyManager mPolicyManager;
+    Context mContext;
+
+    /**
+     * Generated from above and converted with:
+     *
+     * openssl pkcs8 -topk8 -outform d -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
+     */
+    private static final byte[] PRIVATE_KEY =
+            new byte[] {(byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x76, (byte) 0x02,
+                    (byte) 0x01, (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
+                    (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
+                    (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04,
+                    (byte) 0x82, (byte) 0x02, (byte) 0x60, (byte) 0x30, (byte) 0x82, (byte) 0x02,
+                    (byte) 0x5c, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81,
+                    (byte) 0x81, (byte) 0x00, (byte) 0xee, (byte) 0x6e, (byte) 0x51, (byte) 0xa8,
+                    (byte) 0xc4, (byte) 0x44, (byte) 0xd9, (byte) 0xb7, (byte) 0x53, (byte) 0xf1,
+                    (byte) 0xb9, (byte) 0x1b, (byte) 0x9d, (byte) 0x8d, (byte) 0x7c, (byte) 0x9f,
+                    (byte) 0x06, (byte) 0xe7, (byte) 0xed, (byte) 0xa8, (byte) 0x05, (byte) 0xb8,
+                    (byte) 0xaa, (byte) 0x0a, (byte) 0x2d, (byte) 0x74, (byte) 0x05, (byte) 0x8b,
+                    (byte) 0xad, (byte) 0xfe, (byte) 0xd3, (byte) 0x3e, (byte) 0x08, (byte) 0x9d,
+                    (byte) 0xc9, (byte) 0xf5, (byte) 0xf7, (byte) 0x81, (byte) 0x90, (byte) 0xf1,
+                    (byte) 0xcc, (byte) 0x3f, (byte) 0x91, (byte) 0xda, (byte) 0xcb, (byte) 0x67,
+                    (byte) 0x6a, (byte) 0xe8, (byte) 0x4a, (byte) 0xa0, (byte) 0xc3, (byte) 0x8a,
+                    (byte) 0x53, (byte) 0xd9, (byte) 0xf0, (byte) 0x17, (byte) 0xbe, (byte) 0x90,
+                    (byte) 0xbb, (byte) 0x95, (byte) 0x29, (byte) 0x01, (byte) 0xce, (byte) 0x32,
+                    (byte) 0xce, (byte) 0xf8, (byte) 0x02, (byte) 0xfe, (byte) 0xe8, (byte) 0x19,
+                    (byte) 0x91, (byte) 0x29, (byte) 0x46, (byte) 0xf7, (byte) 0x67, (byte) 0xd1,
+                    (byte) 0xcb, (byte) 0xa7, (byte) 0x20, (byte) 0x8b, (byte) 0x85, (byte) 0x8a,
+                    (byte) 0x0c, (byte) 0x07, (byte) 0xf8, (byte) 0xfe, (byte) 0xf4, (byte) 0x5d,
+                    (byte) 0x08, (byte) 0xf4, (byte) 0x63, (byte) 0x4a, (byte) 0x69, (byte) 0x66,
+                    (byte) 0x28, (byte) 0xcb, (byte) 0x0d, (byte) 0x1c, (byte) 0x7f, (byte) 0x7f,
+                    (byte) 0x7e, (byte) 0x83, (byte) 0x49, (byte) 0x66, (byte) 0x6c, (byte) 0x83,
+                    (byte) 0x2d, (byte) 0xa0, (byte) 0x51, (byte) 0xf6, (byte) 0x14, (byte) 0x68,
+                    (byte) 0x47, (byte) 0x31, (byte) 0x72, (byte) 0x4d, (byte) 0xe9, (byte) 0x1e,
+                    (byte) 0x12, (byte) 0x1b, (byte) 0xd0, (byte) 0xe6, (byte) 0x21, (byte) 0xd8,
+                    (byte) 0x84, (byte) 0x5f, (byte) 0xe3, (byte) 0xef, (byte) 0x02, (byte) 0x03,
+                    (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80,
+                    (byte) 0x24, (byte) 0x95, (byte) 0xb8, (byte) 0xe1, (byte) 0xf4, (byte) 0x7b,
+                    (byte) 0xbc, (byte) 0x0c, (byte) 0x6d, (byte) 0x4d, (byte) 0x01, (byte) 0xe2,
+                    (byte) 0x42, (byte) 0xe2, (byte) 0x9a, (byte) 0xe4, (byte) 0xab, (byte) 0xe2,
+                    (byte) 0x9a, (byte) 0x8c, (byte) 0xd5, (byte) 0x93, (byte) 0xe8, (byte) 0x43,
+                    (byte) 0x77, (byte) 0x85, (byte) 0xfd, (byte) 0xf3, (byte) 0xd8, (byte) 0xd6,
+                    (byte) 0xe9, (byte) 0x02, (byte) 0xf3, (byte) 0xbf, (byte) 0x82, (byte) 0x65,
+                    (byte) 0xc3, (byte) 0x7c, (byte) 0x96, (byte) 0x09, (byte) 0x04, (byte) 0x16,
+                    (byte) 0x1d, (byte) 0x03, (byte) 0x3d, (byte) 0x82, (byte) 0xb8, (byte) 0xdc,
+                    (byte) 0xbb, (byte) 0xd6, (byte) 0xbf, (byte) 0x2a, (byte) 0x52, (byte) 0x83,
+                    (byte) 0x76, (byte) 0x5b, (byte) 0xae, (byte) 0x59, (byte) 0xf6, (byte) 0xee,
+                    (byte) 0x84, (byte) 0x44, (byte) 0x4a, (byte) 0xa7, (byte) 0x25, (byte) 0x50,
+                    (byte) 0x89, (byte) 0x63, (byte) 0x43, (byte) 0x0b, (byte) 0xc8, (byte) 0xd5,
+                    (byte) 0x17, (byte) 0x9d, (byte) 0x8b, (byte) 0x62, (byte) 0xd5, (byte) 0xf1,
+                    (byte) 0xde, (byte) 0x45, (byte) 0xe6, (byte) 0x35, (byte) 0x10, (byte) 0xba,
+                    (byte) 0x58, (byte) 0x18, (byte) 0x44, (byte) 0xc1, (byte) 0x6d, (byte) 0xb6,
+                    (byte) 0x1d, (byte) 0x2f, (byte) 0x53, (byte) 0xb6, (byte) 0x5a, (byte) 0xf1,
+                    (byte) 0x66, (byte) 0xbc, (byte) 0x0e, (byte) 0x63, (byte) 0xa7, (byte) 0x0f,
+                    (byte) 0x81, (byte) 0x4b, (byte) 0x07, (byte) 0x31, (byte) 0xa5, (byte) 0x70,
+                    (byte) 0xec, (byte) 0x30, (byte) 0x57, (byte) 0xc4, (byte) 0x14, (byte) 0xb2,
+                    (byte) 0x8b, (byte) 0x6f, (byte) 0x26, (byte) 0x7e, (byte) 0x55, (byte) 0x60,
+                    (byte) 0x63, (byte) 0x7d, (byte) 0x90, (byte) 0xd7, (byte) 0x5f, (byte) 0xef,
+                    (byte) 0x7d, (byte) 0xc1, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xfe,
+                    (byte) 0x92, (byte) 0xa9, (byte) 0xf1, (byte) 0x29, (byte) 0x1e, (byte) 0xd4,
+                    (byte) 0x72, (byte) 0xd3, (byte) 0x3f, (byte) 0x9d, (byte) 0xd6, (byte) 0x3d,
+                    (byte) 0xe9, (byte) 0xcf, (byte) 0x3e, (byte) 0x06, (byte) 0xdc, (byte) 0x65,
+                    (byte) 0x8f, (byte) 0xc0, (byte) 0x81, (byte) 0xc2, (byte) 0x66, (byte) 0xc1,
+                    (byte) 0x5c, (byte) 0x2c, (byte) 0xfa, (byte) 0x08, (byte) 0x65, (byte) 0xb6,
+                    (byte) 0x47, (byte) 0xc5, (byte) 0x14, (byte) 0x8d, (byte) 0x69, (byte) 0xe9,
+                    (byte) 0xaf, (byte) 0x42, (byte) 0x02, (byte) 0x53, (byte) 0x04, (byte) 0x63,
+                    (byte) 0x47, (byte) 0xaf, (byte) 0xcc, (byte) 0xae, (byte) 0x08, (byte) 0x31,
+                    (byte) 0xba, (byte) 0xea, (byte) 0x85, (byte) 0xda, (byte) 0xd6, (byte) 0xb2,
+                    (byte) 0xe7, (byte) 0x4c, (byte) 0xda, (byte) 0xad, (byte) 0x52, (byte) 0x76,
+                    (byte) 0x48, (byte) 0x16, (byte) 0xeb, (byte) 0x02, (byte) 0x41, (byte) 0x00,
+                    (byte) 0xef, (byte) 0xc4, (byte) 0x7d, (byte) 0x69, (byte) 0x7b, (byte) 0xcb,
+                    (byte) 0xcb, (byte) 0xf7, (byte) 0x00, (byte) 0x2d, (byte) 0x05, (byte) 0x3c,
+                    (byte) 0xe4, (byte) 0xfd, (byte) 0x5c, (byte) 0xea, (byte) 0xcf, (byte) 0x40,
+                    (byte) 0x84, (byte) 0x10, (byte) 0xf1, (byte) 0xc0, (byte) 0xaf, (byte) 0xc7,
+                    (byte) 0xc8, (byte) 0x51, (byte) 0xac, (byte) 0x18, (byte) 0x25, (byte) 0x63,
+                    (byte) 0x75, (byte) 0xc7, (byte) 0x0e, (byte) 0xa9, (byte) 0xed, (byte) 0x9c,
+                    (byte) 0x78, (byte) 0x08, (byte) 0x28, (byte) 0x1d, (byte) 0x9e, (byte) 0xfa,
+                    (byte) 0x17, (byte) 0x0f, (byte) 0x7a, (byte) 0x6a, (byte) 0x78, (byte) 0x63,
+                    (byte) 0x6e, (byte) 0xb3, (byte) 0x6b, (byte) 0xd6, (byte) 0x43, (byte) 0x4b,
+                    (byte) 0x58, (byte) 0xb8, (byte) 0x77, (byte) 0x10, (byte) 0x07, (byte) 0x70,
+                    (byte) 0xa6, (byte) 0xa9, (byte) 0xae, (byte) 0x0d, (byte) 0x02, (byte) 0x41,
+                    (byte) 0x00, (byte) 0x92, (byte) 0x4c, (byte) 0x79, (byte) 0x0b, (byte) 0x95,
+                    (byte) 0xc5, (byte) 0x18, (byte) 0xf4, (byte) 0x90, (byte) 0x40, (byte) 0x8c,
+                    (byte) 0x15, (byte) 0x96, (byte) 0x69, (byte) 0x2a, (byte) 0xe7, (byte) 0x8b,
+                    (byte) 0x8b, (byte) 0xd7, (byte) 0x76, (byte) 0x00, (byte) 0x7c, (byte) 0xd1,
+                    (byte) 0xda, (byte) 0xb9, (byte) 0x9e, (byte) 0x9e, (byte) 0x5e, (byte) 0x66,
+                    (byte) 0xbb, (byte) 0x05, (byte) 0x41, (byte) 0x43, (byte) 0x9a, (byte) 0x67,
+                    (byte) 0x16, (byte) 0x89, (byte) 0xec, (byte) 0x65, (byte) 0x33, (byte) 0xee,
+                    (byte) 0xbf, (byte) 0xa3, (byte) 0xca, (byte) 0x8b, (byte) 0xd6, (byte) 0x45,
+                    (byte) 0xe1, (byte) 0x81, (byte) 0xaa, (byte) 0xd8, (byte) 0xa2, (byte) 0x6a,
+                    (byte) 0x3c, (byte) 0x5e, (byte) 0x7e, (byte) 0x1c, (byte) 0xa5, (byte) 0xc3,
+                    (byte) 0x5b, (byte) 0x93, (byte) 0x8c, (byte) 0x24, (byte) 0x57, (byte) 0x02,
+                    (byte) 0x40, (byte) 0x0a, (byte) 0x6d, (byte) 0x3f, (byte) 0x0e, (byte) 0xf1,
+                    (byte) 0x45, (byte) 0x41, (byte) 0x8f, (byte) 0x72, (byte) 0x40, (byte) 0x82,
+                    (byte) 0xf3, (byte) 0xcc, (byte) 0xf9, (byte) 0x7f, (byte) 0xaa, (byte) 0xee,
+                    (byte) 0x6c, (byte) 0x5d, (byte) 0xd1, (byte) 0xe6, (byte) 0xd1, (byte) 0x7c,
+                    (byte) 0x53, (byte) 0x71, (byte) 0xd0, (byte) 0xab, (byte) 0x6d, (byte) 0x39,
+                    (byte) 0x63, (byte) 0x03, (byte) 0xe2, (byte) 0x2e, (byte) 0x2f, (byte) 0x11,
+                    (byte) 0x98, (byte) 0x36, (byte) 0x58, (byte) 0x14, (byte) 0x76, (byte) 0x85,
+                    (byte) 0x4d, (byte) 0x56, (byte) 0xe7, (byte) 0x63, (byte) 0x69, (byte) 0x71,
+                    (byte) 0xe6, (byte) 0xd1, (byte) 0x0f, (byte) 0x98, (byte) 0x66, (byte) 0xee,
+                    (byte) 0xf2, (byte) 0x3d, (byte) 0xdf, (byte) 0x77, (byte) 0xbe, (byte) 0x08,
+                    (byte) 0xb4, (byte) 0xcb, (byte) 0x6a, (byte) 0xa1, (byte) 0x99, (byte) 0x02,
+                    (byte) 0x40, (byte) 0x52, (byte) 0x01, (byte) 0xde, (byte) 0x62, (byte) 0xc2,
+                    (byte) 0x25, (byte) 0xbf, (byte) 0x5d, (byte) 0x77, (byte) 0xe4, (byte) 0x6b,
+                    (byte) 0xb6, (byte) 0xd7, (byte) 0x8f, (byte) 0x89, (byte) 0x2c, (byte) 0xe6,
+                    (byte) 0x8d, (byte) 0xe5, (byte) 0xad, (byte) 0x39, (byte) 0x17, (byte) 0x54,
+                    (byte) 0x2b, (byte) 0x35, (byte) 0x53, (byte) 0xd1, (byte) 0xa1, (byte) 0xef,
+                    (byte) 0x48, (byte) 0xbc, (byte) 0x95, (byte) 0x48, (byte) 0xcf, (byte) 0x62,
+                    (byte) 0xf4, (byte) 0x33, (byte) 0xcf, (byte) 0x37, (byte) 0x78, (byte) 0xeb,
+                    (byte) 0x17, (byte) 0xb4, (byte) 0x0b, (byte) 0x83, (byte) 0x4f, (byte) 0xb6,
+                    (byte) 0xab, (byte) 0x7d, (byte) 0x67, (byte) 0x3e, (byte) 0x4e, (byte) 0x44,
+                    (byte) 0x4a, (byte) 0x55, (byte) 0x2e, (byte) 0x34, (byte) 0x12, (byte) 0x0b,
+                    (byte) 0x59, (byte) 0xb3, (byte) 0xb1, (byte) 0x1e, (byte) 0x3d};
+
+    /**
+     * Generated from above and converted with:
+     *
+     * openssl x509 -outform d -in usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
+     */
+    private static final byte[] USER_CERT =
+            {(byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xd8, (byte) 0x30, (byte) 0x82,
+                    (byte) 0x01, (byte) 0xc0, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
+                    (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d,
+                    (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+                    (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x0b, (byte) 0x05,
+                    (byte) 0x00, (byte) 0x30, (byte) 0x33, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
+                    (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
+                    (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13,
+                    (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+                    (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d,
+                    (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74,
+                    (byte) 0x65, (byte) 0x31, (byte) 0x0f, (byte) 0x30, (byte) 0x0d, (byte) 0x06,
+                    (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x06,
+                    (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65,
+                    (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x32,
+                    (byte) 0x30, (byte) 0x33, (byte) 0x32, (byte) 0x35, (byte) 0x30, (byte) 0x37,
+                    (byte) 0x32, (byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x5a, (byte) 0x17,
+                    (byte) 0x0d, (byte) 0x33, (byte) 0x32, (byte) 0x30, (byte) 0x33, (byte) 0x32,
+                    (byte) 0x32, (byte) 0x30, (byte) 0x37, (byte) 0x32, (byte) 0x30, (byte) 0x31,
+                    (byte) 0x32, (byte) 0x5a, (byte) 0x30, (byte) 0x33, (byte) 0x31, (byte) 0x0b,
+                    (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+                    (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31,
+                    (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+                    (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f,
+                    (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61,
+                    (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x0f, (byte) 0x30, (byte) 0x0d,
+                    (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c,
+                    (byte) 0x06, (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c,
+                    (byte) 0x65, (byte) 0x30, (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d,
+                    (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+                    (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05,
+                    (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30,
+                    (byte) 0x81, (byte) 0x89, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00,
+                    (byte) 0xee, (byte) 0x6e, (byte) 0x51, (byte) 0xa8, (byte) 0xc4, (byte) 0x44,
+                    (byte) 0xd9, (byte) 0xb7, (byte) 0x53, (byte) 0xf1, (byte) 0xb9, (byte) 0x1b,
+                    (byte) 0x9d, (byte) 0x8d, (byte) 0x7c, (byte) 0x9f, (byte) 0x06, (byte) 0xe7,
+                    (byte) 0xed, (byte) 0xa8, (byte) 0x05, (byte) 0xb8, (byte) 0xaa, (byte) 0x0a,
+                    (byte) 0x2d, (byte) 0x74, (byte) 0x05, (byte) 0x8b, (byte) 0xad, (byte) 0xfe,
+                    (byte) 0xd3, (byte) 0x3e, (byte) 0x08, (byte) 0x9d, (byte) 0xc9, (byte) 0xf5,
+                    (byte) 0xf7, (byte) 0x81, (byte) 0x90, (byte) 0xf1, (byte) 0xcc, (byte) 0x3f,
+                    (byte) 0x91, (byte) 0xda, (byte) 0xcb, (byte) 0x67, (byte) 0x6a, (byte) 0xe8,
+                    (byte) 0x4a, (byte) 0xa0, (byte) 0xc3, (byte) 0x8a, (byte) 0x53, (byte) 0xd9,
+                    (byte) 0xf0, (byte) 0x17, (byte) 0xbe, (byte) 0x90, (byte) 0xbb, (byte) 0x95,
+                    (byte) 0x29, (byte) 0x01, (byte) 0xce, (byte) 0x32, (byte) 0xce, (byte) 0xf8,
+                    (byte) 0x02, (byte) 0xfe, (byte) 0xe8, (byte) 0x19, (byte) 0x91, (byte) 0x29,
+                    (byte) 0x46, (byte) 0xf7, (byte) 0x67, (byte) 0xd1, (byte) 0xcb, (byte) 0xa7,
+                    (byte) 0x20, (byte) 0x8b, (byte) 0x85, (byte) 0x8a, (byte) 0x0c, (byte) 0x07,
+                    (byte) 0xf8, (byte) 0xfe, (byte) 0xf4, (byte) 0x5d, (byte) 0x08, (byte) 0xf4,
+                    (byte) 0x63, (byte) 0x4a, (byte) 0x69, (byte) 0x66, (byte) 0x28, (byte) 0xcb,
+                    (byte) 0x0d, (byte) 0x1c, (byte) 0x7f, (byte) 0x7f, (byte) 0x7e, (byte) 0x83,
+                    (byte) 0x49, (byte) 0x66, (byte) 0x6c, (byte) 0x83, (byte) 0x2d, (byte) 0xa0,
+                    (byte) 0x51, (byte) 0xf6, (byte) 0x14, (byte) 0x68, (byte) 0x47, (byte) 0x31,
+                    (byte) 0x72, (byte) 0x4d, (byte) 0xe9, (byte) 0x1e, (byte) 0x12, (byte) 0x1b,
+                    (byte) 0xd0, (byte) 0xe6, (byte) 0x21, (byte) 0xd8, (byte) 0x84, (byte) 0x5f,
+                    (byte) 0xe3, (byte) 0xef, (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00,
+                    (byte) 0x01, (byte) 0xa3, (byte) 0x7b, (byte) 0x30, (byte) 0x79, (byte) 0x30,
+                    (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13,
+                    (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30, (byte) 0x2c,
+                    (byte) 0x06, (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01,
+                    (byte) 0x86, (byte) 0xf8, (byte) 0x42, (byte) 0x01, (byte) 0x0d, (byte) 0x04,
+                    (byte) 0x1f, (byte) 0x16, (byte) 0x1d, (byte) 0x4f, (byte) 0x70, (byte) 0x65,
+                    (byte) 0x6e, (byte) 0x53, (byte) 0x53, (byte) 0x4c, (byte) 0x20, (byte) 0x47,
+                    (byte) 0x65, (byte) 0x6e, (byte) 0x65, (byte) 0x72, (byte) 0x61, (byte) 0x74,
+                    (byte) 0x65, (byte) 0x64, (byte) 0x20, (byte) 0x43, (byte) 0x65, (byte) 0x72,
+                    (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, (byte) 0x61,
+                    (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x1d, (byte) 0x06, (byte) 0x03,
+                    (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, (byte) 0x04,
+                    (byte) 0x14, (byte) 0xee, (byte) 0xec, (byte) 0x08, (byte) 0xcc, (byte) 0xdd,
+                    (byte) 0xa3, (byte) 0x29, (byte) 0x6e, (byte) 0x2b, (byte) 0x78, (byte) 0x23,
+                    (byte) 0xb3, (byte) 0xf0, (byte) 0xb8, (byte) 0x9d, (byte) 0x53, (byte) 0x41,
+                    (byte) 0x2e, (byte) 0x3c, (byte) 0x61, (byte) 0x30, (byte) 0x1f, (byte) 0x06,
+                    (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, (byte) 0x18,
+                    (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x86, (byte) 0xdb,
+                    (byte) 0xa5, (byte) 0x5e, (byte) 0x0e, (byte) 0x03, (byte) 0xbc, (byte) 0xe4,
+                    (byte) 0xc1, (byte) 0xc8, (byte) 0xf3, (byte) 0xed, (byte) 0x24, (byte) 0x48,
+                    (byte) 0xb1, (byte) 0x37, (byte) 0x3a, (byte) 0x52, (byte) 0x10, (byte) 0x57,
+                    (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
+                    (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
+                    (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, (byte) 0x01,
+                    (byte) 0x01, (byte) 0x00, (byte) 0x15, (byte) 0x5a, (byte) 0x5c, (byte) 0x08,
+                    (byte) 0xe4, (byte) 0x0e, (byte) 0x28, (byte) 0x4c, (byte) 0xa9, (byte) 0x0e,
+                    (byte) 0x35, (byte) 0xbe, (byte) 0xe3, (byte) 0xd5, (byte) 0xd1, (byte) 0xb4,
+                    (byte) 0x47, (byte) 0x87, (byte) 0x63, (byte) 0xd2, (byte) 0x5e, (byte) 0x7e,
+                    (byte) 0xf6, (byte) 0xd8, (byte) 0xce, (byte) 0xdf, (byte) 0x10, (byte) 0x15,
+                    (byte) 0x61, (byte) 0xc4, (byte) 0x9a, (byte) 0xf1, (byte) 0xba, (byte) 0x33,
+                    (byte) 0xf2, (byte) 0xc2, (byte) 0x01, (byte) 0x95, (byte) 0xa7, (byte) 0x74,
+                    (byte) 0x97, (byte) 0xc1, (byte) 0x43, (byte) 0x68, (byte) 0x92, (byte) 0xbe,
+                    (byte) 0x9a, (byte) 0x6f, (byte) 0x38, (byte) 0xcb, (byte) 0xa0, (byte) 0xcf,
+                    (byte) 0x1e, (byte) 0x5b, (byte) 0x03, (byte) 0xde, (byte) 0x45, (byte) 0x6d,
+                    (byte) 0xea, (byte) 0xf0, (byte) 0x46, (byte) 0x4d, (byte) 0xb6, (byte) 0x4b,
+                    (byte) 0x88, (byte) 0xc7, (byte) 0xb8, (byte) 0xe3, (byte) 0x9f, (byte) 0x58,
+                    (byte) 0x8b, (byte) 0x2d, (byte) 0xbf, (byte) 0x4b, (byte) 0x3f, (byte) 0x54,
+                    (byte) 0x2d, (byte) 0xa8, (byte) 0x27, (byte) 0x72, (byte) 0x5e, (byte) 0x36,
+                    (byte) 0x67, (byte) 0x5c, (byte) 0x6e, (byte) 0x9a, (byte) 0x67, (byte) 0x73,
+                    (byte) 0x44, (byte) 0xaf, (byte) 0x46, (byte) 0x7f, (byte) 0xd6, (byte) 0x2b,
+                    (byte) 0x9d, (byte) 0x28, (byte) 0xb1, (byte) 0xc4, (byte) 0xc4, (byte) 0x72,
+                    (byte) 0x3d, (byte) 0x6d, (byte) 0x7d, (byte) 0x28, (byte) 0x40, (byte) 0x62,
+                    (byte) 0x40, (byte) 0x21, (byte) 0x52, (byte) 0xb5, (byte) 0x0b, (byte) 0xf3,
+                    (byte) 0xcc, (byte) 0x36, (byte) 0x03, (byte) 0x10, (byte) 0x19, (byte) 0xe3,
+                    (byte) 0xc2, (byte) 0xfe, (byte) 0xe9, (byte) 0x08, (byte) 0x0d, (byte) 0xd4,
+                    (byte) 0x8b, (byte) 0x12, (byte) 0xd6, (byte) 0x3d, (byte) 0xc5, (byte) 0xb8,
+                    (byte) 0x8c, (byte) 0xbd, (byte) 0xa5, (byte) 0xcd, (byte) 0xb3, (byte) 0xe4,
+                    (byte) 0xd1, (byte) 0xd8, (byte) 0x4c, (byte) 0x32, (byte) 0x44, (byte) 0x3f,
+                    (byte) 0x63, (byte) 0x32, (byte) 0x09, (byte) 0xdb, (byte) 0x8b, (byte) 0x7b,
+                    (byte) 0x30, (byte) 0x58, (byte) 0xc7, (byte) 0xcf, (byte) 0xc3, (byte) 0x44,
+                    (byte) 0xd9, (byte) 0xff, (byte) 0x63, (byte) 0x91, (byte) 0x74, (byte) 0xd8,
+                    (byte) 0x62, (byte) 0x2b, (byte) 0x52, (byte) 0xc8, (byte) 0x82, (byte) 0x9f,
+                    (byte) 0xeb, (byte) 0x22, (byte) 0x5c, (byte) 0xa2, (byte) 0x26, (byte) 0xfe,
+                    (byte) 0x04, (byte) 0x31, (byte) 0x53, (byte) 0x09, (byte) 0xa7, (byte) 0x23,
+                    (byte) 0xe3, (byte) 0x0f, (byte) 0xf8, (byte) 0xe9, (byte) 0x99, (byte) 0xad,
+                    (byte) 0x4b, (byte) 0x23, (byte) 0x07, (byte) 0xfb, (byte) 0xfa, (byte) 0xc3,
+                    (byte) 0x55, (byte) 0x59, (byte) 0xdb, (byte) 0x6b, (byte) 0x71, (byte) 0xdf,
+                    (byte) 0x25, (byte) 0x0f, (byte) 0xaa, (byte) 0xa2, (byte) 0xfa, (byte) 0x28,
+                    (byte) 0x49, (byte) 0x65, (byte) 0x7e, (byte) 0x0b, (byte) 0x74, (byte) 0x30,
+                    (byte) 0xd9, (byte) 0x9a, (byte) 0xfe, (byte) 0x2c, (byte) 0x8c, (byte) 0x67,
+                    (byte) 0x50, (byte) 0x0c, (byte) 0x6d, (byte) 0x4c, (byte) 0xba, (byte) 0x34,
+                    (byte) 0x3b, (byte) 0x0d, (byte) 0x16, (byte) 0x45, (byte) 0x63, (byte) 0x73,
+                    (byte) 0xc2, (byte) 0x9f, (byte) 0xb4, (byte) 0xdd, (byte) 0x6f, (byte) 0xde,
+                    (byte) 0x9d, (byte) 0x71, (byte) 0xbf, (byte) 0x8d, (byte) 0x1b, (byte) 0x79,
+                    (byte) 0xa0, (byte) 0x0a, (byte) 0x66, (byte) 0x7e, (byte) 0x56, (byte) 0x83,
+                    (byte) 0x8f, (byte) 0x3f, (byte) 0x7d, (byte) 0x93, (byte) 0xf6, (byte) 0xc9,
+                    (byte) 0x42, (byte) 0xfc, (byte) 0xc5, (byte) 0xf2, (byte) 0x49, (byte) 0xec};
+
+    @After
+    public void tearDown() {
+        try {
+            if (mPolicyManager != null) {
+                mPolicyManager.removeKeyPair(mContext.getString(R.string.alias));
+                mPolicyManager.clearDeviceOwner();
+                mPolicyManager = null;
+            }
+        } catch (Exception e) {
+            // ignore the exception
+        }
+    }
+
+    @Test
+    public void testCVE_2022_20230() {
+        try {
+            mContext = getApplicationContext();
+            mPolicyManager = new PocPolicyManager(mContext);
+
+            /* Install key pair required to launch KeyChainActivity dialog */
+            KeyFactory kf = KeyFactory.getInstance(mContext.getString(R.string.keyType));
+            PrivateKey privKey = kf.generatePrivate(new PKCS8EncodedKeySpec(PRIVATE_KEY));
+            CertificateFactory cf =
+                    CertificateFactory.getInstance(mContext.getString(R.string.certType));
+            Certificate cert = cf.generateCertificate(new ByteArrayInputStream(USER_CERT));
+            mPolicyManager.installKeyPair(privKey, cert, mContext.getString(R.string.alias));
+
+            /* Launch PocActivity which in turn launches the vulnerable KeyChainActivity */
+            Intent intent = new Intent(mContext, PocActivity.class);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(intent);
+            Intent vulIntent = new Intent(mContext.getString(R.string.actionKeychainActivity));
+            PackageManager pm = mContext.getPackageManager();
+            ResolveInfo ri = pm.resolveActivity(vulIntent, PackageManager.MATCH_DEFAULT_ONLY);
+            assumeNotNull(mContext.getString(R.string.activityNotFoundMsg) + intent, ri);
+            String vulActivityName = ri.activityInfo.name;
+
+            /* Wait for vulnerable text "CVE 2022 20230" to appear */
+            Pattern vulTextPattern = Pattern.compile(mContext.getString(R.string.vulTextPattern),
+                    Pattern.CASE_INSENSITIVE);
+            UiDevice device = UiDevice.getInstance(getInstrumentation());
+            boolean vulTextFound =
+                    device.wait(Until.hasObject(By.text(vulTextPattern)), TIMEOUT_MS);
+
+            /*
+             * Ensure that the vulnerable text "CVE 2022 20230" appeared in the KeyChainActivity
+             * dialog
+             */
+            String activityDump = "";
+            activityDump = device.executeShellCommand(
+                    mContext.getString(R.string.dumpsysActivity) + " " + vulActivityName);
+            Pattern activityPattern = Pattern.compile(mContext.getString(R.string.mResumedTrue),
+                    Pattern.CASE_INSENSITIVE);
+            assumeTrue(mContext.getString(R.string.vulActivityNotRunningError, vulActivityName),
+                    activityPattern.matcher(activityDump).find());
+
+            /*
+             * Fail the test if vulnerable text "CVE 2022 20230" is found in KeyChainActivity dialog
+             */
+            assertFalse(mContext.getString(R.string.failMessage), vulTextFound);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/src/android/security/cts/CVE_2022_20230/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/src/android/security/cts/CVE_2022_20230/PocActivity.java
new file mode 100644
index 0000000..a203f4a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/src/android/security/cts/CVE_2022_20230/PocActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20230;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.security.KeyChain;
+import android.security.KeyChainAliasCallback;
+
+import androidx.annotation.Nullable;
+
+public class PocActivity extends Activity {
+    private static final int PORT_NOT_AVAILABLE = -1;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        KeyChainAliasCallback callback = new KeyChainAliasCallback() {
+            @Override
+            public void alias(@Nullable String alias) {}
+        };
+        KeyChain.choosePrivateKeyAlias(this, callback, null, null, getString(R.string.vulText),
+                PORT_NOT_AVAILABLE, null);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/src/android/security/cts/CVE_2022_20230/PocDeviceAdminReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/src/android/security/cts/CVE_2022_20230/PocDeviceAdminReceiver.java
new file mode 100644
index 0000000..dfe5888
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/src/android/security/cts/CVE_2022_20230/PocDeviceAdminReceiver.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20230;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class PocDeviceAdminReceiver extends DeviceAdminReceiver {
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/src/android/security/cts/CVE_2022_20230/PocPolicyManager.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/src/android/security/cts/CVE_2022_20230/PocPolicyManager.java
new file mode 100644
index 0000000..1887f4f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20230/src/android/security/cts/CVE_2022_20230/PocPolicyManager.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20230;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+
+public class PocPolicyManager {
+    private Context mContext;
+    private DevicePolicyManager mDevicePolicyManager;
+    private ComponentName mComponentName;
+
+    public PocPolicyManager(Context context) {
+        this.mContext = context;
+        mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+        mComponentName = new ComponentName(PocDeviceAdminReceiver.class.getPackage().getName(),
+                PocDeviceAdminReceiver.class.getName());
+    }
+
+    public void clearDeviceOwner() {
+        mDevicePolicyManager.clearDeviceOwnerApp(mContext.getPackageName());
+    }
+
+    public boolean installKeyPair(PrivateKey pkey, Certificate cert, String alias) {
+        return mDevicePolicyManager.installKeyPair(mComponentName, pkey, cert, alias);
+    }
+
+    public boolean removeKeyPair(String alias) {
+        return mDevicePolicyManager.removeKeyPair(mComponentName, alias);
+    }
+}
diff --git a/hostsidetests/silentupdate/AndroidTest.xml b/hostsidetests/silentupdate/AndroidTest.xml
index caad158..8cb9ca1 100644
--- a/hostsidetests/silentupdate/AndroidTest.xml
+++ b/hostsidetests/silentupdate/AndroidTest.xml
@@ -31,6 +31,7 @@
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <!-- Push the test APK so we can test self-update -->
         <option name="push" value="CtsSilentUpdateTestCases.apk->/data/local/tmp/silentupdatetest/CtsSilentUpdateTestCases.apk" />
+        <option name="push" value="CtsSilentUpdateTestCases_mdpi-v4.apk->/data/local/tmp/silentupdatetest/CtsSilentUpdateTestCases_mdpi-v4.apk" />
     </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsSilentUpdateHostTestCases.jar" />
diff --git a/hostsidetests/silentupdate/testapp/Android.bp b/hostsidetests/silentupdate/testapp/Android.bp
index 8bd9cfc..7bd236b 100644
--- a/hostsidetests/silentupdate/testapp/Android.bp
+++ b/hostsidetests/silentupdate/testapp/Android.bp
@@ -19,7 +19,10 @@
 android_test_helper_app {
     name: "CtsSilentUpdateTestCases",
 
-    srcs:  ["src/**/*.java", "src/**/*.kt"],
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
 
     static_libs: [
         "compatibility-device-util-axt",
@@ -31,6 +34,9 @@
         "Nene",
     ],
     sdk_version: "test_current",
+    package_splits: [
+        "mdpi-v4",
+    ],
     test_suites: [
         "cts",
         "general-tests",
@@ -40,5 +46,5 @@
         ":SilentInstallCurrent",
         ":SilentInstallR",
         ":SilentInstallQ",
-    ]
+    ],
 }
diff --git a/hostsidetests/silentupdate/testapp/src/com/android/tests/silentupdate/SilentUpdateTests.java b/hostsidetests/silentupdate/testapp/src/com/android/tests/silentupdate/SilentUpdateTests.java
index 8599bc9..c9ef3df 100644
--- a/hostsidetests/silentupdate/testapp/src/com/android/tests/silentupdate/SilentUpdateTests.java
+++ b/hostsidetests/silentupdate/testapp/src/com/android/tests/silentupdate/SilentUpdateTests.java
@@ -155,8 +155,8 @@
                 .putLong("lastUpdateTime", lastUpdateTime)
                 .commit();
         commit(fileSupplier(
-                "/data/local/tmp/silentupdatetest/CtsSilentUpdateTestCases.apk"),
-                false /* requireUserAction */, true /* dontKillApp */);
+                "/data/local/tmp/silentupdatetest/CtsSilentUpdateTestCases_mdpi-v4.apk"),
+                false /* requireUserAction */, INSTALLER_PACKAGE_NAME);
     }
 
     @Test
@@ -266,7 +266,7 @@
     private int install(Supplier<InputStream> apkStreamSupplier, Boolean requireUserAction)
             throws Exception {
         InstallStatusListener isl = commit(apkStreamSupplier, requireUserAction,
-                false /* dontKillApp */);
+                null /* dontKillPackageName */);
         final Intent statusUpdate = isl.getResult();
         final int result =
                 statusUpdate.getIntExtra(PackageInstaller.EXTRA_STATUS, Integer.MIN_VALUE);
@@ -279,16 +279,21 @@
     }
 
     private InstallStatusListener commit(Supplier<InputStream> apkStreamSupplier,
-            Boolean requireUserAction, boolean dontKillApp) throws IOException {
+            Boolean requireUserAction, String dontKillPackageName) throws IOException {
         final Context context = getContext();
         final PackageInstaller installer = context.getPackageManager().getPackageInstaller();
-        SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
+        SessionParams params = new SessionParams(
+                dontKillPackageName == null ? SessionParams.MODE_FULL_INSTALL
+                        : SessionParams.MODE_INHERIT_EXISTING);
         if (requireUserAction != null) {
             params.setRequireUserAction(requireUserAction
                     ? USER_ACTION_REQUIRED
                     : USER_ACTION_NOT_REQUIRED);
         }
-        params.setDontKillApp(dontKillApp);
+        if (dontKillPackageName != null) {
+            params.setAppPackageName(dontKillPackageName);
+            params.setDontKillApp(true);
+        }
         int sessionId = installer.createSession(params);
         Assert.assertEquals("SessionInfo.getRequireUserAction and "
                         + "SessionParams.setRequireUserAction are not equal",
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/appcompatstate/AppCompatStateStatsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/appcompatstate/AppCompatStateStatsTests.java
index e192e72..9648d8c 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/appcompatstate/AppCompatStateStatsTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/appcompatstate/AppCompatStateStatsTests.java
@@ -183,8 +183,9 @@
     private void testAppCompatFlow(String activity, @Nullable String secondActivity,
             boolean switchToOpened, List<AppCompatStateChanged.State>... expectedStatesOptions)
             throws Exception {
-        if (!isOpenedDeviceStateAvailable()) {
-            CLog.i("Device doesn't support OPENED device state.");
+        if (!isDeviceStateAvailable(DEVICE_STATE_OPENED)
+                || !isDeviceStateAvailable(DEVICE_STATE_CLOSED)) {
+            CLog.i("Device doesn't support OPENED or CLOSED device states.");
             return;
         }
 
@@ -238,10 +239,10 @@
         return result;
     }
 
-    private boolean isOpenedDeviceStateAvailable() throws Exception {
+    private boolean isDeviceStateAvailable(int state) throws Exception {
         return Arrays.stream(
                 getDevice().executeShellCommand(CMD_GET_AVAILABLE_DEVICE_STATES).split(","))
                 .map(Integer::valueOf)
-                .anyMatch(state -> state == DEVICE_STATE_OPENED);
+                .anyMatch(availableState -> availableState == state);
     }
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java
index c7feda6..f07f9d3 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java
@@ -61,12 +61,13 @@
     protected void setUp() throws Exception {
         super.setUp();
 
-        mTransformedFromOp.clear();
-        // The hotword op is allowed to all UIDs on TV and Auto devices.
-        if (!(DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)
-                || DeviceUtils.hasFeature(getDevice(), FEATURE_LEANBACK_ONLY))) {
-            mTransformedFromOp.put(APP_OP_RECORD_AUDIO, APP_OP_RECORD_AUDIO_HOTWORD);
-        }
+        // Temporarily commented out until the Trusted Hotword requirement is enforced again.
+        // mTransformedFromOp.clear();
+        // // The hotword op is allowed to all UIDs on TV and Auto devices.
+        // if (!(DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)
+        //         || DeviceUtils.hasFeature(getDevice(), FEATURE_LEANBACK_ONLY))) {
+        //     mTransformedFromOp.put(APP_OP_RECORD_AUDIO, APP_OP_RECORD_AUDIO_HOTWORD);
+        // }
 
         assertThat(mCtsBuild).isNotNull();
         ConfigUtils.removeConfig(getDevice());
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java
index 5671afb..23ffc03 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/lib/ConfigUtils.java
@@ -69,7 +69,8 @@
                 .addAllowedLogSource("AID_SYSTEM")
                 .addAllowedLogSource("AID_BLUETOOTH")
                 // TODO(b/134091167): Fix bluetooth source name issue in Auto platform.
-                .addAllowedLogSource("com.android.bluetooth")
+                .addAllowedLogSource("com.android.bluetooth.services")
+                .addAllowedLogSource("com.google.android.bluetooth.services")
                 .addAllowedLogSource("AID_LMKD")
                 .addAllowedLogSource("AID_MEDIA")
                 .addAllowedLogSource("AID_RADIO")
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/sizecompatrestartbutton/SizeCompatRestartButtonStatsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/sizecompatrestartbutton/SizeCompatRestartButtonStatsTests.java
index b797e68..a6aaebf 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/sizecompatrestartbutton/SizeCompatRestartButtonStatsTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/sizecompatrestartbutton/SizeCompatRestartButtonStatsTests.java
@@ -98,8 +98,9 @@
     }
 
     public void testSizeCompatRestartButtonAppearedButNotClicked() throws Exception {
-        if (!isOpenedDeviceStateAvailable()) {
-            CLog.i("Device doesn't support OPENED device state.");
+        if (!isDeviceStateAvailable(DEVICE_STATE_OPENED)
+                || !isDeviceStateAvailable(DEVICE_STATE_CLOSED)) {
+            CLog.i("Device doesn't support OPENED or CLOSED device states.");
             return;
         }
 
@@ -120,11 +121,10 @@
         assertThat(atom.getEvent()).isEqualTo(Event.APPEARED);
     }
 
-    private boolean isOpenedDeviceStateAvailable() throws Exception {
+    private boolean isDeviceStateAvailable(int state) throws Exception {
         return Arrays.stream(
                 getDevice().executeShellCommand(CMD_GET_AVAILABLE_DEVICE_STATES).split(","))
                 .map(Integer::valueOf)
-                .anyMatch(state -> state == DEVICE_STATE_OPENED);
+                .anyMatch(availableState -> availableState == state);
     }
 }
-
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/wifi/WifiStatsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/wifi/WifiStatsTests.java
index cb3df79..e17b6b8 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/wifi/WifiStatsTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/wifi/WifiStatsTests.java
@@ -42,6 +42,8 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 public class WifiStatsTests extends DeviceTestCase implements IBuildReceiver {
     private IBuildInfo mCtsBuild;
@@ -215,25 +217,29 @@
         DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testWifiScan");
         Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT);
 
-        List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
-        assertThat(data).hasSize(2);
+        List<StatsLog.EventMetricData> metricData = ReportUtils.getEventMetricDataList(getDevice());
+        List<AtomsProto.WifiScanReported> wifiScanAtoms = metricData.stream()
+                .map(eventLog -> eventLog.getAtom().getWifiScanReported())
+                // Disregard interfering scans from other sources.
+                // If this test is run on a device that has a Settings app open that
+                // continuously performs frequent scans, quite often our scans requests
+                // are bundled together and get attributed to the Settings app.
+                .filter(scan -> List.of(
+                                AtomsProto.WifiScanReported.Source.SOURCE_OTHER_APP,
+                                AtomsProto.WifiScanReported.Source.SOURCE_SETTINGS_APP)
+                        .contains(scan.getSource()))
+                .filter(Predicate.not(scan -> scan.getImportance().equals(
+                        AtomsProto.WifiScanReported.Importance.IMPORTANCE_UNKNOWN)))
+                .collect(Collectors.toList());
+        assertThat(wifiScanAtoms).isNotEmpty();
 
-        AtomsProto.WifiScanReported a0 = data.get(0).getAtom().getWifiScanReported();
-        AtomsProto.WifiScanReported a1 = data.get(1).getAtom().getWifiScanReported();
-
-        for (AtomsProto.WifiScanReported a : new AtomsProto.WifiScanReported[]{a0, a1}) {
-            assertThat(a.getResult()).isEqualTo(AtomsProto.WifiScanReported.Result.RESULT_SUCCESS);
-            assertThat(a.getType()).isEqualTo(AtomsProto.WifiScanReported.Type.TYPE_SINGLE);
-            assertThat(a.getSource()).isAnyOf(
-                    // If this test is run on a device that has a Settings app open that
-                    // continuously performs frequent scans, quite often our scans requests
-                    // are bundled together and get attributed to the Settings app.
-                    AtomsProto.WifiScanReported.Source.SOURCE_SETTINGS_APP,
-                    AtomsProto.WifiScanReported.Source.SOURCE_OTHER_APP);
-            assertThat(a.getImportance()).isEqualTo(
+        for (AtomsProto.WifiScanReported scan : wifiScanAtoms) {
+            assertThat(scan.getResult()).isEqualTo(
+                    AtomsProto.WifiScanReported.Result.RESULT_SUCCESS);
+            assertThat(scan.getType()).isEqualTo(AtomsProto.WifiScanReported.Type.TYPE_SINGLE);
+            assertThat(scan.getImportance()).isEqualTo(
                     AtomsProto.WifiScanReported.Importance.IMPORTANCE_FOREGROUND_SERVICE);
-
-            assertThat(a.getScanDurationMillis()).isGreaterThan(0);
+            assertThat(scan.getScanDurationMillis()).isGreaterThan(0);
         }
     }
 
@@ -242,7 +248,7 @@
 
 
         ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
-                AtomsProto.Atom.WIFI_SCAN_STATE_CHANGED_FIELD_NUMBER,  true);
+                AtomsProto.Atom.WIFI_SCAN_STATE_CHANGED_FIELD_NUMBER, true);
         DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testWifiScan");
         Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT);
 
diff --git a/hostsidetests/sustainedperf/Android.bp b/hostsidetests/sustainedperf/Android.bp
index 4d887e1..97e101f 100644
--- a/hostsidetests/sustainedperf/Android.bp
+++ b/hostsidetests/sustainedperf/Android.bp
@@ -30,4 +30,10 @@
         "tradefed",
         "compatibility-host-util",
     ],
+    data: [
+        ":CtsSustainedPerformanceDeviceTestApp",
+        ":CtsSustainedPerformanceTestCases",
+    ],
+    data_device_bins_both: ["dhry"],
+    per_testcase_directory: true,
 }
diff --git a/hostsidetests/wifibroadcasts/AndroidTest.xml b/hostsidetests/wifibroadcasts/AndroidTest.xml
index 8227587..79760f7 100644
--- a/hostsidetests/wifibroadcasts/AndroidTest.xml
+++ b/hostsidetests/wifibroadcasts/AndroidTest.xml
@@ -16,6 +16,7 @@
 <configuration description="Config for CTS WifiBroadcasts host test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="networking" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsWifiBroadcastsDeviceApp.apk" />
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
index 57d60f2..cc8022d3 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
@@ -431,6 +431,8 @@
         assertMuteButtonState(muteButton, /* isMuted */ false);
         // check that next video resumed previous video's mute state
         swipeLeftAndWait();
+        // Wait for 1s before checking Play/Pause button's visibility
+        playPauseButton.waitForExists(1000);
         // check that player controls are visible
         assertPlayerControlsVisible(playPauseButton, muteButton);
         assertMuteButtonState(muteButton, /* isMuted */ false);
@@ -581,6 +583,8 @@
 
     private void setUpAndAssertStickyPlayerControls(UiObject playerView, UiObject playPauseButton,
             UiObject muteButton) throws Exception {
+        // Wait for 1s for player view to exist
+        playerView.waitForExists(1000);
         // Wait for 1s or Play/Pause button to hide
         playPauseButton.waitUntilGone(1000);
         // Click on StyledPlayerView to make the video controls visible
diff --git a/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/app/src/android/app/cts/SystemFeaturesTest.java
index 6a67df8..7764ff7 100644
--- a/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ b/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -381,8 +381,6 @@
                 Sensor.TYPE_RELATIVE_HUMIDITY);
         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HINGE_ANGLE,
                 Sensor.TYPE_HINGE_ANGLE);
-        assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_DYNAMIC_HEAD_TRACKER,
-                Sensor.TYPE_HEAD_TRACKER);
         assertFeatureForSensor(featuresLeft,
                 PackageManager.FEATURE_SENSOR_ACCELEROMETER_LIMITED_AXES,
                 Sensor.TYPE_ACCELEROMETER_LIMITED_AXES);
@@ -398,6 +396,15 @@
         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEADING,
                 Sensor.TYPE_HEADING);
 
+        // Note that FEATURE_SENSOR_DYNAMIC_HEAD_TRACKER requires dynamic sensor discovery, but
+        // dynamic sensor discovery does not require FEATURE_SENSOR_DYNAMIC_HEAD_TRACKER
+        if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_DYNAMIC_HEAD_TRACKER)) {
+            assertTrue("Device declared " + PackageManager.FEATURE_SENSOR_DYNAMIC_HEAD_TRACKER
+                    + " but does not support dynamic sensor discovery",
+                    mSensorManager.isDynamicSensorDiscoverySupported());
+        }
+        featuresLeft.remove(PackageManager.FEATURE_SENSOR_DYNAMIC_HEAD_TRACKER);
+
         /*
          * We have three cases to test for :
          * Case 1:  Device does not have an HRM
diff --git a/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java
index 49ba64b..a6251f5 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java
@@ -109,6 +109,10 @@
 
         mUiBot.assertFillDialogDatasets("Dialog Presentation");
 
+        // Dismiss fill dialog
+        mUiBot.touchOutsideDialog();
+        mUiBot.waitForIdle();
+
         // Click on password field again
         mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
         mUiBot.waitForIdleSync();
@@ -317,6 +321,9 @@
         // Verify IME is not shown
         assertThat(isImeShowing(activity.getRootWindowInsets())).isFalse();
 
+        mUiBot.touchOutsideDialog();
+        mUiBot.waitForIdle();
+
         // Click on username field, and verify dropdown UI is shown
         mUiBot.selectByRelativeIdFromUiDevice(ID_USERNAME);
         mUiBot.waitForIdleSync();
@@ -623,7 +630,7 @@
 
         // Touch outside to cancel the fill dialog, should back to dropdown UI
         mUiBot.touchOutsideDialog();
-        mUiBot.waitForIdleSync();
+        mUiBot.waitForIdle();
 
         mUiBot.assertDatasets("Dropdown Presentation");
         assertMockImeStatus(activity, true);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/dropdown/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/dropdown/LoginActivityTest.java
index 34e1eb1..9cd6d64 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/dropdown/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/dropdown/LoginActivityTest.java
@@ -1524,7 +1524,7 @@
                 mUiBot.pressHome();
                 break;
             case TOUCH_OUTSIDE:
-                mUiBot.assertShownByText(expectedMessage).click();
+                mUiBot.touchOutsideSaveDialog();
                 break;
             default:
                 throw new IllegalArgumentException("invalid dismiss type: " + dismissType);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/saveui/AutofillSaveDialogTest.java b/tests/autofillservice/src/android/autofillservice/cts/saveui/AutofillSaveDialogTest.java
index 05c42c9..f52f94a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/saveui/AutofillSaveDialogTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/saveui/AutofillSaveDialogTest.java
@@ -17,6 +17,7 @@
 package android.autofillservice.cts.saveui;
 
 import static android.autofillservice.cts.testcore.Helper.ID_USERNAME;
+import static android.autofillservice.cts.testcore.Helper.assertActivityShownInBackground;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_USERNAME;
 
 import android.autofillservice.cts.activities.LoginActivity;
@@ -74,7 +75,7 @@
         startActivityWithFlag(SimpleAfterLoginActivity.getCurrentActivity(),
                 SimpleBeforeLoginActivity.class,
                 Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
-        mUiBot.assertShownByRelativeId(SimpleBeforeLoginActivity.ID_BEFORE_LOGIN);
+        assertActivityShownInBackground(SimpleBeforeLoginActivity.class);
 
         // Verify save ui dialog.
         mUiBot.assertSaveShowing(SAVE_DATA_TYPE_USERNAME);
@@ -112,7 +113,7 @@
         // Start SimpleAfterLoginActivity with CLEAR_TASK and NEW_TASK after login activity.
         startActivityWithFlag(loginActivity, SimpleAfterLoginActivity.class,
                 Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
-        mUiBot.assertShownByRelativeId(SimpleAfterLoginActivity.ID_AFTER_LOGIN);
+        assertActivityShownInBackground(SimpleAfterLoginActivity.class);
 
         // Verify save ui dialog.
         mUiBot.assertSaveShowing(SAVE_DATA_TYPE_USERNAME);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/saveui/PreSimpleSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/saveui/PreSimpleSaveActivityTest.java
index 0ee330c..1f7d79e 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/saveui/PreSimpleSaveActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/saveui/PreSimpleSaveActivityTest.java
@@ -18,8 +18,8 @@
 import static android.autofillservice.cts.activities.LoginActivity.ID_USERNAME_CONTAINER;
 import static android.autofillservice.cts.activities.PreSimpleSaveActivity.ID_PRE_INPUT;
 import static android.autofillservice.cts.activities.SimpleSaveActivity.ID_INPUT;
-import static android.autofillservice.cts.activities.SimpleSaveActivity.ID_LABEL;
 import static android.autofillservice.cts.testcore.Helper.ID_STATIC_TEXT;
+import static android.autofillservice.cts.testcore.Helper.assertActivityShownInBackground;
 import static android.autofillservice.cts.testcore.Helper.assertTextAndValue;
 import static android.autofillservice.cts.testcore.Helper.findAutofillIdByResourceId;
 import static android.autofillservice.cts.testcore.Helper.findNodeByResourceId;
@@ -89,7 +89,7 @@
         mActivity.syncRunOnUiThread(() -> mActivity.mSubmit.performClick());
 
         // Make sure post-save activity is shown...
-        mUiBot.assertShownByRelativeId(ID_INPUT);
+        assertActivityShownInBackground(SimpleSaveActivity.class);
 
         // Tap the link.
         final UiObject2 saveUi = assertSaveUiWithLinkIsShown(SAVE_DATA_TYPE_PASSWORD);
@@ -147,7 +147,7 @@
         mActivity.syncRunOnUiThread(() -> mActivity.mSubmit.performClick());
 
         // Make sure post-save activity is shown...
-        mUiBot.assertShownByRelativeId(ID_INPUT);
+        assertActivityShownInBackground(SimpleSaveActivity.class);
 
         // Tap the link.
         final UiObject2 saveUi = assertSaveUiWithLinkIsShown(SAVE_DATA_TYPE_PASSWORD);
@@ -166,7 +166,7 @@
         // ...instead, do something to dismiss it:
         switch (action) {
             case TOUCH_OUTSIDE:
-                mUiBot.assertShownByRelativeId(ID_LABEL).longClick();
+                mUiBot.touchOutsideSaveDialog();
                 break;
             case TAP_NO_ON_SAVE_UI:
                 mUiBot.saveForAutofill(saveUi2, false);
@@ -205,7 +205,7 @@
         newActivty.syncRunOnUiThread(() -> newActivty.mCommit.performClick());
 
         // Make sure post-save activity is shown...
-        mUiBot.assertShownByRelativeId(ID_INPUT);
+        assertActivityShownInBackground(SimpleSaveActivity.class);
 
         // Save it...
         mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_EMAIL_ADDRESS);
@@ -238,7 +238,7 @@
         mActivity.syncRunOnUiThread(() -> mActivity.mSubmit.performClick());
 
         // Make sure post-save activity is shown...
-        mUiBot.assertShownByRelativeId(ID_INPUT);
+        assertActivityShownInBackground(SimpleSaveActivity.class);
 
         // Tap the link.
         final UiObject2 saveUi = assertSaveUiWithLinkIsShown(SAVE_DATA_TYPE_PASSWORD);
@@ -300,7 +300,7 @@
         tapSaveUiLink(saveUi);
 
         // Make sure new activity is shown...
-        WelcomeActivity.assertShowingDefaultMessage(mUiBot);
+        assertActivityShownInBackground(WelcomeActivity.class);
 
         // Save UI should be showing as well, since Trampoline finished.
         mUiBot.assertSaveShowing(SAVE_DATA_TYPE_PASSWORD);
@@ -310,7 +310,7 @@
         mUiBot.pressBack();
         // second BACK cancel WelcomeActivity
         mUiBot.pressBack();
-        mUiBot.assertShownByRelativeId(ID_INPUT);
+        assertActivityShownInBackground(SimpleSaveActivity.class);
 
         // Now triggers a new session in the new activity (SaveActivity) and do business as usual...
         sReplier.addResponse(new CannedFillResponse.Builder()
@@ -327,7 +327,7 @@
         newActivty.setTextAndWaitTextChange(/* input= */ "42", /* password= */  null);
         newActivty.syncRunOnUiThread(() -> newActivty.mCommit.performClick());
         // Make sure post-save activity is shown...
-        mUiBot.assertShownByRelativeId(ID_INPUT);
+        assertActivityShownInBackground(SimpleSaveActivity.class);
 
         // Save it...
         mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_EMAIL_ADDRESS);
@@ -372,7 +372,7 @@
         mActivity.syncRunOnUiThread(() -> mActivity.mSubmit.performClick());
 
         // Make sure post-save activity is shown...
-        mUiBot.assertShownByRelativeId(ID_INPUT);
+        assertActivityShownInBackground(SimpleSaveActivity.class);
 
         // Tap the link.
         final UiObject2 saveUi;
diff --git a/tests/autofillservice/src/android/autofillservice/cts/saveui/SimpleSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/saveui/SimpleSaveActivityTest.java
index b06a187..9762456 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/saveui/SimpleSaveActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/saveui/SimpleSaveActivityTest.java
@@ -18,13 +18,13 @@
 import static android.autofillservice.cts.activities.LoginActivity.ID_USERNAME_CONTAINER;
 import static android.autofillservice.cts.activities.SimpleSaveActivity.ID_COMMIT;
 import static android.autofillservice.cts.activities.SimpleSaveActivity.ID_INPUT;
-import static android.autofillservice.cts.activities.SimpleSaveActivity.ID_LABEL;
 import static android.autofillservice.cts.activities.SimpleSaveActivity.ID_PASSWORD;
 import static android.autofillservice.cts.activities.SimpleSaveActivity.TEXT_LABEL;
 import static android.autofillservice.cts.testcore.AntiTrimmerTextWatcher.TRIMMER_PATTERN;
 import static android.autofillservice.cts.testcore.Helper.ID_STATIC_TEXT;
 import static android.autofillservice.cts.testcore.Helper.ID_USERNAME;
 import static android.autofillservice.cts.testcore.Helper.LARGE_STRING;
+import static android.autofillservice.cts.testcore.Helper.assertActivityShownInBackground;
 import static android.autofillservice.cts.testcore.Helper.assertTextAndValue;
 import static android.autofillservice.cts.testcore.Helper.assertTextValue;
 import static android.autofillservice.cts.testcore.Helper.findAutofillIdByResourceId;
@@ -527,7 +527,7 @@
         startActivityOnNewTask(LoginActivity.class);
 
         // Make sure LoginActivity started...
-        mUiBot.assertShownByRelativeId(ID_USERNAME_CONTAINER);
+        assertActivityShownInBackground(LoginActivity.class);
 
         // Set expectations.
         sReplier.addResponse(new CannedFillResponse.Builder()
@@ -715,13 +715,6 @@
         dismissSaveTest(DismissType.TOUCH_OUTSIDE);
     }
 
-    @Presubmit
-    @Test
-    public void testDismissSave_byFocusingOutside() throws Exception {
-        startActivity();
-        dismissSaveTest(DismissType.FOCUS_OUTSIDE);
-    }
-
     private void dismissSaveTest(DismissType dismissType) throws Exception {
         // Set service.
         enableService();
@@ -751,11 +744,7 @@
                 mUiBot.pressHome();
                 break;
             case TOUCH_OUTSIDE:
-                mUiBot.assertShownByText(TEXT_LABEL).click();
-                break;
-            case FOCUS_OUTSIDE:
-                mActivity.syncRunOnUiThread(() -> mActivity.mLabel.requestFocus());
-                mUiBot.assertShownByText(TEXT_LABEL).click();
+                mUiBot.touchOutsideSaveDialog();
                 break;
             default:
                 throw new IllegalArgumentException("invalid dismiss type: " + dismissType);
@@ -919,7 +908,7 @@
                 throw new IllegalArgumentException("invalid type: " + type);
         }
         // Make sure previous activity is back...
-        mUiBot.assertShownByRelativeId(ID_INPUT);
+        assertActivityShownInBackground(SimpleSaveActivity.class);
 
         // ... and tap save.
         final UiObject2 newSaveUi = assertSaveUiWithLinkIsShown(SAVE_DATA_TYPE_GENERIC);
@@ -969,7 +958,7 @@
         // Tap back to restore the Save UI...
         mUiBot.pressBack();
         // Make sure previous activity is back...
-        mUiBot.assertShownByRelativeId(ID_LABEL);
+        assertActivityShownInBackground(SimpleSaveActivity.class);
 
         // ...but don't tap it...
         final UiObject2 saveUi2 = mUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
@@ -977,7 +966,7 @@
         // ...instead, do something to dismiss it:
         switch (action) {
             case TOUCH_OUTSIDE:
-                mUiBot.assertShownByRelativeId(ID_LABEL).longClick();
+                mUiBot.touchOutsideSaveDialog();
                 break;
             case TAP_NO_ON_SAVE_UI:
                 mUiBot.saveForAutofill(saveUi2, false);
@@ -1167,7 +1156,7 @@
         tapSaveUiLink(saveUi);
 
         // Make sure new activity is shown...
-        WelcomeActivity.assertShowingDefaultMessage(mUiBot);
+        assertActivityShownInBackground(WelcomeActivity.class);
 
         // Save UI should be showing as well, since Trampoline finished.
         mUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
@@ -1176,7 +1165,7 @@
         mUiBot.pressBack();
         // Go back and make sure it's showing the right activity.
         mUiBot.pressBack();
-        mUiBot.assertShownByRelativeId(ID_LABEL);
+        assertActivityShownInBackground(SimpleSaveActivity.class);
 
         // Now start a new session.
         sReplier.addResponse(new CannedFillResponse.Builder()
@@ -1892,7 +1881,7 @@
         mUiBot.waitForIdle();
 
         // Make sure previous activity is back...
-        mUiBot.assertShownByRelativeId(ID_INPUT);
+        assertActivityShownInBackground(SimpleSaveActivity.class);
 
         // ... and tap save.
         final UiObject2 newSaveUi = mUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/DismissType.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/DismissType.java
index 97a053a..cdf774e 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/testcore/DismissType.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/DismissType.java
@@ -25,5 +25,4 @@
     BACK_BUTTON,
     HOME_BUTTON,
     TOUCH_OUTSIDE,
-    FOCUS_OUTSIDE
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
index c9d4fa6..3a40ca9 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
@@ -78,6 +78,8 @@
 import androidx.annotation.Nullable;
 import androidx.autofill.inline.v1.InlineSuggestionUi;
 import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
+import androidx.test.runner.lifecycle.Stage;
 
 import com.android.compatibility.common.util.BitmapUtils;
 import com.android.compatibility.common.util.DeviceConfigStateManager;
@@ -89,6 +91,8 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -1708,6 +1712,25 @@
                 });
     }
 
+    /**
+     * Make sure the activity that the name is clazz resumed.
+     */
+    public static void assertActivityShownInBackground(Class<?> clazz) throws Exception {
+        Timeouts.UI_TIMEOUT.run("activity is not resumed: " + clazz, () -> {
+            ArrayList<Boolean> result = new ArrayList<>();
+            InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+                final Collection<Activity> stage = ActivityLifecycleMonitorRegistry.getInstance()
+                        .getActivitiesInStage(Stage.RESUMED);
+                for (Activity act : stage) {
+                    if (act.getClass().equals(clazz)) {
+                        result.add(Boolean.TRUE);
+                    }
+                }
+            });
+            return result.isEmpty() ? null : Boolean.TRUE;
+        });
+    }
+
     private Helper() {
         throw new UnsupportedOperationException("contain static methods only");
     }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/UiBot.java
index 134e0c0..73639c0 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/testcore/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/UiBot.java
@@ -1374,7 +1374,16 @@
     public void touchOutsideDialog() throws Exception {
         Log.v(TAG, "touchOutsideDialog()");
         final UiObject2 picker = findFillDialogPicker();
-        mDevice.click(1, picker.getVisibleBounds().top - 1);
+        mDevice.click(1, picker.getVisibleBounds().top / 2);
+    }
+
+    /**
+     * Touch outside the fill dialog.
+     */
+    public void touchOutsideSaveDialog() throws Exception {
+        Log.v(TAG, "touchOutsideSaveDialog()");
+        final UiObject2 picker = waitForObject(SAVE_UI_SELECTOR, SAVE_TIMEOUT);
+        mDevice.click(1, picker.getVisibleBounds().top / 2);
     }
 
     /**
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
index 7507d0a..11b5fd4 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
@@ -1177,6 +1177,7 @@
     @Test
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
     @RequireDoesNotHaveFeature(FEATURE_MANAGED_USERS)
+    @RequireFeature(FEATURE_DEVICE_ADMIN)
     public void checkProvisioningPreCondition_actionPO_withoutManagedUserFeature_returnsManagedUsersNotSupported() {
         assertThat(
                 sDevicePolicyManager.checkProvisioningPrecondition(
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index 9920ad2..39c3d3e 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -418,7 +418,8 @@
         <activity android:name="android.server.wm.WindowInputTests$TestActivity" />
 
         <activity android:name="android.server.wm.ActivityRecordInputSinkTestsActivity"
-                  android:exported="true"/>
+            android:theme="@android:style/Theme.Material.NoActionBar"
+            android:exported="true"/>
 
         <service android:name="android.view.cts.surfacevalidator.LocalMediaProjectionService"
              android:foregroundServiceType="mediaProjection"
diff --git a/tests/framework/base/windowmanager/res/values/styles.xml b/tests/framework/base/windowmanager/res/values/styles.xml
index 9d6e9dc..2945940 100644
--- a/tests/framework/base/windowmanager/res/values/styles.xml
+++ b/tests/framework/base/windowmanager/res/values/styles.xml
@@ -49,6 +49,9 @@
     <style name="Theme.EdgeExtensions" parent="Theme.WhiteBackground">
         <item name="android:statusBarColor">@android:color/transparent</item>
         <item name="android:navigationBarColor">@android:color/transparent</item>
+        <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
+        <item name="android:windowTranslucentStatus">true</item>
+        <item name="android:windowTranslucentNavigation">true</item>
     </style>
     <style name="Theme.TranslucentBars" parent="@android:style/Theme.Material.NoActionBar">
         <item name="android:statusBarColor">@android:color/transparent</item>
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
index 31bb8bf..7e87fb4 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
@@ -304,7 +304,7 @@
                 EdgeExtensionActivity.class, extras);
         final Rect appBounds = getTopAppBounds();
         assertColorChangeXIndex(screenshots,
-                (appBounds.left + appBounds.right) / 4 * 3, testBounds);
+                appBounds.left + (appBounds.right - appBounds.left) * 3 / 4, testBounds);
     }
 
     /**
@@ -355,7 +355,7 @@
                 EdgeExtensionActivity.class, extras);
         final Rect appBounds = getTopAppBounds();
         assertColorChangeXIndex(screenshots,
-                (appBounds.left + appBounds.right) / 4, testBounds);
+            appBounds.left + (appBounds.right - appBounds.left) / 4, testBounds);
     }
 
     /**
@@ -422,9 +422,7 @@
         boolean isTransitioning;
         do {
             getWmState().computeState();
-            isTransitioning =
-                    getWmState().getDefaultDisplayLastTransition().equals("TRANSIT_ACTIVITY_OPEN")
-                    && getWmState().getDefaultDisplayAppTransitionState()
+            isTransitioning = getWmState().getDefaultDisplayAppTransitionState()
                             .equals("APP_STATE_RUNNING");
             SystemClock.sleep(10);
         } while (!isTransitioning);
@@ -530,11 +528,15 @@
     }
 
     private boolean arrayEquals(float[] array1, float[] array2) {
+        return arrayEquals(array1, array2, COLOR_VALUE_VARIANCE_TOLERANCE);
+    }
+
+    private boolean arrayEquals(float[] array1, float[] array2, float varianceTolerance) {
         if (array1.length != array2.length) {
             return true;
         }
         for (int i = 0; i < array1.length; i++) {
-            if (Math.abs(array1[i] - array2[i]) > COLOR_VALUE_VARIANCE_TOLERANCE) {
+            if (Math.abs(array1[i] - array2[i]) > varianceTolerance) {
                 return true;
             }
         }
@@ -593,13 +595,6 @@
 
     private AssertionResult assertColorChangeXIndex(Bitmap screen, int xIndex,
             TestBounds testBounds) {
-        final int colorChangeXIndex = getColorChangeXIndex(screen);
-
-        if (xIndex != colorChangeXIndex) {
-            return new AssertionResult(true, "Expected color to change at x index " + xIndex
-                    + " instead of " + colorChangeXIndex);
-        }
-
         // The activity we are extending is a half red, half blue.
         // We are scaling the activity in the animation so if the extension doesn't work we should
         // have a blue, then red, then black section, and if it does work we should see on a blue,
@@ -631,9 +626,13 @@
                     sRgbColor = rawColor;
                 }
 
+                // Increase tolerance on edge pixels since blending might occur there
+                final float varianceTolerance = Math.abs(x - xIndex) <= 1
+                        ? 0.5f : COLOR_VALUE_VARIANCE_TOLERANCE;
                 if (arrayEquals(new float[]{
                                 expectedColor.red(), expectedColor.green(), expectedColor.blue()},
-                        new float[]{sRgbColor.red(), sRgbColor.green(), sRgbColor.blue()})) {
+                        new float[]{sRgbColor.red(), sRgbColor.green(), sRgbColor.blue()},
+                        varianceTolerance)) {
                     return new ColorCheckResult(new Point(x, y), expectedColor, sRgbColor);
                 }
             }
@@ -642,25 +641,6 @@
         return AssertionResult.SUCCESS;
     }
 
-    private int getColorChangeXIndex(Bitmap screen) {
-        // Look for color changing index at middle of app
-        final int y =
-                (getTopAppBounds().top + getTopAppBounds().bottom) / 2;
-
-        Color prevColor = screen.getColor(0, y)
-                .convert(ColorSpace.get(ColorSpace.Named.SRGB));
-        for (int x = 0; x < screen.getWidth(); x++) {
-            final Color c = screen.getColor(x, y)
-                    .convert(ColorSpace.get(ColorSpace.Named.SRGB));
-
-            if (!colorsEqual(prevColor, c)) {
-                return x;
-            }
-        }
-
-        return -1;
-    }
-
     private boolean colorsEqual(Color c1, Color c2) {
         return almostEquals(c1.red(), c2.red(), COLOR_VALUE_VARIANCE_TOLERANCE)
                 && almostEquals(c1.green(), c2.green(), COLOR_VALUE_VARIANCE_TOLERANCE)
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
index a667c96..6e9d910 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
@@ -24,6 +24,7 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.Activity;
 import android.content.ComponentName;
@@ -62,6 +63,7 @@
      */
     @Test
     public void testCreateTaskFragment() {
+        assumeTrue("MultiWindow is not supported.", supportsMultiWindow());
         mWmState.computeState(mOwnerActivityName);
         Task parentTask = mWmState.getRootTask(mOwnerActivity.getTaskId());
         final int originalTaskFragCount = parentTask.getTaskFragments().size();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
index 669594d..e73ae81 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
@@ -756,8 +756,16 @@
 
         final ExecutorService executor = Executors.newSingleThreadExecutor();
         boolean[] securityExceptionCaught = new boolean[1];
+        Exception[] illegalArgumentException = new Exception[1];
         executor.execute(() -> {
-            mInstrumentation.sendPointerSync(eventDown);
+            try {
+                mInstrumentation.sendPointerSync(eventDown);
+            } catch (IllegalArgumentException e) {
+                // InputManagerService throws IllegalArgumentException when input target mismatch.
+                // Store the exception, and raise test failure later to avoid cts thread crash.
+                illegalArgumentException[0] = e;
+                return;
+            }
             for (int i = 0; i < 20; i++) {
                 final long eventTime = SystemClock.uptimeMillis();
                 final MotionEvent eventMove = MotionEvent.obtain(
@@ -766,8 +774,13 @@
                     mInstrumentation.sendPointerSync(eventMove);
                 } catch (SecurityException e) {
                     securityExceptionCaught[0] = true;
+                    return;
+                } catch (IllegalArgumentException e) {
+                    illegalArgumentException[0] = e;
+                    return;
                 }
             }
+
         });
 
         // Launch another activity, should not crash the process.
@@ -783,6 +796,11 @@
             // so the failure is thrown in the test thread.
             fail("Should be allowed to inject event.");
         }
+
+        if (illegalArgumentException[0] != null) {
+            fail("Failed to inject event due to input target mismatch: "
+                    + illegalArgumentException[0].getMessage());
+        }
     }
 
     private void waitForWindow(String name) {
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
index 6395679..8cc0b8e 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
@@ -582,8 +582,8 @@
                     NOT_EXPECT_TIMEOUT);
 
             final int touchSlop = getTouchSlop();
-            final int startX = 50;
-            final int startY = 50;
+            final int startX = editText.getWidth() / 2;
+            final int startY = editText.getHeight() / 2;
             final int endX = startX + 2 * touchSlop;
             final int endY = startY + 2 * touchSlop;
             final int number = 5;
diff --git a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
index a687b6b..a8d7947 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
@@ -1036,6 +1036,7 @@
     }
 
     @Test
+    @AppModeFull(reason = "Instant apps can't hold INTERACT_ACROSS_USERS permission")
     public void testAddProviderRequestListener() throws Exception {
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .adoptShellPermissionIdentity(Manifest.permission.LOCATION_HARDWARE);
diff --git a/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java b/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java
new file mode 100644
index 0000000..990d1de
--- /dev/null
+++ b/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.location.cts.none;
+
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
+
+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.content.pm.PackageManager;
+import android.location.LocationManager;
+import android.os.PackageTagsList;
+import android.os.Process;
+import android.os.UserHandle;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LocationDisabledAppOpsTest {
+
+    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
+    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<String> bypassedNoteOps = new ArrayList<>();
+            List<String> bypassedCheckOps = new ArrayList<>();
+            for (PackageInfo pi : mContext.getPackageManager().getInstalledPackagesAsUser(
+                            0, user.getIdentifier())) {
+                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/media/src/android/mediav2/cts/CodecEncoderValidationTest.java b/tests/media/src/android/mediav2/cts/CodecEncoderValidationTest.java
index 5f17678..932af63 100644
--- a/tests/media/src/android/mediav2/cts/CodecEncoderValidationTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecEncoderValidationTest.java
@@ -142,6 +142,10 @@
         if (!mIsAudio) {
             int colorFormat = mFormats.get(0).getInteger(MediaFormat.KEY_COLOR_FORMAT);
             Assume.assumeTrue(hasSupportForColorFormat(mCodecName, mMime, colorFormat));
+            if (mUseHBD) {
+                Assume.assumeTrue("Codec doesn't support high bit depth profile encoding",
+                        doesCodecSupportHDRProfile(mCodecName, mMime));
+            }
         }
         checkFormatSupport(mCodecName, mMime, true, mFormats, null, CODEC_OPTIONAL);
         setUpSource(inputFile);
diff --git a/tests/media/src/android/mediav2/cts/CodecInfoTest.java b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
index 945a7db..5f9aa09 100644
--- a/tests/media/src/android/mediav2/cts/CodecInfoTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
@@ -91,40 +91,31 @@
 
     /**
      * Tests if the devices on T or later, if decoder for a mediaType supports HDR profiles then
-     * it should be capable of displaying the same
+     * it should be capable of displaying the same. Since HLG profiles can't be distinguished from
+     * default 10-bit profiles, those are excluded from this test.
      */
     @Test
-    @Ignore("TODO(b/228237404) Enable once display capabilities can be queried at codec2 level")
     public void testHDRDisplayCapabilities() {
         Assume.assumeTrue("Test needs Android 13", IS_AT_LEAST_T);
         Assume.assumeTrue("Test is applicable for video codecs", mMediaType.startsWith("video/"));
-        Assume.assumeTrue("Test is applicable for codecs with HDR profiles",
-                mProfileHdrMap.containsKey(mMediaType));
 
-        int[] HdrProfiles = mProfileHdrMap.get(mMediaType);
+        int[] Hdr10Profiles = mProfileHdr10Map.get(mMediaType);
+        int[] Hdr10PlusProfiles = mProfileHdr10PlusMap.get(mMediaType);
+        Assume.assumeTrue("Test is applicable for codecs with HDR10/HDR10+ profiles",
+                Hdr10Profiles != null || Hdr10PlusProfiles != null);
+
         MediaCodecInfo.CodecCapabilities caps = mCodecInfo.getCapabilitiesForType(mMediaType);
 
         for (CodecProfileLevel pl : caps.profileLevels) {
-            if (IntStream.of(HdrProfiles).anyMatch(x -> x == pl.profile)) {
-                if (pl.profile == AV1ProfileMain10 || pl.profile == AVCProfileHigh10 ||
-                        pl.profile == HEVCProfileMain10 || pl.profile == VP9Profile2) {
-                    assertTrue("Advertises support for HLG technology without HLG display",
-                            IntStream.of(DISPLAY_HDR_TYPES).anyMatch(x -> x == HDR_TYPE_HLG));
-                } else if (pl.profile == AV1ProfileMain10HDR10 ||
-                        pl.profile == HEVCProfileMain10HDR10 || pl.profile == VP9Profile2HDR) {
-                    assertTrue(mCodecInfo.getName() + " Advertises support for HDR10 profile " +
-                                    pl.profile + " without HDR10 display",
-                            IntStream.of(DISPLAY_HDR_TYPES).anyMatch(x -> x == HDR_TYPE_HDR10));
-                } else if (pl.profile == AV1ProfileMain10HDR10Plus ||
-                        pl.profile == HEVCProfileMain10HDR10Plus ||
-                        pl.profile == VP9Profile2HDR10Plus) {
-                    assertTrue(mCodecInfo.getName() + " Advertises support for HDR10+ profile " +
-                                    pl.profile + " without HDR10+ display",
-                            IntStream.of(DISPLAY_HDR_TYPES)
-                                    .anyMatch(x -> x == HDR_TYPE_HDR10_PLUS));
-                } else {
-                    fail("Unhandled HDR profile" + pl.profile + " for type " + mMediaType);
-                }
+            boolean isHdr10Profile = Hdr10Profiles != null &&
+                    IntStream.of(Hdr10Profiles).anyMatch(x -> x == pl.profile);
+            boolean isHdr10PlusProfile = Hdr10PlusProfiles != null &&
+                    IntStream.of(Hdr10PlusProfiles).anyMatch(x -> x == pl.profile);
+            // TODO (b/228237404) Once there is a way to query support for HDR10/HDR10+ display at
+            // native level, separate the following to independent checks for HDR10 and HDR10+
+            if (isHdr10Profile || isHdr10PlusProfile) {
+                assertTrue(mCodecInfo.getName() + " Advertises support for HDR10/HDR10+ profile " +
+                        pl.profile + " without any HDR display", DISPLAY_HDR_TYPES.length > 0);
             }
         }
     }
@@ -160,8 +151,8 @@
 
         // COLOR_FormatSurface support is an existing requirement, but we did not
         // test for it before T.  We can not retroactively apply the higher standard to
-        // devices that are already certified, so only test on T or later devices.
-        if (IS_AT_LEAST_T) {
+        // devices that are already certified, so only test on VNDK T or later devices.
+        if (VNDK_IS_AT_LEAST_T) {
             assertFalse(mCodecInfo.getName() + " does not support COLOR_FormatSurface",
                     IntStream.of(caps.colorFormats)
                             .noneMatch(x -> x == COLOR_FormatSurface));
diff --git a/tests/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index 1105799..0368d88 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -32,6 +32,7 @@
 import android.media.MediaFormat;
 import android.os.Build;
 import android.os.PersistableBundle;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.util.Pair;
 import android.view.Display;
@@ -597,6 +598,8 @@
     // TIRAMISU is set correctly
     public static final boolean FIRST_SDK_IS_AT_LEAST_T =
             ApiLevelUtil.isFirstApiAfter(Build.VERSION_CODES.S_V2);
+    public static final boolean VNDK_IS_AT_LEAST_T =
+            SystemProperties.getInt("ro.vndk.version", 0) > Build.VERSION_CODES.S_V2;
     private static final String LOG_TAG = CodecTestBase.class.getSimpleName();
     enum SupportClass {
         CODEC_ALL, // All codecs must support
diff --git a/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java b/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
index c6e0ae6..83cc6f4 100644
--- a/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
+++ b/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
@@ -33,6 +33,7 @@
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
@@ -45,14 +46,15 @@
  * data in compressed YUV format. The output of the decoders is shared with OpenGL
  * as external textures. And OpenGL outputs RGB pixels. The class validates whether
  * the conversion of input YUV to output RGB is in accordance with the chosen color
- * aspects.
+ * aspects. Video files used in the test do not have any color aspects info coded in
+ * the bitstreams
  */
 @RunWith(Parameterized.class)
 public class DecodeGlAccuracyTest extends CodecDecoderTestBase {
-    private final String LOG_TAG = DecodeGlAccuracyTest.class.getSimpleName();
+    private static final String LOG_TAG = DecodeGlAccuracyTest.class.getSimpleName();
 
     // Allowed color tolerance to account for differences in the conversion process
-    private final int ALLOWED_COLOR_DELTA = 8;
+    private static final int ALLOWED_COLOR_DELTA = 8;
 
     // The test video assets were generated with a set of color bars.
     // Depending on the color aspects, the values from OpenGL pbuffer
@@ -64,18 +66,7 @@
     // RGB = Transpose(FLOOR_CLIP_PIXEL(CONV_CSC * (Transpose(YUV) - LVL_OFFSET)))
     // The matrices LVL_OFFSET and CONV_CSC for different color aspects are below.
     //
-    // YUV values in the 8bit color bar test videos
-    //     {{126, 191, 230},
-    //      {98, 104, 204},
-    //      {180, 20, 168},
-    //      {121, 109, 60},
-    //      {114, 179, 172},
-    //      {133, 138, 118},
-    //      {183, 93, 153},
-    //      {203, 20, 33},
-    //      {147, 131, 183},
-    //      {40, 177, 202},
-    //      {170, 82, 96},
+    // YUV values in the 8bit color bar test videos are in COLOR_BARS_YUV below
     //
     // The color conversion matrices (CONV_CSC) for the RGB equation above:
     // MULTIPLY_ROW_WISE_LR = Transpose({255/219, 255/224, 255/224})
@@ -94,8 +85,22 @@
     // LVL_OFFSET_LR = Transpose({16, 128, 128})
     // LVL_OFFSET_FR = Transpose({0, 128, 128})
 
+    private static final int[][] COLOR_BARS_YUV = new int[][]{
+            {126, 191, 230},
+            {98, 104, 204},
+            {180, 20, 168},
+            {121, 109, 60},
+            {114, 179, 172},
+            {133, 138, 118},
+            {183, 93, 153},
+            {203, 20, 33},
+            {147, 131, 183},
+            {40, 177, 202},
+            {170, 82, 96},
+    };
+
     // Reference RGB values for 601 Limited Range
-    private final int[][] mColorBars601LR = new int[][]{
+    private static final int[][] COLOR_BARS_601LR = new int[][]{
             {255, 17, 252},
             {219, 40, 44},
             {255, 196, 0},
@@ -109,7 +114,7 @@
             {127, 219, 82},
     };
     // Reference RGB values for 601 Full Range
-    private final int[][] mColorBars601FR = new int[][]{
+    private static final int[][] COLOR_BARS_601FR = new int[][]{
             {255, 31, 237},
             {204, 51, 55},
             {236, 188, 0},
@@ -123,7 +128,7 @@
             {125, 208, 88},
     };
     // Reference RGB values for 709 Limited Range
-    private final int[][] mColorBars709LR = new int[][]{
+    private static final int[][] COLOR_BARS_709LR = new int[][]{
             {255, 57, 255},
             {234, 57, 42},
             {255, 188, 0},
@@ -137,6 +142,11 @@
             {120, 202, 78},
     };
 
+    // The test videos were generated with the above color bars. Each bar is of width 16.
+    private static final int COLOR_BAR_WIDTH = 16;
+    private static final int COLOR_BAR_OFFSET_X = 8;
+    private static final int COLOR_BAR_OFFSET_Y = 64;
+
     private int[][] mColorBars;
 
     private final String mCompName;
@@ -146,45 +156,46 @@
     private final int mRange;
     private final int mStandard;
     private final int mTransferCurve;
+    private final boolean mUseYuvSampling;
 
     private OutputSurface mEGLWindowOutSurface;
-
-    // The test videos were generated with the above color bars. Each bar is of
-    // width 16.
-    private final int mColorBarWidth = 16;
-    private final int xOffset = 8;
-    private final int yOffset = 64;
     private int mBadFrames = 0;
 
     public DecodeGlAccuracyTest(String decoder, String mediaType, String fileName, int range,
-            int standard, int transfer) {
+            int standard, int transfer, boolean useYuvSampling) {
         super(null, mediaType, null);
         mCompName = decoder;
         mFileName = fileName;
         mRange = range;
         mStandard = standard;
         mTransferCurve = transfer;
+        mUseYuvSampling = useYuvSampling;
 
-        mColorBars = mColorBars601LR;
-        if ((mStandard == MediaFormat.COLOR_STANDARD_BT601_NTSC) &&
-                (mRange == MediaFormat.COLOR_RANGE_LIMITED)) {
-            mColorBars = mColorBars601LR;
-        } else if ((mStandard == MediaFormat.COLOR_STANDARD_BT601_NTSC) &&
-                (mRange == MediaFormat.COLOR_RANGE_FULL)) {
-            mColorBars = mColorBars601FR;
-        } else if ((mStandard == MediaFormat.COLOR_STANDARD_BT709) &&
-                (mRange == MediaFormat.COLOR_RANGE_LIMITED)) {
-            mColorBars = mColorBars709LR;
+        if (!mUseYuvSampling) {
+            mColorBars = COLOR_BARS_601LR;
+            if ((mStandard == MediaFormat.COLOR_STANDARD_BT601_NTSC) &&
+                    (mRange == MediaFormat.COLOR_RANGE_LIMITED)) {
+                mColorBars = COLOR_BARS_601LR;
+            } else if ((mStandard == MediaFormat.COLOR_STANDARD_BT601_NTSC) &&
+                    (mRange == MediaFormat.COLOR_RANGE_FULL)) {
+                mColorBars = COLOR_BARS_601FR;
+            } else if ((mStandard == MediaFormat.COLOR_STANDARD_BT709) &&
+                    (mRange == MediaFormat.COLOR_RANGE_LIMITED)) {
+                mColorBars = COLOR_BARS_709LR;
+            } else {
+                Log.e(LOG_TAG, "Unsupported Color Aspects.");
+            }
         } else {
-            Log.e(LOG_TAG, "Unsupported Color Aspects.");
+            mColorBars = COLOR_BARS_YUV;
         }
     }
 
-    @Parameterized.Parameters(name = "{index}({0}_{1}_{3}_{4}_{5})")
+    @Parameterized.Parameters(name = "{index}({0}_{1}_{3}_{4}_{5}_{6})")
     public static Collection<Object[]> input() {
         final boolean isEncoder = false;
         final boolean needAudio = false;
         final boolean needVideo = true;
+
         final List<Object[]> argsList = Arrays.asList(new Object[][]{
                 // mediaType, asset, range, standard, transfer
                 // 601LR
@@ -255,7 +266,18 @@
 
                 // Note: OpenGL is not required to support 709 FR. So we are not testing it.
         });
-        return CodecTestBase.prepareParamList(argsList, isEncoder, needAudio, needVideo,
+        final List<Object[]> exhaustiveArgsList = new ArrayList<>();
+        for (Object[] arg : argsList) {
+            int argLength = argsList.get(0).length;
+            boolean[] boolStates = {true, false};
+            for (boolean useYuvSampling : boolStates) {
+                Object[] testArgs = new Object[argLength + 1];
+                System.arraycopy(arg, 0, testArgs, 0, argLength);
+                testArgs[argLength] = useYuvSampling;
+                exhaustiveArgsList.add(testArgs);
+            }
+        }
+        return CodecTestBase.prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo,
                 false);
     }
 
@@ -268,8 +290,8 @@
         ByteBuffer pixelBuf = ByteBuffer.allocateDirect(4);
         boolean frameFailed = false;
         for (int i = 0; i < mColorBars.length; i++) {
-            int x = mColorBarWidth * i + xOffset;
-            int y = yOffset;
+            int x = COLOR_BAR_WIDTH * i + COLOR_BAR_OFFSET_X;
+            int y = COLOR_BAR_OFFSET_Y;
             GLES20.glReadPixels(x, y, 1, 1, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixelBuf);
             int r = pixelBuf.get(0) & 0xff;
             int g = pixelBuf.get(1) & 0xff;
@@ -337,7 +359,7 @@
 
         mWidth = format.getInteger(MediaFormat.KEY_WIDTH);
         mHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
-        mEGLWindowOutSurface = new OutputSurface(mWidth, mHeight, false);
+        mEGLWindowOutSurface = new OutputSurface(mWidth, mHeight, false, mUseYuvSampling);
         mSurface = mEGLWindowOutSurface.getSurface();
 
         mCodec = MediaCodec.createByCodecName(mCompName);
diff --git a/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java b/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java
index 31ba0ba..3dd28aa 100644
--- a/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java
+++ b/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java
@@ -95,11 +95,23 @@
     @SmallTest
     @Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
     public void testHDRMetadata() throws IOException, InterruptedException {
+        int[] Hdr10Profiles = mProfileHdr10Map.get(mMime);
+        Assume.assumeNotNull("Test is only applicable to codecs that have HDR10 profiles",
+                Hdr10Profiles);
         MediaFormat format = setUpSource(mTestFile);
         mExtractor.release();
         ArrayList<MediaFormat> formats = new ArrayList<>();
         formats.add(format);
+
+        // When HDR metadata isn't present in the container, but included in the bitstream,
+        // extractors may not be able to populate HDR10/HDR10+ profiles correctly.
+        // In such cases, override the profile
+        if (mHDRStaticInfoContainer == null && mHDRStaticInfoStream != null) {
+            int profile = Hdr10Profiles[0];
+            format.setInteger(MediaFormat.KEY_PROFILE, profile);
+        }
         Assume.assumeTrue(areFormatsSupported(mCodecName, mMime, formats));
+
         if (mHDRStaticInfoContainer != null) {
             validateHDRStaticMetaData(format, mHDRStaticInfoContainer);
         }
diff --git a/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java b/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
index e9a74fa..9c722c4 100644
--- a/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
+++ b/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
@@ -20,8 +20,11 @@
 import android.media.MediaCodecList;
 import android.media.MediaFormat;
 import android.media.MediaMuxer;
+import android.opengl.GLES20;
 import android.os.Build;
 import android.util.Log;
+import android.util.Pair;
+import android.view.Surface;
 
 import androidx.test.filters.SmallTest;
 
@@ -39,7 +42,9 @@
 import java.util.Collection;
 import java.util.List;
 
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_Format32bitABGR2101010;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
@@ -54,22 +59,31 @@
     private int mStandard;
     private int mTransferCurve;
     private boolean mUseHighBitDepth;
+    private boolean mSurfaceMode;
+
+    private Surface mInpSurface;
+    private EGLWindowSurface mEGLWindowInpSurface;
     private MediaFormat mConfigFormat;
 
     private MediaMuxer mMuxer;
     private int mTrackID = -1;
 
+    private int mLatency;
+    private boolean mReviseLatency;
+
     private ArrayList<String> mCheckESList = new ArrayList<>();
 
     private static boolean sIsAtLeastR = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
 
     public EncoderColorAspectsTest(String encoderName, String mime, int width, int height,
-            int range, int standard, int transferCurve, boolean useHighBitDepth) {
+            int range, int standard, int transferCurve, boolean useHighBitDepth,
+            boolean surfaceMode) {
         super(encoderName, mime, new int[]{64000}, new int[]{width}, new int[]{height});
         mRange = range;
         mStandard = standard;
         mTransferCurve = transferCurve;
         mUseHighBitDepth = useHighBitDepth;
+        mSurfaceMode = surfaceMode;
         mWidth = width;
         mHeight = height;
         setUpParams(1);
@@ -113,7 +127,10 @@
                         if (!stringArgsList.contains(currentObject)) {
                             exhaustiveArgsList
                                     .add(new Object[]{mediaType, 176, 144, range, standard,
-                                            transfer, useHighBitDepth});
+                                            transfer, useHighBitDepth, false});
+                            exhaustiveArgsList
+                                    .add(new Object[]{mediaType, 176, 144, range, standard,
+                                            transfer, useHighBitDepth, true});
                             stringArgsList.add(currentObject);
                         }
                     }
@@ -122,7 +139,7 @@
         }
     }
 
-    @Parameterized.Parameters(name = "{index}({0}_{1}_{4}_{5}_{6})")
+    @Parameterized.Parameters(name = "{index}({0}_{1}_{4}_{5}_{6}_{7}_{8})")
     public static Collection<Object[]> input() {
         final boolean isEncoder = true;
         final boolean needAudio = false;
@@ -170,19 +187,109 @@
         return CodecTestBase
                 .prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
     }
+    private long computePresentationTime(int frameIndex) {
+        return frameIndex * 1000000 / mFrameRate;
+    }
+
+    private void generateSurfaceFrame() {
+        GLES20.glViewport(0, 0, mWidth, mHeight);
+        GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
+        GLES20.glClearColor(128.0f, 128.0f, 128.0f, 1.0f);
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+    }
+
+    private void tryEncoderOutput(long timeOutUs) throws InterruptedException {
+        if (!mAsyncHandle.hasSeenError() && !mSawOutputEOS) {
+            int retry = 0;
+            while (mReviseLatency) {
+                if (mAsyncHandle.hasOutputFormatChanged()) {
+                    mReviseLatency = false;
+                    int actualLatency = mAsyncHandle.getOutputFormat()
+                            .getInteger(MediaFormat.KEY_LATENCY, mLatency);
+                    if (mLatency < actualLatency) {
+                        mLatency = actualLatency;
+                        return;
+                    }
+                } else {
+                    if (retry > RETRY_LIMIT) {
+                        throw new InterruptedException(
+                                "did not receive output format changed for encoder after " +
+                                        Q_DEQ_TIMEOUT_US * RETRY_LIMIT + " us");
+                    }
+                    Thread.sleep(Q_DEQ_TIMEOUT_US / 1000);
+                    retry++;
+                }
+            }
+            Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getOutput();
+            if (element != null) {
+                dequeueOutput(element.first, element.second);
+            }
+        }
+    }
+
+    void queueEOS() throws InterruptedException {
+        if (!mSurfaceMode) {
+            super.queueEOS();
+        } else {
+            if (!mAsyncHandle.hasSeenError() && !mSawInputEOS) {
+                mCodec.signalEndOfInputStream();
+                mSawInputEOS = true;
+                if (ENABLE_LOGS) Log.d(LOG_TAG, "signalled end of stream");
+            }
+        }
+    }
+
+    void doWork(int frameLimit) throws IOException, InterruptedException {
+        if (!mSurfaceMode) {
+            super.doWork(frameLimit);
+        } else {
+            while (!mAsyncHandle.hasSeenError() && !mSawInputEOS &&
+                    mInputCount < frameLimit) {
+                if (mInputCount - mOutputCount > mLatency) {
+                    tryEncoderOutput(CodecTestBase.Q_DEQ_TIMEOUT_US);
+                }
+                mEGLWindowInpSurface.makeCurrent();
+                generateSurfaceFrame();
+                mEGLWindowInpSurface
+                        .setPresentationTime(computePresentationTime(mInputCount) * 1000);
+                if (ENABLE_LOGS) Log.d(LOG_TAG, "inputSurface swapBuffers");
+                mEGLWindowInpSurface.swapBuffers();
+                mInputCount++;
+            }
+        }
+    }
 
     @SmallTest
     @Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
     public void testColorAspects() throws IOException, InterruptedException {
         Assume.assumeTrue("Test introduced with Android 11", sIsAtLeastR);
-        String inputTestFile = mInputFile;
         if (mUseHighBitDepth) {
-            Assume.assumeTrue(hasSupportForColorFormat(mCodecName, mMime, COLOR_FormatYUVP010));
-            mConfigFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUVP010);
-            mBytesPerSample = 2;
-            inputTestFile = INPUT_VIDEO_FILE_HBD;
+            // Check if encoder is capable of supporting HDR profiles.
+            // Previous check doesn't verify this as profile isn't set in the format
+            Assume.assumeTrue(mCodecName + " doesn't support HDR encoding",
+                    CodecTestBase.doesCodecSupportHDRProfile(mCodecName, mMime));
+
+            // Encoder surface mode tests are to be enabled only if an encoder supports
+            // COLOR_Format32bitABGR2101010
+            if (mSurfaceMode) {
+                Assume.assumeTrue(mCodecName + " doesn't support RGBA1010102",
+                        hasSupportForColorFormat(mCodecName, mMime, COLOR_Format32bitABGR2101010));
+            }
         }
-        setUpSource(inputTestFile);
+
+        if (mSurfaceMode) {
+            mConfigFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatSurface);
+        } else {
+            String inputTestFile = mInputFile;
+            if (mUseHighBitDepth) {
+                Assume.assumeTrue(hasSupportForColorFormat(mCodecName, mMime, COLOR_FormatYUVP010));
+                mConfigFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUVP010);
+                mBytesPerSample = 2;
+                inputTestFile = INPUT_VIDEO_FILE_HBD;
+            }
+            setUpSource(inputTestFile);
+        }
+
         mOutputBuff = new OutputManager();
         {
             mCodec = MediaCodec.createByCodecName(mCodecName);
@@ -205,7 +312,19 @@
                 tmpFile = File.createTempFile("tmp" + (mUseHighBitDepth ? "10bit" : ""), ".mp4");
             }
             mMuxer = new MediaMuxer(tmpFile.getAbsolutePath(), muxerFormat);
-            configureCodec(mConfigFormat, false, true, true);
+            // When in surface mode, encoder needs to be configured in async mode
+            boolean isAsync = mSurfaceMode;
+            configureCodec(mConfigFormat, isAsync, true, true);
+
+            if (mSurfaceMode) {
+                mInpSurface = mCodec.createInputSurface();
+                assertTrue("Surface is not valid", mInpSurface.isValid());
+                mEGLWindowInpSurface = new EGLWindowSurface(mInpSurface, mUseHighBitDepth);
+                if (mCodec.getInputFormat().containsKey(MediaFormat.KEY_LATENCY)) {
+                    mReviseLatency = true;
+                    mLatency = mCodec.getInputFormat().getInteger(MediaFormat.KEY_LATENCY);
+                }
+            }
             mCodec.start();
             doWork(4);
             queueEOS();
@@ -218,6 +337,16 @@
                 mMuxer.release();
                 mMuxer = null;
             }
+
+            if (mEGLWindowInpSurface != null) {
+                mEGLWindowInpSurface.release();
+                mEGLWindowInpSurface = null;
+            }
+            if (mInpSurface != null) {
+                mInpSurface.release();
+                mInpSurface = null;
+            }
+
             assertTrue(log + "unexpected error", !mAsyncHandle.hasSeenError());
             assertTrue(log + "no input sent", 0 != mInputCount);
             assertTrue(log + "output received", 0 != mOutputCount);
diff --git a/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java b/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java
index a6a3688..26c6eb5 100644
--- a/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java
+++ b/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java
@@ -82,11 +82,12 @@
         super.enqueueInput(bufferIndex);
     }
     void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+        MediaFormat bufferFormat = mCodec.getOutputFormat(bufferIndex);
         if (info.size > 0) {
             ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
             if (mMuxer != null) {
                 if (mTrackID == -1) {
-                    mTrackID = mMuxer.addTrack(mCodec.getOutputFormat());
+                    mTrackID = mMuxer.addTrack(bufferFormat);
                     mMuxer.start();
                 }
                 mMuxer.writeSampleData(mTrackID, buf, info);
@@ -95,7 +96,7 @@
         super.dequeueOutput(bufferIndex, info);
         // verify if the out fmt contains HDR Dynamic metadata as expected
         if (mTestDynamicMetadata && mOutputCount > 0) {
-            validateHDRDynamicMetaData(mCodec.getOutputFormat(),
+            validateHDRDynamicMetaData(bufferFormat,
                     ByteBuffer.wrap(loadByteArrayFromString(HDR_DYNAMIC_INFO[mOutputCount - 1])));
         }
     }
diff --git a/tests/media/src/android/mediav2/cts/OutputSurface.java b/tests/media/src/android/mediav2/cts/OutputSurface.java
index fb962a7..03856a2 100644
--- a/tests/media/src/android/mediav2/cts/OutputSurface.java
+++ b/tests/media/src/android/mediav2/cts/OutputSurface.java
@@ -65,14 +65,18 @@
      * to MediaCodec.configure().
      */
     public OutputSurface(int width, int height, boolean useHighBitDepth) {
+        this(width, height, useHighBitDepth, /* useYuvSampling */ false);
+    }
+
+    public OutputSurface(int width, int height, boolean useHighBitDepth, boolean useYuvSampling) {
         if (width <= 0 || height <= 0) {
             throw new IllegalArgumentException();
         }
 
-        eglSetup(width, height, useHighBitDepth);
+        eglSetup(width, height, useHighBitDepth, useYuvSampling);
         makeCurrent();
 
-        setup(this);
+        setup(this, useYuvSampling);
     }
 
     /**
@@ -80,23 +84,24 @@
      * new one).  Creates a Surface that can be passed to MediaCodec.configure().
      */
     public OutputSurface() {
-        setup(this);
+        setup(this, /* useYuvSampling */ false);
     }
 
     public OutputSurface(final SurfaceTexture.OnFrameAvailableListener listener) {
-        setup(listener);
+        setup(listener, /* useYuvSampling */ false);
     }
 
     /**
      * Creates instances of TextureRender and SurfaceTexture, and a Surface associated
      * with the SurfaceTexture.
      */
-    private void setup(SurfaceTexture.OnFrameAvailableListener listener) {
+    private void setup(SurfaceTexture.OnFrameAvailableListener listener, boolean useYuvSampling) {
         assertTrue(EGL14.eglGetCurrentContext() != EGL14.EGL_NO_CONTEXT);
         assertTrue(EGL14.eglGetCurrentDisplay() != EGL14.EGL_NO_DISPLAY);
         assertTrue(EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW) != EGL14.EGL_NO_SURFACE);
         assertTrue(EGL14.eglGetCurrentSurface(EGL14.EGL_READ) != EGL14.EGL_NO_SURFACE);
         mTextureRender = new TextureRender();
+        mTextureRender.setUseYuvSampling(useYuvSampling);
         mTextureRender.surfaceCreated();
 
         // Even if we don't access the SurfaceTexture after the constructor returns, we
@@ -125,7 +130,7 @@
     /**
      * Prepares EGL.  We want a GLES 2.0 context and a surface that supports pbuffer.
      */
-    private void eglSetup(int width, int height, boolean useHighBitDepth) {
+    private void eglSetup(int width, int height, boolean useHighBitDepth, boolean useYuvSampling) {
         mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
         if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
             throw new RuntimeException("unable to get EGL14 display");
@@ -156,9 +161,10 @@
             throw new RuntimeException("unable to find RGB888+recordable ES2 EGL config");
         }
 
-        // Configure context for OpenGL ES 2.0.
+        // Configure context for OpenGL ES 3.0/2.0.
+        int eglContextClientVersion = useYuvSampling ? 3: 2;
         int[] attrib_list = {
-                EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
+                EGL14.EGL_CONTEXT_CLIENT_VERSION, eglContextClientVersion,
                 EGL14.EGL_NONE
         };
         mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,
diff --git a/tests/media/src/android/mediav2/cts/TextureRender.java b/tests/media/src/android/mediav2/cts/TextureRender.java
index 4cda868..548ff03 100644
--- a/tests/media/src/android/mediav2/cts/TextureRender.java
+++ b/tests/media/src/android/mediav2/cts/TextureRender.java
@@ -49,7 +49,7 @@
 
     private FloatBuffer mTriangleVertices;
 
-    private static final String VERTEX_SHADER =
+    private static final String VERTEX_SHADER_RGB =
             "uniform mat4 uMVPMatrix;\n" +
             "uniform mat4 uSTMatrix;\n" +
             "attribute vec4 aPosition;\n" +
@@ -60,7 +60,7 @@
             "  vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
             "}\n";
 
-    private static final String FRAGMENT_SHADER =
+    private static final String FRAGMENT_SHADER_RGB =
             "#extension GL_OES_EGL_image_external : require\n" +
             "precision mediump float;\n" +      // highp here doesn't seem to matter
             "varying vec2 vTextureCoord;\n" +
@@ -69,6 +69,30 @@
             "  gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
             "}\n";
 
+    private static final String VERTEX_SHADER_YUV =
+            "#version 300 es\n" +
+            "uniform mat4 uMVPMatrix;\n" +
+            "uniform mat4 uSTMatrix;\n" +
+            "in vec4 aPosition;\n" +
+            "in vec4 aTextureCoord;\n" +
+            "out vec2 vTextureCoord;\n" +
+            "void main() {\n" +
+            "  gl_Position = uMVPMatrix * aPosition;\n" +
+            "  vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
+            "}\n";
+
+    private static final String FRAGMENT_SHADER_YUV =
+            "#version 300 es\n" +
+            "#extension GL_OES_EGL_image_external : require\n" +
+            "#extension GL_EXT_YUV_target : require\n" +
+            "precision mediump float;\n" +      // highp here doesn't seem to matter
+            "uniform __samplerExternal2DY2YEXT uTexSampler;\n" +
+            "in vec2 vTextureCoord;\n" +
+            "out vec4 outColor;\n" +
+            "void main() {\n" +
+            "    outColor = texture(uTexSampler, vTextureCoord);\n" +
+            "}\n";
+
     private float[] mMVPMatrix = new float[16];
     private float[] mSTMatrix = new float[16];
 
@@ -78,6 +102,7 @@
     private int muSTMatrixHandle;
     private int maPositionHandle;
     private int maTextureHandle;
+    private boolean mUseYuvSampling;
 
     public TextureRender() {
         mTriangleVertices = ByteBuffer.allocateDirect(
@@ -86,6 +111,11 @@
         mTriangleVertices.put(mTriangleVerticesData).position(0);
 
         Matrix.setIdentityM(mSTMatrix, 0);
+        mUseYuvSampling = false;
+    }
+
+    public void setUseYuvSampling(boolean useYuvSampling) {
+        mUseYuvSampling = useYuvSampling;
     }
 
     public int getTextureId() {
@@ -132,7 +162,11 @@
      * Initializes GL state.  Call this after the EGL surface has been created and made current.
      */
     public void surfaceCreated() {
-        mProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
+        if (mUseYuvSampling == false) {
+            mProgram = createProgram(VERTEX_SHADER_RGB, FRAGMENT_SHADER_RGB);
+        } else {
+            mProgram = createProgram(VERTEX_SHADER_YUV, FRAGMENT_SHADER_YUV);
+        }
         if (mProgram == 0) {
             throw new RuntimeException("failed creating program");
         }
@@ -183,7 +217,7 @@
      */
     public void changeFragmentShader(String fragmentShader) {
         GLES20.glDeleteProgram(mProgram);
-        mProgram = createProgram(VERTEX_SHADER, fragmentShader);
+        mProgram = createProgram(VERTEX_SHADER_RGB, fragmentShader);
         if (mProgram == 0) {
             throw new RuntimeException("failed creating program");
         }
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java b/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
index 1c3a4dd..327fb9c 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
@@ -20,10 +20,13 @@
 
 import static org.junit.Assume.assumeTrue;
 
+import android.media.MediaFormat;
 import android.os.Build;
 
 import com.google.common.base.Preconditions;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import org.junit.rules.TestName;
 
 import java.util.HashSet;
@@ -90,36 +93,17 @@
                 .setId(RequirementConstants.LONG_RESOLUTION)
                 .setPredicate(RequirementConstants.INTEGER_GTE)
                 .addRequiredValue(Build.VERSION_CODES.S, 1920)
-                .build();
-            RequiredMeasurement<Integer> short_resolution = RequiredMeasurement
-                .<Integer>builder()
-                .setId(RequirementConstants.SHORT_RESOLUTION)
-                .setPredicate(RequirementConstants.INTEGER_GTE)
-                .addRequiredValue(Build.VERSION_CODES.S, 1080)
-                .build();
-
-            return new ResolutionRequirement(RequirementConstants.R7_1_1_1__H_2_1, long_resolution,
-                short_resolution);
-        }
-
-        /**
-         * [7.1.1.1/?] MUST have screen resolution of at least 1080p.
-         */
-        public static ResolutionRequirement createR7_1_1_1__TBD1() {
-            RequiredMeasurement<Integer> long_resolution = RequiredMeasurement
-                .<Integer>builder()
-                .setId(RequirementConstants.LONG_RESOLUTION)
-                .setPredicate(RequirementConstants.INTEGER_GTE)
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1920)
                 .build();
             RequiredMeasurement<Integer> short_resolution = RequiredMeasurement
                 .<Integer>builder()
                 .setId(RequirementConstants.SHORT_RESOLUTION)
                 .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.S, 1080)
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1080)
                 .build();
 
-            return new ResolutionRequirement(RequirementConstants.RTBD, long_resolution,
+            return new ResolutionRequirement(RequirementConstants.R7_1_1_1__H_2_1, long_resolution,
                 short_resolution);
         }
     }
@@ -159,27 +143,14 @@
                 .setId(RequirementConstants.DISPLAY_DENSITY)
                 .setPredicate(RequirementConstants.INTEGER_GTE)
                 .addRequiredValue(Build.VERSION_CODES.S, 400)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 400)
                 .build();
 
             return new DensityRequirement(RequirementConstants.R7_1_1_3__H_2_1, display_density);
         }
-
-        /**
-         * [7.1.1.3/?] MUST have screen density of at least 400 dpi.
-         */
-        public static DensityRequirement createR7_1_1_3__TBD2() {
-            RequiredMeasurement<Integer> display_density = RequiredMeasurement
-                .<Integer>builder()
-                .setId(RequirementConstants.DISPLAY_DENSITY)
-                .setPredicate(RequirementConstants.INTEGER_GTE)
-                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 400)
-                .build();
-
-            return new DensityRequirement(RequirementConstants.RTBD, display_density);
-        }
     }
 
-    // used for requirements [7.6.1/H-1-1], [7.6.1/H-2-1], [7.6.1/H-3-1]
+    // used for requirements [7.6.1/H-1-1], [7.6.1/H-2-1]
     public static class MemoryRequirement extends Requirement {
         private static final String TAG = MemoryRequirement.class.getSimpleName();
 
@@ -208,39 +179,23 @@
         }
 
         /**
-         * [7.6.1/H-2-1] MUST have at least 6 GB of physical memory.
+         * [7.6.1/H-2-1] MUST have at least 6/8 GB of physical memory.
          */
         public static MemoryRequirement createR7_6_1__H_2_1() {
             RequiredMeasurement<Long> physical_memory = RequiredMeasurement
                 .<Long>builder()
                 .setId(RequirementConstants.PHYSICAL_MEMORY)
                 .setPredicate(RequirementConstants.LONG_GTE)
-                // Media performance requires 6 GB minimum RAM, but keeping the following to 5 GB
-                // as activityManager.getMemoryInfo() returns around 5.4 GB on a 6 GB device.
+                // Media performance requires 6/8 GB minimum RAM, but keeping the following to
+                // 5/7 GB as activityManager.getMemoryInfo() returns around 5.4 GB on a 6 GB device.
                 .addRequiredValue(Build.VERSION_CODES.S, 5L * 1024L)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 7L * 1024L)
                 .build();
 
             return new MemoryRequirement(RequirementConstants.R7_6_1__H_2_1, physical_memory);
         }
-
-        /**
-         * [7.6.1/H-3-1] MUST have at least 8 GB of physical memory.
-         */
-        public static MemoryRequirement createR7_6_1__H_3_1() {
-            RequiredMeasurement<Long> physical_memory = RequiredMeasurement
-                .<Long>builder()
-                .setId(RequirementConstants.PHYSICAL_MEMORY)
-                .setPredicate(RequirementConstants.LONG_GTE)
-                // Media performance requires 8 GB minimum RAM, but keeping the following to 7 GB
-                // as activityManager.getMemoryInfo() returns around 7.4 GB on a 8 GB device.
-                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 7L * 1024L)
-                .build();
-
-            return new MemoryRequirement(RequirementConstants.R7_6_1__H_3_1, physical_memory);
-        }
     }
 
-    // used for requirements [2.2.7.1/5.1/H-1-7], [2.2.7.1/5.1/H-1-8], [2.2.7.1/5.1/H-1-?]
     public static class CodecInitLatencyRequirement extends Requirement {
 
         private static final String TAG = CodecInitLatencyRequirement.class.getSimpleName();
@@ -293,40 +248,38 @@
                 codec_init_latency);
         }
 
-        // TODO(b/218771970): Update CDD section, change RequirementConstants.RTBD to appropirate
-        // requirement id once finalized, ex: RequirementConstants.R5_1__H_1_<something>
         /**
-         * [2.2.7.1/5.1/H-1-?] Codec initialization latency of 40ms or less for a 1080p or
+         * [2.2.7.1/5.1/H-1-12] Codec initialization latency of 40ms or less for a 1080p or
          * smaller video decoding session for all hardware video encoders when under load. Load
          * here is defined as a concurrent 1080p to 720p video-only transcoding session using
          * hardware video codecs together with the 1080p audio-video recording initialization.
          */
-        public static CodecInitLatencyRequirement createR5_1__H_1_TBD1() {
+        public static CodecInitLatencyRequirement createR5_1__H_1_12() {
             RequiredMeasurement<Long> codec_init_latency =
                 RequiredMeasurement.<Long>builder().setId(RequirementConstants.CODEC_INIT_LATENCY)
                     .setPredicate(RequirementConstants.LONG_LTE)
                     .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 40L)
                     .build();
 
-            return new CodecInitLatencyRequirement(RequirementConstants.RTBD, codec_init_latency);
+            return new CodecInitLatencyRequirement(RequirementConstants.R5_1__H_1_12,
+                    codec_init_latency);
         }
 
-        // TODO(b/218771970): Update CDD section, change RequirementConstants.RTBD to appropirate
-        // requirement id once finalized, ex: RequirementConstants.R5_1__H_1_<something>
         /**
-         * [2.2.7.1/5.1/H-1-?] Codec initialization latency of 30ms or less for a 128kbps or
+         * [2.2.7.1/5.1/H-1-13] Codec initialization latency of 30ms or less for a 128kbps or
          * lower bitrate audio decoding session for all audio encoders when under load. Load here
          * is defined as a concurrent 1080p to 720p video-only transcoding session using hardware
          * video codecs together with the 1080p audio-video recording initialization.
          */
-        public static CodecInitLatencyRequirement createR5_1__H_1_TBD2() {
+        public static CodecInitLatencyRequirement createR5_1__H_1_13() {
             RequiredMeasurement<Long> codec_init_latency =
                 RequiredMeasurement.<Long>builder().setId(RequirementConstants.CODEC_INIT_LATENCY)
                     .setPredicate(RequirementConstants.LONG_LTE)
                     .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 30L)
                     .build();
 
-            return new CodecInitLatencyRequirement(RequirementConstants.RTBD, codec_init_latency);
+            return new CodecInitLatencyRequirement(RequirementConstants.R5_1__H_1_13,
+                    codec_init_latency);
         }
     }
 
@@ -455,9 +408,6 @@
         }
     }
 
-    // TODO(b/218771970): Add cdd annotation, change RequirementConstants.RTBD to appropirate
-    // requirement id once finalized
-    // used for requirements [?]
     public static class VideoCodecRequirement extends Requirement {
         private static final String TAG = VideoCodecRequirement.class.getSimpleName();
 
@@ -478,7 +428,7 @@
         }
 
         /**
-         * [?] Must have at least 1 HW video decoder supporting 4K60
+         * [2.2.7.1/5.1/H-1-15] Must have at least 1 HW video decoder supporting 4K60
          */
         public static VideoCodecRequirement createR4k60HwDecoder() {
             RequiredMeasurement<Integer> requirement = RequiredMeasurement
@@ -488,11 +438,11 @@
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1)
                 .build();
 
-            return new VideoCodecRequirement(RequirementConstants.RTBD, requirement);
+            return new VideoCodecRequirement(RequirementConstants.R5_1__H_1_15, requirement);
         }
 
         /**
-         * [?] Must have at least 1 HW video encoder supporting 4K60
+         * [2.2.7.1/5.1/H-1-16] Must have at least 1 HW video encoder supporting 4K60
          */
         public static VideoCodecRequirement createR4k60HwEncoder() {
             RequiredMeasurement<Integer> requirement = RequiredMeasurement
@@ -502,11 +452,11 @@
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1)
                 .build();
 
-            return new VideoCodecRequirement(RequirementConstants.RTBD, requirement);
+            return new VideoCodecRequirement(RequirementConstants.R5_1__H_1_16, requirement);
         }
 
         /**
-         * [?] AV1 Hardware decoder: Main 10, Level 4.1, Film Grain
+         * [2.2.7.1/5.1/H-1-14] AV1 Hardware decoder: Main 10, Level 4.1, Film Grain
          */
         public static VideoCodecRequirement createRAV1DecoderReq() {
             RequiredMeasurement<Boolean> requirement = RequiredMeasurement
@@ -516,12 +466,343 @@
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
                 .build();
 
-            return new VideoCodecRequirement(RequirementConstants.RTBD, requirement);
+            return new VideoCodecRequirement(RequirementConstants.R5_1__H_1_14, requirement);
         }
     }
 
-    // TODO(b/218771970): Add cdd annotation
-    // used for requirements [?]
+    // used for requirements [2.2.7.1/5.1/H-1-1], [2.2.7.1/5.1/H-1-2], [2.2.7.1/5.1/H-1-3],
+    // [2.2.7.1/5.1/H-1-4], [2.2.7.1/5.1/H-1-5], [2.2.7.1/5.1/H-1-6], [2.2.7.1/5.1/H-1-9],
+    // [2.2.7.1/5.1/H-1-10]
+    public static class ConcurrentCodecRequirement extends Requirement {
+        private static final String TAG = ConcurrentCodecRequirement.class.getSimpleName();
+        // allowed tolerance in measured fps vs expected fps in percentage, i.e. codecs achieving
+        // fps that is greater than (FPS_TOLERANCE_FACTOR * expectedFps) will be considered as
+        // passing the test
+        private static final double FPS_TOLERANCE_FACTOR = 0.95;
+        private static final double FPS_30_TOLERANCE = 30.0 * FPS_TOLERANCE_FACTOR;
+        static final int REQUIRED_MIN_CONCURRENT_INSTANCES = 6;
+        static final int REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9 = 2;
+
+        private ConcurrentCodecRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setConcurrentInstances(int concurrentInstances) {
+            this.setMeasuredValue(RequirementConstants.CONCURRENT_SESSIONS,
+                concurrentInstances);
+        }
+
+        public void setConcurrentFps(double achievedFps) {
+            this.setMeasuredValue(RequirementConstants.CONCURRENT_FPS, achievedFps);
+        }
+
+        // copied from android.mediapc.cts.getReqMinConcurrentInstances due to build issues on aosp
+        public static int getReqMinConcurrentInstances(int performanceClass, String mimeType1,
+            String mimeType2, int resolution) {
+            ArrayList<String> MEDIAPC_CONCURRENT_CODECS_R = new ArrayList<>(
+                Arrays.asList(MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC));
+            ArrayList<String> MEDIAPC_CONCURRENT_CODECS = new ArrayList<>(Arrays
+                .asList(MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC,
+                    MediaFormat.MIMETYPE_VIDEO_VP9, MediaFormat.MIMETYPE_VIDEO_AV1));
+
+            if (performanceClass >= Build.VERSION_CODES.TIRAMISU) {
+                return resolution >= 1080 ? REQUIRED_MIN_CONCURRENT_INSTANCES : 0;
+            } else if (performanceClass == Build.VERSION_CODES.S) {
+                if (resolution >= 1080) {
+                    return 0;
+                }
+                if (MEDIAPC_CONCURRENT_CODECS.contains(mimeType1) && MEDIAPC_CONCURRENT_CODECS
+                    .contains(mimeType2)) {
+                    if (MediaFormat.MIMETYPE_VIDEO_VP9.equalsIgnoreCase(mimeType1)
+                        || MediaFormat.MIMETYPE_VIDEO_VP9.equalsIgnoreCase(mimeType2)) {
+                        return REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9;
+                    } else {
+                        return REQUIRED_MIN_CONCURRENT_INSTANCES;
+                    }
+                } else {
+                    return 0;
+                }
+            } else if (performanceClass == Build.VERSION_CODES.R) {
+                if (resolution >= 1080) {
+                    return 0;
+                }
+                if (MEDIAPC_CONCURRENT_CODECS_R.contains(mimeType1) && MEDIAPC_CONCURRENT_CODECS_R
+                    .contains(mimeType2)) {
+                    return REQUIRED_MIN_CONCURRENT_INSTANCES;
+                } else {
+                    return 0;
+                }
+            } else {
+                return 0;
+            }
+        }
+
+        private static double getReqMinConcurrentFps(int performanceClass, String mimeType1,
+            String mimeType2, int resolution) {
+            return FPS_30_TOLERANCE * getReqMinConcurrentInstances(performanceClass, mimeType1,
+                mimeType2, resolution);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-1] MUST advertise the maximum number of hardware video decoder
+         * sessions that can be run concurrently in any codec combination via the
+         * CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
+         * .getSupportedPerformancePoints() methods.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_1_720p(String mimeType1,
+            String mimeType2, int resolution) {
+            RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.CONCURRENT_SESSIONS)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R,
+                    getReqMinConcurrentInstances(Build.VERSION_CODES.R, mimeType1, mimeType2,
+                        resolution))
+                .addRequiredValue(Build.VERSION_CODES.S,
+                    getReqMinConcurrentInstances(Build.VERSION_CODES.S, mimeType1, mimeType2,
+                        resolution))
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_1, maxInstances);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-1] MUST advertise the maximum number of hardware video decoder
+         * sessions that can be run concurrently in any codec combination via the
+         * CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
+         * .getSupportedPerformancePoints() methods.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_1_1080p() {
+            RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.CONCURRENT_SESSIONS)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6)
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_1, maxInstances);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-2] MUST support 6 instances of hardware video decoder sessions (AVC,
+         * HEVC, VP9* or later) in any codec combination running concurrently at 720p(R,S)
+         * resolution@30 fps.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_2_720p(String mimeType1,
+            String mimeType2, int resolution) {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R,
+                    getReqMinConcurrentFps(Build.VERSION_CODES.R, mimeType1, mimeType2, resolution))
+                .addRequiredValue(Build.VERSION_CODES.S,
+                    getReqMinConcurrentFps(Build.VERSION_CODES.S, mimeType1, mimeType2, resolution))
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_2,
+                reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-2] MUST support 6 instances of hardware video decoder sessions (AVC,
+         * HEVC, VP9* or later) in any codec combination running concurrently at 1080p(T)
+         * resolution@30 fps.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_2_1080p() {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6 * FPS_30_TOLERANCE)
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_2,
+                reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-3] MUST advertise the maximum number of hardware video encoder
+         * sessions that can be run concurrently in any codec combination via the
+         * CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
+         * .getSupportedPerformancePoints() methods.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_3_720p(String mimeType1,
+            String mimeType2, int resolution) {
+            RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.CONCURRENT_SESSIONS)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R,
+                    getReqMinConcurrentInstances(Build.VERSION_CODES.R, mimeType1, mimeType2,
+                        resolution))
+                .addRequiredValue(Build.VERSION_CODES.S,
+                    getReqMinConcurrentInstances(Build.VERSION_CODES.S, mimeType1, mimeType2,
+                        resolution))
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_3, maxInstances);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-3] MUST advertise the maximum number of hardware video encoder
+         * sessions that can be run concurrently in any codec combination via the
+         * CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
+         * .getSupportedPerformancePoints() methods.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_3_1080p() {
+            RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.CONCURRENT_SESSIONS)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6)
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_3, maxInstances);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-4] MUST support 6 instances of hardware video encoder sessions (AVC,
+         * HEVC, VP9* or later) in any codec combination running concurrently at 720p(R,S)
+         * resolution@30 fps.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_4_720p() {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                // Requirement not asserted since encoder test runs in byte buffer mode
+                .addRequiredValue(Build.VERSION_CODES.R, 0.0)
+                .addRequiredValue(Build.VERSION_CODES.S, 0.0)
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_4,
+                reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-4] MUST support 6 instances of hardware video encoder sessions (AVC,
+         * HEVC, VP9* or later) in any codec combination running concurrently at 1080p(T)
+         * resolution@30 fps.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_4_1080p() {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                // Requirement not asserted since encoder test runs in byte buffer mode
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 0.0)
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_4,
+                reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-5] MUST advertise the maximum number of hardware video encoder and
+         * decoder sessions that can be run concurrently in any codec combination via the
+         * CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
+         * .getSupportedPerformancePoints() methods.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_5_720p(String mimeType1,
+            String mimeType2, int resolution) {
+            RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.CONCURRENT_SESSIONS)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R,
+                    getReqMinConcurrentInstances(Build.VERSION_CODES.R, mimeType1, mimeType2,
+                        resolution))
+                .addRequiredValue(Build.VERSION_CODES.S,
+                    getReqMinConcurrentInstances(Build.VERSION_CODES.S, mimeType1, mimeType2,
+                        resolution))
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_5, maxInstances);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-5] MUST advertise the maximum number of hardware video encoder and
+         * decoder sessions that can be run concurrently in any codec combination via the
+         * CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
+         * .getSupportedPerformancePoints() methods.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_5_1080p() {
+            RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.CONCURRENT_SESSIONS)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6)
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_5, maxInstances);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-6] Support 6 instances of hardware video decoder and hardware video
+         * encoder sessions (AVC, HEVC, VP9 or AV1) in any codec combination running concurrently
+         * at 720p(R,S) /1080p(T) @30fps resolution.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_6_720p(String mimeType1,
+            String mimeType2, int resolution) {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                // Test transcoding, fps calculated for encoder and decoder combined so req / 2
+                .addRequiredValue(Build.VERSION_CODES.R,
+                    getReqMinConcurrentFps(Build.VERSION_CODES.R, mimeType1, mimeType2, resolution)
+                        / 2)
+                .addRequiredValue(Build.VERSION_CODES.S,
+                    getReqMinConcurrentFps(Build.VERSION_CODES.S, mimeType1, mimeType2, resolution)
+                        / 2)
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_6,
+                reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-6] Support 6 instances of hardware video decoder and hardware video
+         * encoder sessions (AVC, HEVC, VP9 or AV1) in any codec combination running concurrently
+         * at 720p(R,S) /1080p(T) @30fps resolution.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_6_1080p() {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                // Test transcoding, fps calculated for encoder and decoder combined so req / 2
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6 * FPS_30_TOLERANCE / 2)
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_6,
+                reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-9] Support 2 instances of secure hardware video decoder sessions
+         * (AVC, HEVC, VP9 or AV1) in any codec combination running concurrently at 1080p
+         * resolution@30fps.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_9() {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 2 * FPS_30_TOLERANCE)
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_9,
+                reqConcurrentFps);
+        }
+
+        /**
+         * [2.2.7.1/5.1/H-1-10] Support 3 instances of non-secure hardware video decoder sessions
+         * together with 1 instance of secure hardware video decoder session (4 instances total)
+         * (AVC, HEVC, VP9 or AV1) in any codec combination running concurrently at 1080p
+         * resolution@30fps.
+         */
+        public static ConcurrentCodecRequirement createR5_1__H_1_10() {
+            RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
+                .setId(RequirementConstants.CONCURRENT_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 4 * FPS_30_TOLERANCE)
+                .build();
+
+            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_10,
+                reqConcurrentFps);
+        }
+    }
+
+    // used for requirements [2.2.7.1/5.1/H-1-11], [2.2.7.1/5.7/H-1-2]
     public static class SecureCodecRequirement extends Requirement {
         private static final String TAG = SecureCodecRequirement.class.getSimpleName();
 
@@ -533,70 +814,30 @@
             this.setMeasuredValue(RequirementConstants.SECURE_REQ_SATISFIED, secureReqSatisfied);
         }
 
-        public void setWidevineSupported(boolean isWidevineSupported) {
-            this.setMeasuredValue(RequirementConstants.WIDEWINE_SUPPORT, isWidevineSupported);
-        }
-
-        public void setWidevineL1Supported(boolean isL1Supported) {
-            this.setMeasuredValue(RequirementConstants.WIDEWINE_L1, isL1Supported);
-        }
-
-        public void setWidevineL1Tier3Supported(boolean isL1Tier3Supported) {
-            this.setMeasuredValue(RequirementConstants.WIDEWINE_L1_TIER3, isL1Tier3Supported);
-        }
-
-        public void setOemCrypto17Plus(boolean isOemCrypto17Plus) {
-            this.setMeasuredValue(RequirementConstants.OEM_CRYPTO_17_PLUS, isOemCrypto17Plus);
-        }
-
-        public void setWidevineCdm17Plus(boolean isWidevineCdm17Plus) {
-            this.setMeasuredValue(RequirementConstants.WIDEWINE_CDM_17_PLUS, isWidevineCdm17Plus);
+        public void setNumCryptoHwSecureAllDec(int numCryptoHwSecureAllDec) {
+            this.setMeasuredValue(RequirementConstants.NUM_CRYPTO_HW_SECURE_ALL_SUPPORT,
+                numCryptoHwSecureAllDec);
         }
 
         /**
-         * [?] Support for Widevine L1 Tier 3, WidevineCdmVersion >= 17, OemCryptoVersion >= 17
+         * [2.2.7.1/5.7/H-1-2] MUST support MediaDrm.SECURITY_LEVEL_HW_SECURE_ALL with the below
+         * content decryption capabilities.
          */
-        public static SecureCodecRequirement createRWidevineSupport() {
-            RequiredMeasurement<Boolean> widevineSupport = RequiredMeasurement
-                .<Boolean>builder()
-                .setId(RequirementConstants.WIDEWINE_SUPPORT)
-                .setPredicate(RequirementConstants.BOOLEAN_EQ)
-                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+        public static SecureCodecRequirement createR5_7__H_1_2() {
+            RequiredMeasurement<Integer> hw_secure_all = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.NUM_CRYPTO_HW_SECURE_ALL_SUPPORT)
+                .setPredicate(RequirementConstants.INTEGER_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1)
                 .build();
 
-            RequiredMeasurement<Boolean> widevineL1 =
-                RequiredMeasurement.<Boolean>builder().setId(RequirementConstants.WIDEWINE_L1)
-                    .setPredicate(RequirementConstants.BOOLEAN_EQ)
-                    .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
-                    .build();
-
-            RequiredMeasurement<Boolean> widevineL1Tier3 =
-                RequiredMeasurement.<Boolean>builder().setId(RequirementConstants.WIDEWINE_L1_TIER3)
-                    .setPredicate(RequirementConstants.BOOLEAN_EQ)
-                    .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
-                    .build();
-
-            RequiredMeasurement<Boolean> oemCryptoReq = RequiredMeasurement.<Boolean>builder()
-                .setId(RequirementConstants.OEM_CRYPTO_17_PLUS)
-                .setPredicate(RequirementConstants.BOOLEAN_EQ)
-                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
-                .build();
-
-            RequiredMeasurement<Boolean> widevineCdmReq = RequiredMeasurement.<Boolean>builder()
-                .setId(RequirementConstants.WIDEWINE_CDM_17_PLUS)
-                .setPredicate(RequirementConstants.BOOLEAN_EQ)
-                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
-                .build();
-
-            return new SecureCodecRequirement(RequirementConstants.RTBD, widevineSupport,
-                widevineL1, widevineL1Tier3, oemCryptoReq, widevineCdmReq);
+            return new SecureCodecRequirement(RequirementConstants.R5_7__H_1_2, hw_secure_all);
         }
 
         /**
-         * [?] Must support secure decoder when a corresponding AVC/VP9/HEVC or AV1 hardware
-         * decoder is available
+         * [2.2.7.1/5.1/H-1-11] Must support secure decoder when a corresponding AVC/VP9/HEVC or AV1
+         * hardware decoder is available
          */
-        public static SecureCodecRequirement createRSecureDecodeSupport() {
+        public static SecureCodecRequirement createR5_1__H_1_11() {
             RequiredMeasurement<Boolean> requirement = RequiredMeasurement
                 .<Boolean>builder()
                 .setId(RequirementConstants.SECURE_REQ_SATISFIED)
@@ -604,7 +845,7 @@
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
                 .build();
 
-            return new SecureCodecRequirement(RequirementConstants.RTBD, requirement);
+            return new SecureCodecRequirement(RequirementConstants.R5_1__H_1_11, requirement);
         }
     }
 
@@ -633,25 +874,13 @@
             ResolutionRequirement.createR7_1_1_1__H_2_1());
     }
 
-    public ResolutionRequirement addR7_1_1_1__TBD1() {
-        return this.<ResolutionRequirement>addRequirement(
-            ResolutionRequirement.createR7_1_1_1__TBD1());
-    }
-
     public DensityRequirement addR7_1_1_3__H_2_1() {
         return this.<DensityRequirement>addRequirement(DensityRequirement.createR7_1_1_3__H_2_1());
     }
 
-    public DensityRequirement addR7_1_1_3__TBD2() {
-        return this.<DensityRequirement>addRequirement(DensityRequirement.createR7_1_1_3__TBD2());
-    }
-
     public MemoryRequirement addR7_6_1__H_2_1() {
         return this.<MemoryRequirement>addRequirement(MemoryRequirement.createR7_6_1__H_2_1());
     }
-    public MemoryRequirement addR7_6_1__H_3_1() {
-        return this.<MemoryRequirement>addRequirement(MemoryRequirement.createR7_6_1__H_3_1());
-    }
 
     public FrameDropRequirement addR5_3__H_1_1_R() {
         return this.addRequirement(FrameDropRequirement.createR5_3__H_1_1_R());
@@ -677,12 +906,12 @@
         return this.addRequirement(CodecInitLatencyRequirement.createR5_1__H_1_8());
     }
 
-    public CodecInitLatencyRequirement addR5_1__H_1_TBD1() {
-        return this.addRequirement(CodecInitLatencyRequirement.createR5_1__H_1_TBD1());
+    public CodecInitLatencyRequirement addR5_1__H_1_12() {
+        return this.addRequirement(CodecInitLatencyRequirement.createR5_1__H_1_12());
     }
 
-    public CodecInitLatencyRequirement addR5_1__H_1_TBD2() {
-        return this.addRequirement(CodecInitLatencyRequirement.createR5_1__H_1_TBD2());
+    public CodecInitLatencyRequirement addR5_1__H_1_13() {
+        return this.addRequirement(CodecInitLatencyRequirement.createR5_1__H_1_13());
     }
 
     public VideoCodecRequirement addR4k60HwEncoder() {
@@ -697,12 +926,78 @@
         return this.addRequirement(VideoCodecRequirement.createRAV1DecoderReq());
     }
 
-    public SecureCodecRequirement addRSecureDecodeSupport() {
-        return this.addRequirement(SecureCodecRequirement.createRSecureDecodeSupport());
+    public SecureCodecRequirement addR5_1__H_1_11() {
+        return this.addRequirement(SecureCodecRequirement.createR5_1__H_1_11());
     }
 
-    public SecureCodecRequirement addRWidevineSupport() {
-        return this.addRequirement(SecureCodecRequirement.createRWidevineSupport());
+    public SecureCodecRequirement addR5_7__H_1_2() {
+        return this.addRequirement(SecureCodecRequirement.createR5_7__H_1_2());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_1_720p(String mimeType1, String mimeType2,
+        int resolution) {
+        return this.addRequirement(
+            ConcurrentCodecRequirement.createR5_1__H_1_1_720p(mimeType1, mimeType2, resolution));
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_1_1080p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_1_1080p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_2_720p(String mimeType1, String mimeType2,
+        int resolution) {
+        return this.addRequirement(
+            ConcurrentCodecRequirement.createR5_1__H_1_2_720p(mimeType1, mimeType2, resolution));
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_2_1080p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_2_1080p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_3_720p(String mimeType1, String mimeType2,
+        int resolution) {
+        return this.addRequirement(
+            ConcurrentCodecRequirement.createR5_1__H_1_3_720p(mimeType1, mimeType2, resolution));
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_3_1080p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_3_1080p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_4_720p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_4_720p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_4_1080p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_4_1080p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_5_720p(String mimeType1, String mimeType2,
+        int resolution) {
+        return this.addRequirement(
+            ConcurrentCodecRequirement.createR5_1__H_1_5_720p(mimeType1, mimeType2, resolution));
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_5_1080p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_5_1080p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_6_720p(String mimeType1, String mimeType2,
+        int resolution) {
+        return this.addRequirement(
+            ConcurrentCodecRequirement.createR5_1__H_1_6_720p(mimeType1, mimeType2, resolution));
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_6_1080p() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_6_1080p());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_9() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_9());
+    }
+
+    public ConcurrentCodecRequirement addR5_1__H_1_10() {
+        return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_10());
     }
 
     public void submitAndCheck() {
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 0de6a99..d93cb2e 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
@@ -35,9 +35,19 @@
     public static final String R5_1__H_1_6 = "r5_1__h_1_6"; // 5.1/H-1-6
     public static final String R5_1__H_1_7 = "r5_1__h_1_7"; // 5.1/H-1-7
     public static final String R5_1__H_1_8 = "r5_1__h_1_8"; // 5.1/H-1-8
+    public static final String R5_1__H_1_9 = "r5_1__h_1_9"; // 5.1/H-1-9
+    public static final String R5_1__H_1_10 = "r5_1__h_1_10"; // 5.1/H-1-10
+    public static final String R5_1__H_1_11 = "r5_1__h_1_11"; // 5.1/H-1-11
+    public static final String R5_1__H_1_12 = "r5_1__h_1_12"; // 5.1/H-1-12
+    public static final String R5_1__H_1_13 = "r5_1__h_1_13"; // 5.1/H-1-13
+    public static final String R5_1__H_1_14 = "r5_1__h_1_14"; // 5.1/H-1-14
+    public static final String R5_1__H_1_15 = "r5_1__h_1_15"; // 5.1/H-1-16
+    public static final String R5_1__H_1_16 = "r5_1__h_1_16"; // 5.1/H-1-16
     public static final String R5_3__H_1_1 = "r5_3__h_1_1"; // 5.3/H-1-1
     public static final String R5_3__H_1_2 = "r5_3__h_1_2"; // 5.3/H-1-2
     public static final String R5_6__H_1_1 = "r5_6__h_1_1"; // 5.6/H-1-1
+    public static final String R5_7__H_1_1 = "r5_7__h_1_1"; // 5.7/H-1-1
+    public static final String R5_7__H_1_2 = "r5_7__h_1_2"; // 5.7/H-1-2
     public static final String R7_5__H_1_1 = "r7_5__h_1_1"; // 7.5/H-1-1
     public static final String R7_5__H_1_2 = "r7_5__h_1_2"; // 7.5/H-1-2
     public static final String R7_5__H_1_3 = "r7_5__h_1_3"; // 7.5/H-1-3
@@ -63,7 +73,8 @@
     public static final String R8_2__H_2_4 = "r8_2__h_2_4"; // 8.2/H-2-4
     public static final String RTBD = "tbd"; // placeholder for requirements without a set id
 
-    public static final String MAX_CONCURRENT_SESSIONS = "max_concurrent_sessions";
+    public static final String CONCURRENT_SESSIONS = "concurrent_sessions";
+    public static final String CONCURRENT_FPS = "concurrent_fps";
     public static final String SUPPORTED_PERFORMANCE_POINTS = "supported_performance_points";
     public static final String FRAMES_DROPPED = "frame_drops_per_30sec";
     public static final String FRAME_RATE = "frame_rate";
@@ -76,11 +87,8 @@
     public static final String NUM_4k_HW_DEC = "number_4k_hw_decoders";
     public static final String NUM_4k_HW_ENC = "number_4k_hw_encoders";
     public static final String SECURE_REQ_SATISFIED = "secure_requirement_satisfied_boolean";
-    public static final String WIDEWINE_SUPPORT = "widevine_support_boolean";
-    public static final String WIDEWINE_L1 = "widevine_l1_support_boolean";
-    public static final String WIDEWINE_L1_TIER3 = "widevine_l1_tier3_support_boolean";
-    public static final String OEM_CRYPTO_17_PLUS = "oem_crypto_version_17plus_boolean";
-    public static final String WIDEWINE_CDM_17_PLUS = "widevine_cdm_version_17plus_boolean";
+    public static final String NUM_CRYPTO_HW_SECURE_ALL_SUPPORT =
+        "number_crypto_hw_secure_all_support";
 
     public enum Result {
         NA, MET, UNMET
@@ -92,6 +100,7 @@
     public static final BiPredicate<Integer, Integer> INTEGER_LTE = RequirementConstants.lte();
     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();
 
     /**
      * Creates a >= predicate.
diff --git a/tests/mediapc/src/android/mediapc/cts/CodecInitializationLatencyTest.java b/tests/mediapc/src/android/mediapc/cts/CodecInitializationLatencyTest.java
index 0379090..5a4822d 100644
--- a/tests/mediapc/src/android/mediapc/cts/CodecInitializationLatencyTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/CodecInitializationLatencyTest.java
@@ -37,6 +37,7 @@
 import android.media.MediaRecorder;
 import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
+import android.os.SystemClock;
 import android.util.Log;
 import android.util.Pair;
 import android.view.Surface;
@@ -269,7 +270,6 @@
         }
     }
 
-    // TODO(b/218771970): Add cdd annotation
     /**
      * This test validates the initialization latency (time for codec create + configure) for
      * audio and hw video codecs.
@@ -282,7 +282,9 @@
     @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
     @CddTest(requirements = {
         "2.2.7.1/5.1/H-1-7",
-        "2.2.7.1/5.1/H-1-8",})
+        "2.2.7.1/5.1/H-1-8",
+        "2.2.7.1/5.1/H-1-12",
+        "2.2.7.1/5.1/H-1-13",})
     public void testInitializationLatency() throws Exception {
         MediaCodec codec = MediaCodec.createByCodecName(mCodecName);
         boolean isEncoder = codec.getCodecInfo().isEncoder();
@@ -347,7 +349,7 @@
         PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
         PerformanceClassEvaluator.CodecInitLatencyRequirement r5_1__H_1_Latency =
             isEncoder ? isAudio ? pce.addR5_1__H_1_8() : pce.addR5_1__H_1_7()
-                : isAudio ? pce.addR5_1__H_1_TBD2() : pce.addR5_1__H_1_TBD1();
+                : isAudio ? pce.addR5_1__H_1_13() : pce.addR5_1__H_1_12();
 
         r5_1__H_1_Latency.setCodecInitLatencyMs(initializationLatency);
 
@@ -435,14 +437,14 @@
             MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
             long enqueueTimeStamp = 0;
             long dequeueTimeStamp = 0;
-            long baseTimeStamp = System.nanoTime();
+            long baseTimeStamp = SystemClock.elapsedRealtimeNanos();
             mCodec = MediaCodec.createByCodecName(mEncoderName);
             resetContext(mIsAsync, false);
             mAsyncHandle.setCallBack(mCodec, mIsAsync);
             mCodec.configure(format, null, MediaCodec.CONFIGURE_FLAG_ENCODE, null);
-            long configureTimeStamp = System.nanoTime();
+            long configureTimeStamp = SystemClock.elapsedRealtimeNanos();
             mCodec.start();
-            long startTimeStamp = System.nanoTime();
+            long startTimeStamp = SystemClock.elapsedRealtimeNanos();
             if (mIsAsync) {
                 // We will keep on feeding the input to encoder until we see the first dequeued
                 // frame.
@@ -452,12 +454,12 @@
                         int bufferID = element.first;
                         MediaCodec.BufferInfo info = element.second;
                         if (info != null) {
-                            dequeueTimeStamp = System.nanoTime();
+                            dequeueTimeStamp = SystemClock.elapsedRealtimeNanos();
                             dequeueOutput(bufferID, info);
                             break;
                         } else {
                             if (enqueueTimeStamp == 0) {
-                                enqueueTimeStamp = System.nanoTime();
+                                enqueueTimeStamp = SystemClock.elapsedRealtimeNanos();
                             }
                             enqueueInput(bufferID);
                         }
@@ -469,14 +471,14 @@
                         int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
                         if (inputBufferId > 0) {
                             if (enqueueTimeStamp == 0) {
-                                enqueueTimeStamp = System.nanoTime();
+                                enqueueTimeStamp = SystemClock.elapsedRealtimeNanos();
                             }
                             enqueueInput(inputBufferId);
                         }
                     }
                     int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
                     if (outputBufferId >= 0) {
-                        dequeueTimeStamp = System.nanoTime();
+                        dequeueTimeStamp = SystemClock.elapsedRealtimeNanos();
                         dequeueOutput(outputBufferId, outInfo);
                         break;
                     }
@@ -531,14 +533,14 @@
             MediaFormat format = setUpSource(mTestFile);
             long enqueueTimeStamp = 0;
             long dequeueTimeStamp = 0;
-            long baseTimeStamp = System.nanoTime();
+            long baseTimeStamp = SystemClock.elapsedRealtimeNanos();
             mCodec = MediaCodec.createByCodecName(mDecoderName);
             resetContext(mIsAsync, false);
             mAsyncHandle.setCallBack(mCodec, mIsAsync);
             mCodec.configure(format, mSurface, 0, null);
-            long configureTimeStamp = System.nanoTime();
+            long configureTimeStamp = SystemClock.elapsedRealtimeNanos();
             mCodec.start();
-            long startTimeStamp = System.nanoTime();
+            long startTimeStamp = SystemClock.elapsedRealtimeNanos();
             if (mIsAsync) {
                 // We will keep on feeding the input to decoder until we see the first dequeued
                 // frame.
@@ -548,12 +550,12 @@
                         int bufferID = element.first;
                         MediaCodec.BufferInfo info = element.second;
                         if (info != null) {
-                            dequeueTimeStamp = System.nanoTime();
+                            dequeueTimeStamp = SystemClock.elapsedRealtimeNanos();
                             dequeueOutput(bufferID, info);
                             break;
                         } else {
                             if (enqueueTimeStamp == 0) {
-                                enqueueTimeStamp = System.nanoTime();
+                                enqueueTimeStamp = SystemClock.elapsedRealtimeNanos();
                             }
                             enqueueInput(bufferID);
                         }
@@ -565,14 +567,14 @@
                         int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
                         if (inputBufferId >= 0) {
                             if (enqueueTimeStamp == 0) {
-                                enqueueTimeStamp = System.nanoTime();
+                                enqueueTimeStamp = SystemClock.elapsedRealtimeNanos();
                             }
                             enqueueInput(inputBufferId);
                         }
                     }
                     int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
                     if (outputBufferId >= 0) {
-                        dequeueTimeStamp = System.nanoTime();
+                        dequeueTimeStamp = SystemClock.elapsedRealtimeNanos();
                         dequeueOutput(outputBufferId, outInfo);
                         break;
                     }
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java b/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
index 98c3347..ca7a17a 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
@@ -44,10 +44,7 @@
     static final int REQUIRED_MIN_CONCURRENT_INSTANCES = 6;
     static final int REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9 = 2;
     static final int REQUIRED_MIN_CONCURRENT_SECURE_INSTANCES = 2;
-    // allowed tolerance in measured fps vs expected fps in percentage, i.e. codecs achieving fps
-    // that is greater than (FPS_TOLERANCE_FACTOR * expectedFps) will be considered as
-    // passing the test
-    static final double FPS_TOLERANCE_FACTOR = 0.95;
+
     static ArrayList<String> mMimeList = new ArrayList<>();
     static Map<String, String> mTestFiles = new HashMap<>();
     static Map<String, String> m720pTestFiles = new HashMap<>();
@@ -89,8 +86,6 @@
     String mTestFile;
     final boolean mIsAsync;
 
-    double mMaxFrameRate;
-
     @Before
     public void isPerformanceClassCandidate() {
         Utils.assumeDeviceMeetsPerformanceClassPreconditions();
@@ -120,9 +115,11 @@
     }
 
     // Returns the max number of 30 fps instances that the given list of mimeCodecPairs
-    // supports. It also checks that the each codec supports 180 fps PerformancePoint.
+    // supports. It also checks that the each codec supports a PerformancePoint that covers
+    // required number of 30 fps instances.
     public int checkAndGetMaxSupportedInstancesForCodecCombinations(int height, int width,
-            ArrayList<Pair<String, String>> mimeCodecPairs) throws IOException {
+            ArrayList<Pair<String, String>> mimeCodecPairs, int requiredMinInstances)
+            throws IOException {
         int[] maxInstances = new int[mimeCodecPairs.size()];
         int[] maxFrameRates = new int[mimeCodecPairs.size()];
         int[] maxMacroBlockRates = new int[mimeCodecPairs.size()];
@@ -135,8 +132,7 @@
             assertTrue(pps.size() > 0);
 
             boolean hasVP9 = mimeCodecPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
-            int requiredFrameRate = getRequiredMinConcurrentInstances(hasVP9, mimeCodecPair.second,
-                    mimeCodecPair.first) * 30;
+            int requiredFrameRate = requiredMinInstances * 30;
 
             maxInstances[loopCount] = cap.getMaxSupportedInstances();
             PerformancePoint PPRes = new PerformancePoint(width, height, requiredFrameRate);
@@ -168,26 +164,13 @@
         int minOfMaxFrameRates = maxFrameRates[0];
         int minOfMaxMacroBlockRates = maxMacroBlockRates[0];
 
-        // Allow a tolerance in expected frame rate
-        mMaxFrameRate = minOfMaxFrameRates * FPS_TOLERANCE_FACTOR;
-
         // Calculate how many 30fps max instances it can support from it's mMaxFrameRate
         // amd maxMacroBlockRate. (assuming 16x16 macroblocks)
         return Math.min(minOfMaxInstances, Math.min((int) (minOfMaxFrameRates / 30.0),
                 (int) (minOfMaxMacroBlockRates / ((width / 16) * (height / 16)) / 30.0)));
     }
 
-    public int getRequiredMinConcurrentInstances(boolean hasVP9) throws IOException {
-        return getRequiredMinConcurrentInstances(hasVP9, null, null);
-    }
-
-    public int getRequiredMinConcurrentInstances(boolean hasVP9, String codecName, String mime)
-            throws IOException {
-        if (codecName != null && mime != null) {
-            if (isSecureSupportedCodec(codecName, mime)) {
-                return REQUIRED_MIN_CONCURRENT_SECURE_INSTANCES;
-            }
-        }
+    public int getRequiredMinConcurrentInstances720p(boolean hasVP9) throws IOException {
         // Below T, VP9 requires 60 fps at 720p and minimum of 2 instances
         if (!Utils.isTPerfClass() && hasVP9) {
             return REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9;
@@ -203,21 +186,4 @@
         codec.release();
         return isSecureSupported;
     }
-
-    boolean codecSupportsPP(String codecName, String mime, PerformancePoint reqPP)
-            throws IOException {
-        MediaCodec codec = MediaCodec.createByCodecName(codecName);
-        List<PerformancePoint> suppPPs =
-                codec.getCodecInfo().getCapabilitiesForType(mime).getVideoCapabilities()
-                        .getSupportedPerformancePoints();
-        assertTrue("Performance point not published by codec: " + codecName, suppPPs != null);
-        boolean codecSupportsReqPP = false;
-        for (PerformancePoint pp : suppPPs) {
-            if (pp.covers(reqPP)) {
-                codecSupportsReqPP = true;
-            }
-        }
-        codec.release();
-        return codecSupportsReqPP;
-    }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
index 6694a46..0c69346 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
@@ -20,8 +20,8 @@
 
 import android.media.MediaCodecInfo;
 import android.media.MediaFormat;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
-import android.os.Build;
 import android.util.Pair;
 
 import androidx.test.filters.LargeTest;
@@ -33,7 +33,9 @@
 import com.android.compatibility.common.util.ResultUnit;
 
 import org.junit.Assume;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -68,6 +70,9 @@
         mSecondPair = secondPair;
     }
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     // Returns the list of params with two hardware (mime - decoder) pairs in both
     // sync and async modes.
     // Parameters {0}_{1}_{2} -- Pair(Mime DecoderName)_Pair(Mime DecoderName)_isAsync
@@ -110,7 +115,7 @@
 
         boolean hasVP9 = mFirstPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9) ||
                 mSecondPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
-        int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9);
+        int requiredMinInstances = getRequiredMinConcurrentInstances720p(hasVP9);
         testCodec(m720pTestFiles, 720, 1280, requiredMinInstances);
     }
 
@@ -122,99 +127,25 @@
      */
     @LargeTest
     @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    @CddTest(requirement = "2.2.7.1/5.1/H-1-1,H-1-2")
+    @CddTest(requirements = {
+            "2.2.7.1/5.1/H-1-1",
+            "2.2.7.1/5.1/H-1-2",
+            "2.2.7.1/5.1/H-1-9",
+            "2.2.7.1/5.1/H-1-10",})
     public void test1080p() throws Exception {
         Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
-        Assume.assumeFalse("Skipping regular performance tests for secure codecs",
-                isSecureSupportedCodec(mFirstPair.second, mFirstPair.first) ||
-                        isSecureSupportedCodec(mSecondPair.second, mSecondPair.first));
-        testCodec(m1080pTestFiles, 1080, 1920, REQUIRED_MIN_CONCURRENT_INSTANCES);
-    }
+        boolean isFirstSecure = isSecureSupportedCodec(mFirstPair.second, mFirstPair.first);
+        boolean isSecondSecure = isSecureSupportedCodec(mSecondPair.second, mSecondPair.first);
+        boolean onlyOneSecure = isFirstSecure ^ isSecondSecure;
+        boolean bothSecure = isFirstSecure & isSecondSecure;
 
-    /**
-     * Validates if hardware decoder pairs where one supports secure decode and required
-     * perf are present and tests with concurrent unsecure decoders
-     */
-    @LargeTest
-    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    // TODO(b/218771970) Add @CddTest annotation
-    public void testReqSecureWithUnsecureDecodeSupport() throws Exception {
-        Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
-        Assume.assumeTrue("Testing if only one of the pair is secure",
-                isSecureSupportedCodec(mFirstPair.second, mFirstPair.first) ^
-                        isSecureSupportedCodec(mSecondPair.second, mSecondPair.first));
-
-        MediaCodecInfo.VideoCapabilities.PerformancePoint reqSecurePP =
-                new MediaCodecInfo.VideoCapabilities.PerformancePoint(1920, 1080, 30);
-
-        MediaCodecInfo.VideoCapabilities.PerformancePoint reqNonSecurePP =
-                new MediaCodecInfo.VideoCapabilities.PerformancePoint(1920, 1080,
-                        30 * REQUIRED_CONCURRENT_NON_SECURE_INSTANCES_WITH_SECURE);
-
-        boolean codecSupportsReqPP = codecSupportsPP(mFirstPair.second, mFirstPair.first,
-                isSecureSupportedCodec(mFirstPair.second, mFirstPair.first) ? reqSecurePP :
-                        reqNonSecurePP);
-
-        codecSupportsReqPP &= codecSupportsPP(mSecondPair.second, mSecondPair.first,
-                isSecureSupportedCodec(mSecondPair.second, mSecondPair.first) ? reqSecurePP :
-                        reqNonSecurePP);
-
-        testCodec(m1080pTestFiles, 1080, 1920,
-                REQUIRED_CONCURRENT_NON_SECURE_INSTANCES_WITH_SECURE + 1, true);
-
-        if (Utils.isTPerfClass()) {
-            assertTrue(
-                    "Required Secure Decode Support required for MPC >= Android T, unsupported " +
-                            "codec pair: " + mFirstPair.second + "," + mSecondPair.second,
-                    codecSupportsReqPP);
+        if (bothSecure) {
+            testCodec(null, 1080, 1920, REQUIRED_MIN_CONCURRENT_SECURE_INSTANCES);
+        } else if (onlyOneSecure) {
+            testCodec(m1080pTestFiles, 1080, 1920,
+                    REQUIRED_CONCURRENT_NON_SECURE_INSTANCES_WITH_SECURE + 1, true);
         } else {
-            DeviceReportLog log =
-                    new DeviceReportLog("MediaPerformanceClassLogs", "SecureDecodeSupport");
-            log.addValue("Req Secure Decode Support pair: " + mFirstPair.second + "," +
-                    mSecondPair.second, codecSupportsReqPP, ResultType.NEUTRAL, ResultUnit.NONE);
-            // TODO(b/218771970) Log CDD sections
-            log.setSummary("MPC 13: Secure Decode requirements", 0, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
-        }
-    }
-
-    /**
-     * Validates if hardware decoder pairs where both supports secure decode and required
-     * perf is present
-     */
-    @LargeTest
-    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    // TODO(b/218771970) Add @CddTest annotation
-    public void testReqMultiSecureDecodeSupport() throws Exception {
-        Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
-        Assume.assumeTrue("Run test if both are secure codecs",
-                isSecureSupportedCodec(mFirstPair.second, mFirstPair.first) &&
-                        isSecureSupportedCodec(mSecondPair.second, mSecondPair.first));
-
-        MediaCodecInfo.VideoCapabilities.PerformancePoint reqSecurePP =
-                new MediaCodecInfo.VideoCapabilities.PerformancePoint(1920, 1080, 30);
-
-        boolean codecSupportsReqPP =
-                codecSupportsPP(mFirstPair.second, mFirstPair.first, reqSecurePP);
-        codecSupportsReqPP &= codecSupportsPP(mSecondPair.second, mSecondPair.first, reqSecurePP);
-
-        testCodec(null, 1080, 1920, REQUIRED_MIN_CONCURRENT_SECURE_INSTANCES);
-
-        if (Utils.isTPerfClass()) {
-            assertTrue(
-                    "Required Secure Decode Support required for MPC >= Android T, unsupported " +
-                            "codec pair: " + mFirstPair.second + "," + mSecondPair.second,
-                    codecSupportsReqPP);
-        } else {
-            DeviceReportLog log =
-                    new DeviceReportLog("MediaPerformanceClassLogs", "SecureDecodeSupport");
-            log.addValue("Req Secure Decode Support pair: " + mFirstPair.second + "," +
-                    mSecondPair.second, codecSupportsReqPP, ResultType.NEUTRAL, ResultUnit.NONE);
-            // TODO(b/218771970) Log CDD sections
-            log.setSummary("MPC 13: Secure Decode requirements", 0, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
+            testCodec(m1080pTestFiles, 1080, 1920, REQUIRED_MIN_CONCURRENT_INSTANCES);
         }
     }
 
@@ -229,8 +160,9 @@
         ArrayList<Pair<String, String>> mimeDecoderPairs = new ArrayList<>();
         mimeDecoderPairs.add(mFirstPair);
         mimeDecoderPairs.add(mSecondPair);
+        boolean bothSecure = true;
         int maxInstances = checkAndGetMaxSupportedInstancesForCodecCombinations(height, width,
-                mimeDecoderPairs);
+                mimeDecoderPairs, requiredMinInstances);
         double achievedFrameRate = 0.0;
         // secure test should not reach this point if secure codec doesn't support PP
         if (maxInstances >= requiredMinInstances || secureWithUnsecure) {
@@ -245,6 +177,7 @@
             List<Decode> testList = new ArrayList<>();
             for (int i = 0; i < firstPairInstances; i++) {
                 boolean isSecure = isSecureSupportedCodec(mFirstPair.second, mFirstPair.first);
+                bothSecure &= isSecure;
                 String testFile = isSecure ? m1080pWidevineTestFiles.get(mFirstPair.first) :
                         mTestFiles.get(mFirstPair.first);
                 Assume.assumeTrue("Add " + (isSecure ? "secure" : "") + " test vector for mime: " +
@@ -254,6 +187,7 @@
             }
             for (int i = 0; i < secondPairInstances; i++) {
                 boolean isSecure = isSecureSupportedCodec(mSecondPair.second, mSecondPair.first);
+                bothSecure &= isSecure;
                 String testFile = isSecure ? m1080pWidevineTestFiles.get(mSecondPair.first) :
                         mTestFiles.get(mSecondPair.first);
                 Assume.assumeTrue("Add " + (isSecure ? "secure" : "") + " test vector for mime: " +
@@ -267,29 +201,30 @@
                 achievedFrameRate += result.get();
             }
         }
-        if (Utils.isPerfClass()) {
-            assertTrue("Decoder pair " + mFirstPair.second + " and " + mSecondPair.second
-                            + " unable to support minimum concurrent " +
-                            "instances. act/exp: " + maxInstances + "/" + requiredMinInstances,
-                    maxInstances >= requiredMinInstances);
 
-            assertTrue("Unable to achieve the maxFrameRate supported. act/exp: " + achievedFrameRate
-                            + "/" + mMaxFrameRate + " for " + maxInstances + " instances.",
-                    achievedFrameRate >= mMaxFrameRate);
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        if (secureWithUnsecure) {
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_10 =
+                pce.addR5_1__H_1_10();
+            r5_1__H_1_10.setConcurrentFps(achievedFrameRate);
+        } else if (bothSecure) {
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_9 = pce.addR5_1__H_1_9();
+            r5_1__H_1_9.setConcurrentFps(achievedFrameRate);
         } else {
-            int pc = maxInstances >= requiredMinInstances && achievedFrameRate >= mMaxFrameRate
-                    ? Build.VERSION_CODES.R : 0;
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
-                    "MultiDecoderPairPerf_" + mFirstPair.second);
-            log.addValue("decoders",
-                    mFirstPair.first + "_" + mFirstPair.second + "_" + mSecondPair.first + "_"
-                            + mSecondPair.second, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.addValue("achieved_framerate", achievedFrameRate, ResultType.HIGHER_BETTER,
-                    ResultUnit.NONE);
-            log.addValue("expected_framerate", mMaxFrameRate, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.setSummary("CDD 2.2.7.1/5.1/H-1-1,H-1-2 performance_class", pc, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_1;
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_2;
+            if (height >= 1080) {
+                r5_1__H_1_1 = pce.addR5_1__H_1_1_1080p();
+                r5_1__H_1_2 = pce.addR5_1__H_1_2_1080p();
+                r5_1__H_1_1.setConcurrentInstances(maxInstances);
+                r5_1__H_1_2.setConcurrentFps(achievedFrameRate);
+            } else {
+                r5_1__H_1_1 = pce.addR5_1__H_1_1_720p(mMime, mMime, height);
+                r5_1__H_1_2 = pce.addR5_1__H_1_2_720p(mMime, mMime, height);
+                r5_1__H_1_1.setConcurrentInstances(maxInstances);
+                r5_1__H_1_2.setConcurrentFps(achievedFrameRate);
+            }
         }
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
index 62c7f83..13203cc 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
@@ -18,10 +18,9 @@
 
 import static org.junit.Assert.assertTrue;
 
-import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
 import android.media.MediaFormat;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
-import android.os.Build;
 import android.util.Pair;
 
 import androidx.test.filters.LargeTest;
@@ -33,7 +32,9 @@
 import com.android.compatibility.common.util.ResultUnit;
 
 import org.junit.Assume;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -62,6 +63,9 @@
         mDecoderName = decoderName;
     }
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     // Returns the params list with the mime and corresponding hardware decoders in
     // both sync and async modes.
     // Parameters {0}_{1}_{2} -- Mime_DecoderName_isAsync
@@ -92,56 +96,28 @@
         Assume.assumeFalse("Skipping regular performance tests for secure codecs",
                 isSecureSupportedCodec(mDecoderName, mMime));
         boolean hasVP9 = mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
-        int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9);
+        int requiredMinInstances = getRequiredMinConcurrentInstances720p(hasVP9);
         testCodec(m720pTestFiles, 720, 1280, requiredMinInstances);
     }
 
     /**
-     * This test validates that the decoder can support at least 6 concurrent 1080p 30fps
-     * decoder instances. Also ensures that all the concurrent sessions succeed in decoding
-     * with meeting the expected frame rate.
+     * This test validates that the decoder can support at least 6 non-secure/2 secure concurrent
+     * 1080p 30fps decoder instances. Also ensures that all the concurrent sessions succeed in
+     * decoding with meeting the expected frame rate.
      */
     @LargeTest
     @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    @CddTest(requirement = "2.2.7.1/5.1/H-1-1,H-1-2")
+    @CddTest(requirements = {
+            "2.2.7.1/5.1/H-1-1",
+            "2.2.7.1/5.1/H-1-2",
+            "2.2.7.1/5.1/H-1-9",})
     public void test1080p() throws Exception {
         Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
-        Assume.assumeFalse("Skipping regular performance tests for secure codecs",
-                isSecureSupportedCodec(mDecoderName, mMime));
-        testCodec(m1080pTestFiles, 1080, 1920, REQUIRED_MIN_CONCURRENT_INSTANCES);
-    }
-
-    /**
-     * Validates if hardware decoder that supports required secure decode perf is present
-     */
-    @LargeTest
-    @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    // TODO(b/218771970) Add @CddTest annotation
-    public void testReqSecureDecodeSupport() throws Exception {
-        Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
-        Assume.assumeTrue("Skipping secure decode support tests for non-secure codecs",
-                isSecureSupportedCodec(mDecoderName, mMime));
-
-        PerformancePoint reqPP =
-                new PerformancePoint(1920, 1080, 30 * REQUIRED_MIN_CONCURRENT_SECURE_INSTANCES);
-
-        boolean codecSupportsReqPP = codecSupportsPP(mDecoderName, mMime, reqPP);
-
-        testCodec(m1080pWidevineTestFiles, 1080, 1920, REQUIRED_MIN_CONCURRENT_SECURE_INSTANCES);
-
-        if (Utils.isTPerfClass()) {
-            assertTrue(
-                    "Required Secure Decode Support required for MPC >= Android T, unsupported " +
-                            "codec: " + mDecoderName, codecSupportsReqPP);
+        if (isSecureSupportedCodec(mDecoderName, mMime)) {
+            testCodec(m1080pWidevineTestFiles, 1080, 1920,
+                    REQUIRED_MIN_CONCURRENT_SECURE_INSTANCES);
         } else {
-            DeviceReportLog log =
-                    new DeviceReportLog("MediaPerformanceClassLogs", "SecureDecodeSupport");
-            log.addValue("Req Secure Decode Support: " + mDecoderName, codecSupportsReqPP,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-            // TODO(b/218771970) Log CDD sections
-            log.setSummary("MPC 13: Secure Decode requirements", 0, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
+            testCodec(m1080pTestFiles, 1080, 1920, REQUIRED_MIN_CONCURRENT_INSTANCES);
         }
     }
 
@@ -151,15 +127,15 @@
         Assume.assumeTrue("Add test vector for mime: " + mMime, mTestFile != null);
         ArrayList<Pair<String, String>> mimeDecoderPairs = new ArrayList<>();
         mimeDecoderPairs.add(Pair.create(mMime, mDecoderName));
+        boolean isSecure = isSecureSupportedCodec(mDecoderName, mMime);
         int maxInstances =
                 checkAndGetMaxSupportedInstancesForCodecCombinations(height, width,
-                        mimeDecoderPairs);
+                        mimeDecoderPairs, requiredMinInstances);
         double achievedFrameRate = 0.0;
         if (maxInstances >= requiredMinInstances) {
             ExecutorService pool = Executors.newFixedThreadPool(maxInstances);
             List<Decode> testList = new ArrayList<>();
             for (int i = 0; i < maxInstances; i++) {
-                boolean isSecure = isSecureSupportedCodec(mDecoderName, mMime);
                 testList.add(new Decode(mMime, mTestFile, mDecoderName, mIsAsync, isSecure));
             }
             List<Future<Double>> resultList = pool.invokeAll(testList);
@@ -167,26 +143,26 @@
                 achievedFrameRate += result.get();
             }
         }
-        if (Utils.isPerfClass()) {
-            assertTrue("Decoder " + mDecoderName + " unable to support minimum concurrent " +
-                            "instances. act/exp: " + maxInstances + "/" + requiredMinInstances,
-                    maxInstances >= requiredMinInstances);
-            assertTrue("Unable to achieve the maxFrameRate supported. act/exp: " + achievedFrameRate
-                            + "/" + mMaxFrameRate + " for " + maxInstances + " instances.",
-                    achievedFrameRate >= mMaxFrameRate);
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        if (isSecure) {
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_9 = pce.addR5_1__H_1_9();
+            r5_1__H_1_9.setConcurrentFps(achievedFrameRate);
         } else {
-            int pc = maxInstances >= requiredMinInstances && achievedFrameRate >= mMaxFrameRate
-                    ? Build.VERSION_CODES.R : 0;
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
-                    "MultiDecoderPerf_" + mDecoderName);
-            log.addValue("decoders", mMime + "_" + mDecoderName, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.addValue("achieved_framerate", achievedFrameRate, ResultType.HIGHER_BETTER,
-                    ResultUnit.NONE);
-            log.addValue("expected_framerate", mMaxFrameRate, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.setSummary("CDD 2.2.7.1/5.1/H-1-1,H-1-2 performance_class", pc, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_1;
+            PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_2;
+            if (height >= 1080) {
+                r5_1__H_1_1 = pce.addR5_1__H_1_1_1080p();
+                r5_1__H_1_2 = pce.addR5_1__H_1_2_1080p();
+                r5_1__H_1_1.setConcurrentInstances(maxInstances);
+                r5_1__H_1_2.setConcurrentFps(achievedFrameRate);
+            } else {
+                r5_1__H_1_1 = pce.addR5_1__H_1_1_720p(mMime, mMime, height);
+                r5_1__H_1_2 = pce.addR5_1__H_1_2_720p(mMime, mMime, height);
+                r5_1__H_1_1.setConcurrentInstances(maxInstances);
+                r5_1__H_1_2.setConcurrentFps(achievedFrameRate);
+            }
         }
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
index 01e68d3..1997c6b 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
@@ -16,24 +16,19 @@
 
 package android.mediapc.cts;
 
-import static org.junit.Assert.assertTrue;
-
 import android.media.MediaFormat;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
-import android.os.Build;
-import android.util.Log;
 import android.util.Pair;
 
 import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
 
 import org.junit.Assume;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -66,6 +61,9 @@
         mSecondPair = secondPair;
     }
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     // Returns the list of params with two hardware (mime - encoder) pairs in both
     // sync and async modes.
     // Parameters {0}_{1}_{2} -- Pair(Mime EncoderName)_Pair(Mime EncoderName)_isAsync
@@ -105,7 +103,7 @@
 
         boolean hasVP9 = mFirstPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9) ||
                 mSecondPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
-        int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9);
+        int requiredMinInstances = getRequiredMinConcurrentInstances720p(hasVP9);
         testCodec(720, 1280, 4000000, requiredMinInstances);
     }
 
@@ -129,7 +127,7 @@
         mimeEncoderPairs.add(mFirstPair);
         mimeEncoderPairs.add(mSecondPair);
         int maxInstances = checkAndGetMaxSupportedInstancesForCodecCombinations(height, width,
-                mimeEncoderPairs);
+                mimeEncoderPairs, requiredMinInstances);
         double achievedFrameRate = 0.0;
         if (maxInstances >= requiredMinInstances) {
             int secondPairInstances = maxInstances / 2;
@@ -151,22 +149,22 @@
                 achievedFrameRate += result.get();
             }
         }
-        if (Utils.isPerfClass()) {
-            assertTrue("Encoder pair " + mFirstPair.second + " and " + mSecondPair.second
-                    + " unable to support minimum concurrent instances. act/exp: " + maxInstances
-                    + "/" + requiredMinInstances, maxInstances >= requiredMinInstances);
-            Log.v(LOG_TAG, "Achieved fps: " + achievedFrameRate +
-                    "\nAchieved frame rate is not compared as this test runs in byte buffer mode");
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_3;
+        PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_4;
+        // Achieved frame rate is not compared as this test runs in byte buffer mode.
+        if (height >= 1080) {
+            r5_1__H_1_3 = pce.addR5_1__H_1_3_1080p();
+            r5_1__H_1_4 = pce.addR5_1__H_1_4_1080p();
+            r5_1__H_1_3.setConcurrentInstances(maxInstances);
+            r5_1__H_1_4.setConcurrentFps(achievedFrameRate);
         } else {
-            int pc = maxInstances >= requiredMinInstances ? Build.VERSION_CODES.R : 0;
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
-                    "MultiEncoderPairPerf_" + mFirstPair.second);
-            log.addValue("encoders",
-                    mFirstPair.first + "_" + mFirstPair.second + "_" + mSecondPair.first + "_"
-                            + mSecondPair.second, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.setSummary("CDD 2.2.7.1/5.1/H-1-3,H-1-4 performance_class", pc, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
+            r5_1__H_1_3 = pce.addR5_1__H_1_3_720p(mMime, mMime, height);
+            r5_1__H_1_4 = pce.addR5_1__H_1_4_720p();
+            r5_1__H_1_3.setConcurrentInstances(maxInstances);
+            r5_1__H_1_4.setConcurrentFps(achievedFrameRate);
         }
+
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
index 28c7fbd..66afa89 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
@@ -16,24 +16,19 @@
 
 package android.mediapc.cts;
 
-import static org.junit.Assert.assertTrue;
-
 import android.media.MediaFormat;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
-import android.os.Build;
-import android.util.Log;
 import android.util.Pair;
 
 import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
 
 import org.junit.Assume;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -62,6 +57,9 @@
         mEncoderName = encoderName;
     }
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     // Returns the params list with the mime and their hardware encoders in
     // both sync and async modes.
     // Parameters {0}_{2}_{3} -- Mime_EncoderName_isAsync
@@ -90,7 +88,7 @@
         Assume.assumeTrue(Utils.isSPerfClass() || Utils.isRPerfClass() || !Utils.isPerfClass());
 
         boolean hasVP9 = mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
-        int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9);
+        int requiredMinInstances = getRequiredMinConcurrentInstances720p(hasVP9);
         testCodec(720, 1280, 4000000, requiredMinInstances);
     }
 
@@ -111,7 +109,7 @@
         ArrayList<Pair<String, String>> mimeEncoderPairs = new ArrayList<>();
         mimeEncoderPairs.add(Pair.create(mMime, mEncoderName));
         int maxInstances = checkAndGetMaxSupportedInstancesForCodecCombinations(height, width,
-                mimeEncoderPairs);
+                mimeEncoderPairs, requiredMinInstances);
         double achievedFrameRate = 0.0;
         if (maxInstances >= requiredMinInstances) {
             ExecutorService pool = Executors.newFixedThreadPool(maxInstances);
@@ -124,22 +122,22 @@
                 achievedFrameRate += result.get();
             }
         }
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_3;
+        PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_4;
         // Achieved frame rate is not compared as this test runs in byte buffer mode.
-        if (Utils.isPerfClass()) {
-            assertTrue("Encoder " + mEncoderName + " unable to support minimum concurrent " +
-                            "instances. act/exp: " + maxInstances + "/" + requiredMinInstances,
-                    maxInstances >= requiredMinInstances);
-            Log.v(LOG_TAG, "Achieved fps: " + achievedFrameRate +
-                    "\nAchieved frame rate is not compared as this test runs in byte buffer mode");
+        if (height >= 1080) {
+            r5_1__H_1_3 = pce.addR5_1__H_1_3_1080p();
+            r5_1__H_1_4 = pce.addR5_1__H_1_4_1080p();
+            r5_1__H_1_3.setConcurrentInstances(maxInstances);
+            r5_1__H_1_4.setConcurrentFps(achievedFrameRate);
         } else {
-            int pc = maxInstances >= requiredMinInstances ? Build.VERSION_CODES.R : 0;
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
-                    "MultiEncoderPerf_" + mEncoderName);
-            log.addValue("encoder", mMime + "_" + mEncoderName, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.setSummary("CDD 2.2.7.1/5.1/H-1-3,H-1-4 performance_class", pc, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
+            r5_1__H_1_3 = pce.addR5_1__H_1_3_720p(mMime, mMime, height);
+            r5_1__H_1_4 = pce.addR5_1__H_1_4_720p();
+            r5_1__H_1_3.setConcurrentInstances(maxInstances);
+            r5_1__H_1_4.setConcurrentFps(achievedFrameRate);
         }
+
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
index 9312637..34ffc9b 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
@@ -19,23 +19,20 @@
 import static org.junit.Assert.assertTrue;
 
 import android.media.MediaFormat;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.mediapc.cts.common.Utils;
-import android.os.Build;
 import android.util.Pair;
 import android.view.Surface;
 
 import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
 
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
 
 import org.junit.Assume;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -73,6 +70,9 @@
         mEncoderPair = encoderPair;
     }
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     // Parameters {0}_{1}_{2} -- Pair(Mime DecoderName)_Pair(Mime EncoderName)_isAsync
     @Parameterized.Parameters(name = "{index}({0}_{1}_{2})")
     public static Collection<Object[]> inputParams() {
@@ -115,7 +115,7 @@
 
         boolean hasVP9 = mDecoderPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9)
                 || mEncoderPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
-        int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9) / 2;
+        int requiredMinInstances = getRequiredMinConcurrentInstances720p(hasVP9);
         testCodec(m720pTestFiles, 720, 1280, requiredMinInstances);
     }
 
@@ -131,7 +131,7 @@
     @CddTest(requirement = "2.2.7.1/5.1/H-1-5,H-1-6")
     public void test1080p() throws Exception {
         Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
-        testCodec(m1080pTestFiles, 1080, 1920, REQUIRED_MIN_CONCURRENT_INSTANCES / 2);
+        testCodec(m1080pTestFiles, 1080, 1920, REQUIRED_MIN_CONCURRENT_INSTANCES);
     }
 
     private void testCodec(Map<String, String> testFiles, int height, int width,
@@ -141,7 +141,8 @@
         mimeCodecPairs.add(mDecoderPair);
         mimeCodecPairs.add(mEncoderPair);
         int maxInstances =
-                checkAndGetMaxSupportedInstancesForCodecCombinations(height, width, mimeCodecPairs);
+                checkAndGetMaxSupportedInstancesForCodecCombinations(height, width, mimeCodecPairs,
+                        requiredMinInstances);
         double achievedFrameRate = 0.0;
         if (maxInstances >= requiredMinInstances) {
             ExecutorService pool =
@@ -175,29 +176,22 @@
                 }
             }
         }
-        if (Utils.isPerfClass()) {
-            assertTrue("DecodeMime: " + mDecoderPair.first + ", Decoder " + mDecoderPair.second +
-                    ", EncodeMime: " + mEncoderPair.first + ", Encoder: " + mEncoderPair.second +
-                    ", unable to support minimum concurrent instances. act/exp: " + maxInstances +
-                    "/" + requiredMinInstances, maxInstances >= requiredMinInstances);
 
-            assertTrue("Unable to achieve the maxFrameRate supported. act/exp: " + achievedFrameRate
-                            + "/" + mMaxFrameRate / 2 + " for " + maxInstances + " instances.",
-                    achievedFrameRate >= mMaxFrameRate / 2);
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_5;
+        PerformanceClassEvaluator.ConcurrentCodecRequirement r5_1__H_1_6;
+        if (height >= 1080) {
+            r5_1__H_1_5 = pce.addR5_1__H_1_5_1080p();
+            r5_1__H_1_6 = pce.addR5_1__H_1_6_1080p();
+            r5_1__H_1_5.setConcurrentInstances(maxInstances);
+            r5_1__H_1_6.setConcurrentFps(achievedFrameRate);
         } else {
-            int pc = maxInstances >= requiredMinInstances && achievedFrameRate >= mMaxFrameRate / 2
-                    ? Build.VERSION_CODES.R : 0;
-            DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
-                    "MultiTranscoderPairPerf_" + mDecoderPair.second);
-            log.addValue("decoders", mDecoderPair.first + "_" + mDecoderPair.second + "_"
-                            + mEncoderPair.first + "_" + mEncoderPair.second, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.addValue("achieved_framerate", achievedFrameRate, ResultType.HIGHER_BETTER,
-                    ResultUnit.NONE);
-            log.addValue("expected_framerate", mMaxFrameRate, ResultType.NEUTRAL, ResultUnit.NONE);
-            log.setSummary("CDD 2.2.7.1/5.1/H-1-5,H-1-6 performance_class", pc, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-            log.submit(InstrumentationRegistry.getInstrumentation());
+            r5_1__H_1_5 = pce.addR5_1__H_1_5_720p(mDecoderPair.first, mEncoderPair.first, height);
+            r5_1__H_1_6 = pce.addR5_1__H_1_6_720p(mDecoderPair.first, mEncoderPair.first, height);
+            r5_1__H_1_5.setConcurrentInstances(maxInstances);
+            r5_1__H_1_6.setConcurrentFps(achievedFrameRate);
         }
+
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
index 24b22ea..2508845 100644
--- a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
@@ -17,7 +17,7 @@
 package android.mediapc.cts;
 
 import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_SecurePlayback;
-
+import static android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_ALL;
 import static org.junit.Assert.assertTrue;
 
 import android.app.ActivityManager;
@@ -33,30 +33,26 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.WindowManager;
-
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
-
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
 import org.junit.Assume;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.UUID;
-
 /**
  * Tests the basic aspects of the media performance class.
  */
 public class PerformanceClassTest {
     private static final String TAG = "PerformanceClassTest";
-    private static final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
+    public static final String[] VIDEO_CONTAINER_MEDIA_TYPES =
+        {"video/mp4", "video/webm", "video/3gpp", "video/3gpp2", "video/avi", "video/x-ms-wmv",
+            "video/x-ms-asf"};
     static ArrayList<String> mMimeSecureSupport = new ArrayList<>();
 
     @Rule
@@ -83,8 +79,8 @@
 
     @SmallTest
     @Test
-    // TODO(b/218771970) Add @CddTest annotation
-    public void testSecureHwDecodeSupport() throws IOException {
+    @CddTest(requirements = {"2.2.7.1/5.1/H-1-11"})
+    public void testSecureHwDecodeSupport() {
         ArrayList<String> noSecureHwDecoderForMimes = new ArrayList<>();
         for (String mime : mMimeSecureSupport) {
             boolean isSecureHwDecoderFoundForMime = false;
@@ -110,46 +106,35 @@
         boolean secureDecodeSupportIfHwDecoderPresent = noSecureHwDecoderForMimes.isEmpty();
 
         PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
-        PerformanceClassEvaluator.SecureCodecRequirement rSecureDecodeSupport =
-            pce.addRSecureDecodeSupport();
-        rSecureDecodeSupport.setSecureReqSatisfied(secureDecodeSupportIfHwDecoderPresent);
+        PerformanceClassEvaluator.SecureCodecRequirement r5_1__H_1_11 = pce.addR5_1__H_1_11();
+        r5_1__H_1_11.setSecureReqSatisfied(secureDecodeSupportIfHwDecoderPresent);
 
         pce.submitAndCheck();
     }
 
     @SmallTest
     @Test
-    // TODO(b/218771970) Add @CddTest annotation
-    public void testWidevineSupport() throws UnsupportedSchemeException {
-        boolean isWidevineSupported = MediaDrm.isCryptoSchemeSupported(WIDEVINE_UUID);
-        boolean isL1Supported = false;
-        boolean isL1Tier3Supported = false;
-        boolean isOemCrypto17Plus = false;
-        boolean isWidevineCdm17Plus = false;
-        if (isWidevineSupported) {
-            MediaDrm mediaDrm = new MediaDrm(WIDEVINE_UUID);
-            isL1Supported = mediaDrm.getPropertyString("securityLevel").equals("L1");
-            int tier = Integer.parseInt(mediaDrm.getPropertyString("resourceRatingTier"));
-            isL1Tier3Supported = tier >= 3;
+    @CddTest(requirements = {"2.2.7.1/5.7/H-1-2"})
+    public void testMediaDrmSecurityLevelHwSecureAll() throws UnsupportedSchemeException {
+        List<UUID> drmList = MediaDrm.getSupportedCryptoSchemes();
+        List<UUID> supportedHwSecureAllSchemes = new ArrayList<>();
 
-            String oemCryptoVersionProperty = mediaDrm.getPropertyString("oemCryptoApiVersion");
-            int oemCryptoVersion = Integer.parseInt(oemCryptoVersionProperty);
-            isOemCrypto17Plus = oemCryptoVersion >= 17;
-
-            String cdmVersionProperty = mediaDrm.getPropertyString(MediaDrm.PROPERTY_VERSION);
-            int cdmMajorVersion = Integer.parseInt(cdmVersionProperty.split("\\.", 2)[0]);
-            isWidevineCdm17Plus = cdmMajorVersion >= 17;
+        for (UUID cryptoSchemeUUID : drmList) {
+            boolean cryptoSchemeSupportedForAtleastOneMediaType = false;
+            for (String mediaType : VIDEO_CONTAINER_MEDIA_TYPES) {
+                cryptoSchemeSupportedForAtleastOneMediaType |= MediaDrm
+                    .isCryptoSchemeSupported(cryptoSchemeUUID, mediaType,
+                        SECURITY_LEVEL_HW_SECURE_ALL);
+            }
+            if (cryptoSchemeSupportedForAtleastOneMediaType) {
+                supportedHwSecureAllSchemes.add(cryptoSchemeUUID);
+            }
         }
 
         PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
-        PerformanceClassEvaluator.SecureCodecRequirement rWidevineReqSupport =
-            pce.addRWidevineSupport();
+        PerformanceClassEvaluator.SecureCodecRequirement r5_7__H_1_2 = pce.addR5_7__H_1_2();
 
-        rWidevineReqSupport.setWidevineSupported(isWidevineSupported);
-        rWidevineReqSupport.setWidevineL1Supported(isL1Supported);
-        rWidevineReqSupport.setWidevineL1Tier3Supported(isL1Tier3Supported);
-        rWidevineReqSupport.setOemCrypto17Plus(isOemCrypto17Plus);
-        rWidevineReqSupport.setWidevineCdm17Plus(isWidevineCdm17Plus);
+        r5_7__H_1_2.setNumCryptoHwSecureAllDec(supportedHwSecureAllSchemes.size());
 
         pce.submitAndCheck();
     }
@@ -190,19 +175,15 @@
         PerformanceClassEvaluator.DensityRequirement r7_1_1_3__h_1_1 = pce.addR7_1_1_3__H_1_1();
         PerformanceClassEvaluator.ResolutionRequirement r7_1_1_1__h_2_1 = pce.addR7_1_1_1__H_2_1();
         PerformanceClassEvaluator.DensityRequirement r7_1_1_3__h_2_1 = pce.addR7_1_1_3__H_2_1();
-        PerformanceClassEvaluator.ResolutionRequirement r7_1_1_1__tbd1 = pce.addR7_1_1_1__TBD1();
-        PerformanceClassEvaluator.DensityRequirement r7_1_1_3__tbd2 = pce.addR7_1_1_3__TBD2();
 
         r7_1_1_1__h_1_1.setLongResolution(longPix);
         r7_1_1_1__h_2_1.setLongResolution(longPix);
-        r7_1_1_1__tbd1.setLongResolution(longPix);
+
         r7_1_1_1__h_1_1.setShortResolution(shortPix);
         r7_1_1_1__h_2_1.setShortResolution(shortPix);
-        r7_1_1_1__tbd1.setShortResolution(shortPix);
 
         r7_1_1_3__h_1_1.setDisplayDensity(density);
         r7_1_1_3__h_2_1.setDisplayDensity(density);
-        r7_1_1_3__tbd2.setDisplayDensity(density);
 
         pce.submitAndCheck();
     }
@@ -210,8 +191,7 @@
     @Test
     @CddTest(requirements={
         "2.2.7.3/7.6.1/H-1-1",
-        "2.2.7.3/7.6.1/H-2-1",
-        "2.2.7.3/7.6.1/H-3-1"})
+        "2.2.7.3/7.6.1/H-2-1",})
     public void testMinimumMemory() {
         Context context = InstrumentationRegistry.getInstrumentation().getContext();
 
@@ -224,11 +204,9 @@
         PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
         PerformanceClassEvaluator.MemoryRequirement r7_6_1_h_1_1 = pce.addR7_6_1__H_1_1();
         PerformanceClassEvaluator.MemoryRequirement r7_6_1_h_2_1 = pce.addR7_6_1__H_2_1();
-        PerformanceClassEvaluator.MemoryRequirement r7_6_1_h_3_1 = pce.addR7_6_1__H_3_1();
 
         r7_6_1_h_1_1.setPhysicalMemory(totalMemoryMb);
         r7_6_1_h_2_1.setPhysicalMemory(totalMemoryMb);
-        r7_6_1_h_3_1.setPhysicalMemory(totalMemoryMb);
 
         pce.submitAndCheck();
     }
diff --git a/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
index 4a9d39f..bbe26dc 100644
--- a/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
@@ -29,6 +29,7 @@
 import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.util.Log;
 import androidx.test.filters.LargeTest;
+import com.android.compatibility.common.util.CddTest;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -78,7 +79,7 @@
      */
     @LargeTest
     @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    // TODO(b/218771970) Add @CddTest annotation
+    @CddTest(requirement = "2.2.7.1/5.1/H-1-14")
     public void testAV1HwDecoderRequirements() throws Exception {
         MediaFormat format = MediaFormat.createVideoFormat(MIMETYPE_VIDEO_AV1, 1920, 1080);
         format.setInteger(MediaFormat.KEY_FRAME_RATE, 60);
@@ -107,7 +108,7 @@
      */
     @LargeTest
     @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    // TODO(b/218771970) Add @CddTest annotation
+    @CddTest(requirement = "2.2.7.1/5.1/H-1-15")
     public void test4k60Decoder() throws IOException {
         Set<String> decoderSet = get4k60HwCodecSet(false);
 
@@ -123,7 +124,7 @@
      */
     @LargeTest
     @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    // TODO(b/218771970) Add @CddTest annotation
+    @CddTest(requirement = "2.2.7.1/5.1/H-1-16")
     public void test4k60Encoder() throws IOException {
         Set<String> encoderSet = get4k60HwCodecSet(true);
 
diff --git a/tests/musicrecognition/Android.bp b/tests/musicrecognition/Android.bp
index 1b7298a..ecda10b 100644
--- a/tests/musicrecognition/Android.bp
+++ b/tests/musicrecognition/Android.bp
@@ -31,4 +31,8 @@
         "cts",
         "general-tests",
     ],
+    data: [
+        ":CtsOutsideOfPackageService",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/tests/net/src/android/net/cts/LocalSocketTest.java b/tests/net/src/android/net/cts/LocalSocketTest.java
index 39b5dbc..c302f81 100644
--- a/tests/net/src/android/net/cts/LocalSocketTest.java
+++ b/tests/net/src/android/net/cts/LocalSocketTest.java
@@ -30,12 +30,9 @@
 import android.net.LocalServerSocket;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
-import android.os.ParcelFileDescriptor;
-import android.os.SystemClock;
 import android.system.Os;
 import android.system.OsConstants;
 import android.system.StructTimeval;
-import android.system.UnixSocketAddress;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -196,7 +193,7 @@
     }
 
     // http://b/31205169
-    @Test
+    @Test @IgnoreUpTo(SC_V2)  // Crashes on pre-T due to a JNI bug. See http://r.android.com/2096720
     public void testSetSoTimeout_readTimeout() throws Exception {
         String address = ADDRESS_PREFIX + "_testSetSoTimeout_readTimeout";
 
diff --git a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
index 542b3aa..0e1bcd1 100644
--- a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
+++ b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
@@ -405,7 +405,8 @@
     private boolean supportsHardware() {
         final PackageManager pm = mContext.getPackageManager();
         return !pm.hasSystemFeature("android.hardware.type.television")
-                && !pm.hasSystemFeature("android.hardware.type.watch");
+                && !pm.hasSystemFeature("android.hardware.type.watch")
+                && !pm.hasSystemFeature("android.hardware.type.automotive");
     }
 
     public File getVolumePath(String volumeName) {
diff --git a/tests/tests/app.usage/Android.bp b/tests/tests/app.usage/Android.bp
index 74f5593..73baa1b 100644
--- a/tests/tests/app.usage/Android.bp
+++ b/tests/tests/app.usage/Android.bp
@@ -45,11 +45,13 @@
         "general-tests",
     ],
     data: [
-        ":CtsUsageStatsTestApp4",
+        ":CtsUsageStatsTestApp1",
         ":CtsUsageStatsTestApp2",
         ":CtsUsageStatsTestApp3",
-        ":CtsUsageStatsTestApp1",
+        ":CtsUsageStatsTestApp4",
         ":CtsUsageStatsTestAppApi32",
+        ":CtsUsageStatsTestAssistApp",
+        ":CtsUsageStatsTestExactAlarmApp",
     ],
     per_testcase_directory: true,
 }
@@ -127,3 +129,29 @@
         "--rename-manifest-package android.app.usage.cts.testapi32",
     ],
 }
+
+android_test_helper_app {
+    name: "CtsUsageStatsTestAssistApp",
+    defaults: ["test_app_defaults"],
+    resource_dirs: [
+        "TestApp1/res",
+        "TestAssistApp/res",
+    ],
+    manifest: "TestAssistApp/AndroidManifest.xml",
+    aaptflags: [
+        "--rename-manifest-package android.app.usage.cts.test.assist",
+    ],
+}
+
+android_test_helper_app {
+    name: "CtsUsageStatsTestExactAlarmApp",
+    defaults: ["test_app_defaults"],
+    resource_dirs: [
+        "TestApp1/res",
+        "TestExactAlarmApp/res",
+    ],
+    manifest: "TestExactAlarmApp/AndroidManifest.xml",
+    aaptflags: [
+        "--rename-manifest-package android.app.usage.cts.test.exactalarm",
+    ],
+}
diff --git a/tests/tests/app.usage/AndroidTest.xml b/tests/tests/app.usage/AndroidTest.xml
index 4326f98..5d4e7f5 100644
--- a/tests/tests/app.usage/AndroidTest.xml
+++ b/tests/tests/app.usage/AndroidTest.xml
@@ -30,6 +30,8 @@
         <option name="test-file-name" value="CtsUsageStatsTestApp3.apk" />
         <option name="test-file-name" value="CtsUsageStatsTestApp4.apk" />
         <option name="test-file-name" value="CtsUsageStatsTestAppApi32.apk" />
+        <option name="test-file-name" value="CtsUsageStatsTestAssistApp.apk" />
+        <option name="test-file-name" value="CtsUsageStatsTestExactAlarmApp.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.app.usage.cts" />
diff --git a/tests/tests/app.usage/TestAssistApp/AndroidManifest.xml b/tests/tests/app.usage/TestAssistApp/AndroidManifest.xml
new file mode 100644
index 0000000..dd34775
--- /dev/null
+++ b/tests/tests/app.usage/TestAssistApp/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.app.usage.cts.test1">
+    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
+
+    <application>
+        <activity android:name=".SomeActivity"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.ASSIST" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".SomeActivityWithLocus"
+                  android:exported="true" />
+        <service android:name=".TestService"
+                 android:exported="true" />
+        <receiver android:name=".TestBroadcastReceiver"
+                  android:exported="true" />
+        <provider android:name=".TestContentProvider"
+                  android:authorities="@string/authority"
+                  android:exported="true" />
+    </application>
+</manifest>
diff --git a/tests/tests/app.usage/TestAssistApp/res/values/config.xml b/tests/tests/app.usage/TestAssistApp/res/values/config.xml
new file mode 100644
index 0000000..5e21975
--- /dev/null
+++ b/tests/tests/app.usage/TestAssistApp/res/values/config.xml
@@ -0,0 +1,19 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="authority" translatable="false">android.app.usage.cts.test.assist.provider</string>
+</resources>
diff --git a/tests/tests/app.usage/TestExactAlarmApp/AndroidManifest.xml b/tests/tests/app.usage/TestExactAlarmApp/AndroidManifest.xml
new file mode 100644
index 0000000..c5d35b4
--- /dev/null
+++ b/tests/tests/app.usage/TestExactAlarmApp/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.app.usage.cts.test1">
+    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
+    <uses-permission android:name="android.permission.USE_EXACT_ALARM" />
+
+    <application>
+        <activity android:name=".SomeActivity"
+                  android:exported="true">
+        </activity>
+
+        <activity android:name=".SomeActivityWithLocus"
+                  android:exported="true" />
+        <service android:name=".TestService"
+                 android:exported="true" />
+        <receiver android:name=".TestBroadcastReceiver"
+                  android:exported="true" />
+        <provider android:name=".TestContentProvider"
+                  android:authorities="@string/authority"
+                  android:exported="true" />
+    </application>
+</manifest>
diff --git a/tests/tests/app.usage/TestExactAlarmApp/res/values/config.xml b/tests/tests/app.usage/TestExactAlarmApp/res/values/config.xml
new file mode 100644
index 0000000..086940f6
--- /dev/null
+++ b/tests/tests/app.usage/TestExactAlarmApp/res/values/config.xml
@@ -0,0 +1,19 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="authority" translatable="false">android.app.usage.cts.test.exactalarm.provider</string>
+</resources>
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/BroadcastResponseStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/BroadcastResponseStatsTest.java
index 2186632..6a56e5c 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/BroadcastResponseStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/BroadcastResponseStatsTest.java
@@ -17,6 +17,9 @@
 package android.app.usage.cts;
 
 import static android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS;
+import static android.Manifest.permission.INTERNET;
+import static android.Manifest.permission.PACKAGE_USAGE_STATS;
+import static android.Manifest.permission.USE_EXACT_ALARM;
 import static android.app.usage.cts.UsageStatsTest.TEST_APP_CLASS;
 import static android.app.usage.cts.UsageStatsTest.TEST_APP_CLASS_BROADCAST_RECEIVER;
 import static android.app.usage.cts.UsageStatsTest.TEST_APP_CLASS_SERVICE;
@@ -35,6 +38,7 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.UiAutomation;
+import android.app.role.RoleManager;
 import android.app.usage.BroadcastResponseStats;
 import android.app.usage.UsageStatsManager;
 import android.app.usage.cts.UsageStatsTest.TestServiceConnection;
@@ -44,6 +48,7 @@
 import android.graphics.drawable.Icon;
 import android.media.session.MediaSession;
 import android.os.Bundle;
+import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.SystemClock;
 import android.platform.test.annotations.AppModeFull;
@@ -76,6 +81,8 @@
 
     private static final String TEST_APP3_PKG = "android.app.usage.cts.test3";
     private static final String TEST_APP4_PKG = "android.app.usage.cts.test4";
+    private static final String TEST_ASSIST_APP_PKG = "android.app.usage.cts.test.assist";
+    private static final String TEST_EXACT_ALARM_APP_PKG = "android.app.usage.cts.test.exactalarm";
 
     private static final long TEST_RESPONSE_STATS_ID_1 = 11;
     private static final long TEST_RESPONSE_STATS_ID_2 = 22;
@@ -105,8 +112,12 @@
             "broadcast_sessions_duration_ms";
     private static final String KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS =
             "broadcast_sessions_with_response_duration_ms";
-    private static final String KEY_RECORD_ALL_BROADCAST_SESSIONS_WITHIN_RESPONSE_WINDOW =
-            "record_all_broadcast_sessions_within_response_window";
+    private static final String KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS =
+            "note_response_event_for_all_broadcast_sessions";
+    private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES =
+            "brodacast_response_exempted_roles";
+    private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS =
+            "brodacast_response_exempted_permissions";
 
     private static Context sContext;
     private static String sTargetPackage;
@@ -1737,7 +1748,7 @@
                     KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS,
                     String.valueOf(broadcastResponseWindowDurationMs));
             updateFlagWithDelay(deviceConfigStateHelper,
-                    KEY_RECORD_ALL_BROADCAST_SESSIONS_WITHIN_RESPONSE_WINDOW,
+                    KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS,
                     String.valueOf(false));
 
             assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
@@ -1822,6 +1833,205 @@
         }
     }
 
+    @AppModeFull(reason = "No broadcast message response stats in instant apps")
+    @Test
+    public void testBroadcastResponseStats_exemptedRole() throws Exception {
+        try (DeviceConfigStateHelper deviceConfigStateHelper =
+                new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
+            updateFlagWithDelay(deviceConfigStateHelper,
+                    KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES,
+                    RoleManager.ROLE_ASSISTANT);
+
+            assertResponseStats(TEST_ASSIST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+                    0 /* broadcastCount */,
+                    0 /* notificationPostedCount */,
+                    0 /* notificationUpdatedCount */,
+                    0 /* notificationCancelledCount */);
+            assertResponseStats(TEST_ASSIST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+                    0 /* broadcastCount */,
+                    0 /* notificationPostedCount */,
+                    0 /* notificationUpdatedCount */,
+                    0 /* notificationCancelledCount */);
+
+            final TestServiceConnection connection = bindToTestServiceAndGetConnection(
+                    TEST_ASSIST_APP_PKG);
+            try {
+                ITestReceiver testReceiver = connection.getITestReceiver();
+                testReceiver.cancelAll();
+
+                // Send a broadcast with a request to record response and verify broadcast-sent
+                // count gets incremented.
+                final Intent intent = new Intent().setComponent(new ComponentName(
+                        TEST_ASSIST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+                final BroadcastOptions options = BroadcastOptions.makeBasic();
+                options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+                sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+                testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+                        TEST_NOTIFICATION_CHANNEL_NAME,
+                        TEST_NOTIFICATION_CHANNEL_DESC);
+                testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+                        buildMediaNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+                                TEST_NOTIFICATION_TEXT_1));
+
+                assertResponseStats(TEST_ASSIST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+                        1 /* broadcastCount */,
+                        1 /* notificationPostedCount */,
+                        0 /* notificationUpdatedCount */,
+                        0 /* notificationCancelledCount */);
+
+                addAssistRoleHolder(TEST_ASSIST_APP_PKG, Process.myUserHandle().getIdentifier());
+
+                // Since the assistant role is exempted and the test app holds assist role,
+                // broadcast response stats for it would not be recorded.
+                sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+                testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+                        buildMediaNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+                                TEST_NOTIFICATION_TEXT_2));
+
+                assertResponseStats(TEST_ASSIST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+                        1 /* broadcastCount */,
+                        1 /* notificationPostedCount */,
+                        0 /* notificationUpdatedCount */,
+                        0 /* notificationCancelledCount */);
+
+                // Remove the assistant role from exempted roles and verify broadcast
+                // response stats for the test app are recorded.
+                updateFlagWithDelay(deviceConfigStateHelper,
+                        KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES,
+                        String.join("|", RoleManager.ROLE_BROWSER, RoleManager.ROLE_EMERGENCY));
+
+                sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+                testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
+
+                assertResponseStats(TEST_ASSIST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+                        2 /* broadcastCount */,
+                        1 /* notificationPostedCount */,
+                        0 /* notificationUpdatedCount */,
+                        1 /* notificationCancelledCount */);
+
+                // Add the assistant role to the list of exempted roles and verify broadcast
+                // response stats for the test app are not recorded.
+                updateFlagWithDelay(deviceConfigStateHelper,
+                        KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES,
+                        String.join("|", RoleManager.ROLE_BROWSER, RoleManager.ROLE_EMERGENCY,
+                                RoleManager.ROLE_ASSISTANT));
+
+                sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+                testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+                        buildMediaNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+                                TEST_NOTIFICATION_TEXT_1));
+
+                assertResponseStats(TEST_ASSIST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+                        2 /* broadcastCount */,
+                        1 /* notificationPostedCount */,
+                        0 /* notificationUpdatedCount */,
+                        1 /* notificationCancelledCount */);
+            } finally {
+                removeAssistRoleHolder(TEST_ASSIST_APP_PKG, Process.myUserHandle().getIdentifier());
+                connection.unbind();
+            }
+        }
+    }
+
+    @AppModeFull(reason = "No broadcast message response stats in instant apps")
+    @Test
+    public void testBroadcastResponseStats_exemptedPermission() throws Exception {
+        try (DeviceConfigStateHelper deviceConfigStateHelper =
+                     new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
+
+            assertResponseStats(TEST_EXACT_ALARM_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+                    0 /* broadcastCount */,
+                    0 /* notificationPostedCount */,
+                    0 /* notificationUpdatedCount */,
+                    0 /* notificationCancelledCount */);
+            assertResponseStats(TEST_EXACT_ALARM_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+                    0 /* broadcastCount */,
+                    0 /* notificationPostedCount */,
+                    0 /* notificationUpdatedCount */,
+                    0 /* notificationCancelledCount */);
+
+            final TestServiceConnection connection = bindToTestServiceAndGetConnection(
+                    TEST_EXACT_ALARM_APP_PKG);
+            try {
+                ITestReceiver testReceiver = connection.getITestReceiver();
+                testReceiver.cancelAll();
+
+                // Send a broadcast with a request to record response and verify broadcast-sent
+                // count gets incremented.
+                final Intent intent = new Intent().setComponent(new ComponentName(
+                        TEST_EXACT_ALARM_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+                final BroadcastOptions options = BroadcastOptions.makeBasic();
+                options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+                sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+                testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+                        TEST_NOTIFICATION_CHANNEL_NAME,
+                        TEST_NOTIFICATION_CHANNEL_DESC);
+                testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+                        buildMediaNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+                                TEST_NOTIFICATION_TEXT_1));
+
+                assertResponseStats(TEST_EXACT_ALARM_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+                        1 /* broadcastCount */,
+                        1 /* notificationPostedCount */,
+                        0 /* notificationUpdatedCount */,
+                        0 /* notificationCancelledCount */);
+
+                // Add USE_EXACT_ALARM to the list of exempted permissions and verify
+                // broadcast response stats for the test app are not recorded.
+                updateFlagWithDelay(deviceConfigStateHelper,
+                        KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS,
+                        USE_EXACT_ALARM);
+
+                sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+                testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+                        buildMediaNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+                                TEST_NOTIFICATION_TEXT_2));
+
+                assertResponseStats(TEST_EXACT_ALARM_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+                        1 /* broadcastCount */,
+                        1 /* notificationPostedCount */,
+                        0 /* notificationUpdatedCount */,
+                        0 /* notificationCancelledCount */);
+
+                // Remove USE_EXACT_ALARM from the list of exempted permissions and verify
+                // broadcast response stats for the test app are recorded.
+                updateFlagWithDelay(deviceConfigStateHelper,
+                        KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS,
+                        String.join("|", PACKAGE_USAGE_STATS, INTERNET));
+
+                sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+                testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
+
+                assertResponseStats(TEST_EXACT_ALARM_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+                        2 /* broadcastCount */,
+                        1 /* notificationPostedCount */,
+                        0 /* notificationUpdatedCount */,
+                        1 /* notificationCancelledCount */);
+
+                // Add USE_EXACT_ALARM to the list of exempted permissions again and verify
+                // broadcast response stats for the test app are not recorded.
+                updateFlagWithDelay(deviceConfigStateHelper,
+                        KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS,
+                        String.join("|", PACKAGE_USAGE_STATS, INTERNET, USE_EXACT_ALARM));
+
+                sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+                testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+                        buildMediaNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+                                TEST_NOTIFICATION_TEXT_1));
+
+                assertResponseStats(TEST_EXACT_ALARM_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+                        2 /* broadcastCount */,
+                        1 /* notificationPostedCount */,
+                        0 /* notificationUpdatedCount */,
+                        1 /* notificationCancelledCount */);
+            } finally {
+                connection.unbind();
+            }
+        }
+    }
+
     private void updateFlagWithDelay(DeviceConfigStateHelper deviceConfigStateHelper,
             String key, String value) {
         deviceConfigStateHelper.set(key, value);
@@ -1977,6 +2187,18 @@
         }
     }
 
+    protected void addAssistRoleHolder(String pkgName, int userId) throws Exception {
+        final String cmd = String.format("cmd role add-role-holder "
+                + "--user %d android.app.role.ASSISTANT %s", userId, pkgName);
+        SystemUtil.runShellCommand(cmd);
+    }
+
+    protected void removeAssistRoleHolder(String pkgName, int userId) throws Exception {
+        final String cmd = String.format("cmd role remove-role-holder "
+                + "--user %d android.app.role.ASSISTANT %s", userId, pkgName);
+        SystemUtil.runShellCommand(cmd);
+    }
+
     private void wakeUpAndDismissKeyguard() throws Exception {
         mUiDevice.wakeUp();
         SystemUtil.runShellCommand("wm dismiss-keyguard");
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
index e318e42..3821929 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
@@ -252,15 +252,6 @@
                                 Process.myUserHandle().getIdentifier()),
                 REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL,
                 REVOKE_RUNTIME_PERMISSIONS);
-
-        // Clear broadcast response stats
-        setAppOpsMode("allow");
-        try {
-            mUsageStatsManager.clearBroadcastEvents();
-            mUsageStatsManager.clearBroadcastResponseStats(null /* packageName */, 0 /* id */);
-        } finally {
-            resetAppOpsMode();
-        }
     }
 
 
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 671078d..7f35367 100644
--- a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
+++ b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
@@ -196,6 +196,15 @@
             return;
         }
 
+        if (structure != null && structure.isHomeActivity() && !state.isFocused()) {
+            // If the system has multiple display areas, the launcher may be visible and resumed
+            // when the tests are in progress, so the tests might fail if they receives unexpected
+            // state from the launcher. Ignore the states from unfocused launcher to avoid this
+            // failure.
+            Log.i(TAG, "Ignoring the state from unfocused launcher");
+            return;
+        }
+
         // send to test to verify that this is accurate.
         mAssistData.putBoolean(Utils.ASSIST_IS_ACTIVITY_ID_NULL, state.getActivityId() == null);
         mAssistData.putParcelable(Utils.ASSIST_STRUCTURE_KEY, structure);
diff --git a/tests/tests/bluetooth/TEST_MAPPING b/tests/tests/bluetooth/TEST_MAPPING
index 0df5768..cfb28d3 100644
--- a/tests/tests/bluetooth/TEST_MAPPING
+++ b/tests/tests/bluetooth/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit": [
+  "presubmit-large": [
     {
       "name": "CtsBluetoothTestCases"
     }
diff --git a/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java b/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
index 14891e0..32d37fc 100644
--- a/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
+++ b/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
@@ -16,17 +16,19 @@
 
 package android.bluetooth.cts;
 
-import android.app.UiAutomation;
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
+
 import android.bluetooth.BluetoothAdapter;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.util.Log;
+import android.util.SparseIntArray;
 
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
 
-import java.util.HashSet;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Condition;
@@ -37,6 +39,7 @@
  */
 public class BTAdapterUtils {
     private static final String TAG = "BTAdapterUtils";
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
 
     // ADAPTER_ENABLE_TIMEOUT_MS = AdapterState.BLE_START_TIMEOUT_DELAY +
     //                              AdapterState.BREDR_START_TIMEOUT_DELAY
@@ -45,129 +48,297 @@
     //                                  AdapterState.BREDR_STOP_TIMEOUT_DELAY
     private static final int ADAPTER_DISABLE_TIMEOUT_MS = 5000;
 
-    private static BroadcastReceiver mAdapterIntentReceiver;
+    public static final int STATE_BLE_TURNING_ON = 14;
+    public static final int STATE_BLE_ON = 15;
+    public static final int STATE_BLE_TURNING_OFF = 16;
 
-    private static Condition mConditionAdapterIsEnabled;
-    private static ReentrantLock mAdapterStateEnablinglock;
+    private static final SparseIntArray sStateTimeouts = new SparseIntArray();
+    static {
+        sStateTimeouts.put(BluetoothAdapter.STATE_OFF, ADAPTER_DISABLE_TIMEOUT_MS);
+        sStateTimeouts.put(BluetoothAdapter.STATE_TURNING_ON, ADAPTER_ENABLE_TIMEOUT_MS);
+        sStateTimeouts.put(BluetoothAdapter.STATE_ON, ADAPTER_ENABLE_TIMEOUT_MS);
+        sStateTimeouts.put(BluetoothAdapter.STATE_TURNING_OFF, ADAPTER_DISABLE_TIMEOUT_MS);
+        sStateTimeouts.put(STATE_BLE_TURNING_ON, ADAPTER_ENABLE_TIMEOUT_MS);
+        sStateTimeouts.put(STATE_BLE_ON, ADAPTER_ENABLE_TIMEOUT_MS);
+        sStateTimeouts.put(STATE_BLE_TURNING_OFF, ADAPTER_DISABLE_TIMEOUT_MS);
+    }
 
-    private static Condition mConditionAdapterIsDisabled;
-    private static ReentrantLock mAdapterStateDisablinglock;
-    private static boolean mAdapterVarsInitialized;
+    private static BluetoothAdapterReceiver sAdapterReceiver;
 
-    private static class AdapterIntentReceiver extends BroadcastReceiver {
+    private static boolean sAdapterVarsInitialized;
+    private static ReentrantLock sBluetoothAdapterLock;
+    private static Condition sConditionAdapterStateReached;
+    private static int sDesiredState;
+    private static int sAdapterState;
+
+    /**
+     * Handles BluetoothAdapter state changes and signals when we have reached a desired state
+     */
+    private static class BluetoothAdapterReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
-                int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, -1);
+            String action = intent.getAction();
+            if (BluetoothAdapter.ACTION_BLE_STATE_CHANGED.equals(action)) {
                 int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
-                Log.d(TAG, "Previous state: " + previousState + " New state: " + newState);
+                if (DBG) {
+                    Log.d(TAG, "Bluetooth adapter state changed: " + newState);
+                }
 
-                if (newState == BluetoothAdapter.STATE_ON) {
-                    mAdapterStateEnablinglock.lock();
-                    try {
-                        Log.d(TAG, "Signaling to mConditionAdapterIsEnabled");
-                        mConditionAdapterIsEnabled.signal();
-                    } finally {
-                        mAdapterStateEnablinglock.unlock();
+                // Signal if the state is set to the one we are waiting on
+                sBluetoothAdapterLock.lock();
+                sAdapterState = newState;
+                try {
+                    if (sDesiredState == newState) {
+                        if (DBG) {
+                            Log.d(TAG, "Adapter has reached desired state: " + sDesiredState);
+                        }
+                        sConditionAdapterStateReached.signal();
                     }
-                } else if (newState == BluetoothAdapter.STATE_OFF) {
-                    mAdapterStateDisablinglock.lock();
-                    try {
-                        Log.d(TAG, "Signaling to mConditionAdapterIsDisabled");
-                        mConditionAdapterIsDisabled.signal();
-                    } finally {
-                        mAdapterStateDisablinglock.unlock();
-                    }
+                } finally {
+                    sBluetoothAdapterLock.unlock();
                 }
             }
         }
     }
 
-    /** Enables the Bluetooth Adapter. Return true if it is already enabled or is enabled. */
-    public static boolean enableAdapter(BluetoothAdapter bluetoothAdapter, Context context) {
-        if (!mAdapterVarsInitialized) {
-            initAdapterStateVariables(context);
-        }
-
-        if (bluetoothAdapter.isEnabled()) return true;
-
-        Log.d(TAG, "Enabling bluetooth adapter");
-        UiAutomation auto = InstrumentationRegistry.getInstrumentation().getUiAutomation();
-        Set<String> permissions = new HashSet(auto.getAdoptedShellPermissions());
-        Set<String> savedPermissions = Set.copyOf(permissions);
-        permissions.add(android.Manifest.permission.NETWORK_SETTINGS);
-        auto.adoptShellPermissionIdentity(permissions.toArray(new String[permissions.size()]));
-        bluetoothAdapter.enable();
-        mAdapterStateEnablinglock.lock();
-        try {
-            // Wait for the Adapter to be enabled
-            while (!bluetoothAdapter.isEnabled()) {
-                if (!mConditionAdapterIsEnabled.await(
-                        ADAPTER_ENABLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-                    // Timeout
-                    Log.e(TAG, "Timeout while waiting for the Bluetooth Adapter enable");
-                    break;
-                } // else spurious wakeups
-            }
-        } catch(InterruptedException e) {
-            Log.e(TAG, "enableAdapter: interrrupted");
-        } finally {
-            auto.adoptShellPermissionIdentity(savedPermissions.toArray(
-                    new String[savedPermissions.size()]));
-            mAdapterStateEnablinglock.unlock();
-        }
-
-        return bluetoothAdapter.isEnabled();
-    }
-
-    /** Disable the Bluetooth Adapter. Return true if it is already disabled or is disabled. */
-    public static boolean disableAdapter(BluetoothAdapter bluetoothAdapter, Context context) {
-        if (!mAdapterVarsInitialized) {
-            initAdapterStateVariables(context);
-        }
-
-        if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) return true;
-
-        Log.d(TAG, "Disabling bluetooth adapter");
-        UiAutomation auto = InstrumentationRegistry.getInstrumentation().getUiAutomation();
-        Set<String> permissions = new HashSet(auto.getAdoptedShellPermissions());
-        Set<String> savedPermissions = Set.copyOf(permissions);
-        permissions.add(android.Manifest.permission.NETWORK_SETTINGS);
-        auto.adoptShellPermissionIdentity(permissions.toArray(new String[permissions.size()]));
-        bluetoothAdapter.disable();
-        mAdapterStateDisablinglock.lock();
-        try {
-            // Wait for the Adapter to be disabled
-            while (bluetoothAdapter.getState() != BluetoothAdapter.STATE_OFF) {
-                if (!mConditionAdapterIsDisabled.await(
-                        ADAPTER_DISABLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-                    // Timeout
-                    Log.e(TAG, "Timeout while waiting for the Bluetooth Adapter disable");
-                    break;
-                } // else spurious wakeups
-            }
-        } catch(InterruptedException e) {
-            Log.e(TAG, "enableAdapter: interrrupted");
-        } finally {
-            auto.adoptShellPermissionIdentity(savedPermissions.toArray(
-                    new String[savedPermissions.size()]));
-            mAdapterStateDisablinglock.unlock();
-        }
-        return bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF;
-    }
-
-    // Initialize variables required for TestUtils#enableAdapter and TestUtils#disableAdapter
+    /**
+     * Initialize all static state variables
+     */
     private static void initAdapterStateVariables(Context context) {
-        Log.d(TAG, "Initializing adapter state variables");
-        mAdapterIntentReceiver = new AdapterIntentReceiver();
-        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
-        context.registerReceiver(mAdapterIntentReceiver, filter);
+        if (DBG) {
+            Log.d(TAG, "Initializing adapter state variables");
+        }
+        sAdapterReceiver = new BluetoothAdapterReceiver();
+        sBluetoothAdapterLock = new ReentrantLock();
+        sConditionAdapterStateReached = sBluetoothAdapterLock.newCondition();
+        sDesiredState = -1;
+        sAdapterState = -1;
+        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
+        context.registerReceiver(sAdapterReceiver, filter);
+        sAdapterVarsInitialized = true;
+    }
 
-        mAdapterStateEnablinglock = new ReentrantLock();
-        mConditionAdapterIsEnabled = mAdapterStateEnablinglock.newCondition();
-        mAdapterStateDisablinglock = new ReentrantLock();
-        mConditionAdapterIsDisabled = mAdapterStateDisablinglock.newCondition();
+    /**
+     * Wait for the bluetooth adapter to be in a given state
+     *
+     * Assumes all state variables are initialized. Assumes it's being run with
+     * sBluetoothAdapterLock in the locked state.
+     */
+    private static boolean waitForAdapterStateLocked(int desiredState, BluetoothAdapter adapter)
+            throws InterruptedException {
+        int timeout = sStateTimeouts.get(desiredState, ADAPTER_ENABLE_TIMEOUT_MS);
 
-        mAdapterVarsInitialized = true;
+        if (DBG) {
+            Log.d(TAG, "Waiting for adapter state " + desiredState);
+        }
+        sDesiredState = desiredState;
+
+        // Wait until we have reached the desired state
+        while (desiredState != sAdapterState) {
+            if (!sConditionAdapterStateReached.await(timeout, TimeUnit.MILLISECONDS)) {
+                // Handle situation where state change occurs, but we don't receive the broadcast
+                if (desiredState >= BluetoothAdapter.STATE_OFF
+                        && desiredState <= BluetoothAdapter.STATE_TURNING_OFF) {
+                    return adapter.getState() == desiredState;
+                } else if (desiredState == STATE_BLE_ON) {
+                    Log.d(TAG, "adapter isLeEnabled: " + adapter.isLeEnabled());
+                    return adapter.isLeEnabled();
+                }
+                Log.e(TAG, "Timeout while waiting for Bluetooth adapter state " + desiredState
+                        + " while current state is " + sAdapterState);
+                break;
+            }
+        }
+
+        if (DBG) {
+            Log.d(TAG, "Final state while waiting: " + sAdapterState);
+        }
+
+        return sAdapterState == desiredState;
+    }
+
+    /**
+     * Utility method to wait on any specific adapter state
+     */
+    public static boolean waitForAdapterState(int desiredState, BluetoothAdapter adapter) {
+        sBluetoothAdapterLock.lock();
+        try {
+            return waitForAdapterStateLocked(desiredState, adapter);
+        } catch (InterruptedException e) {
+            Log.w(TAG, "waitForAdapterState(): interrupted", e);
+        } finally {
+            sBluetoothAdapterLock.unlock();
+        }
+        return false;
+    }
+
+    /**
+     * Enables Bluetooth to a Low Energy only mode
+     */
+    public static boolean enableBLE(BluetoothAdapter bluetoothAdapter, Context context) {
+        if (!sAdapterVarsInitialized) {
+            initAdapterStateVariables(context);
+        }
+
+        if (bluetoothAdapter.isLeEnabled()) {
+            return true;
+        }
+
+        sBluetoothAdapterLock.lock();
+        try {
+            if (DBG) {
+                Log.d(TAG, "Enabling Bluetooth low energy only mode");
+            }
+            if (!bluetoothAdapter.enableBLE()) {
+                Log.e(TAG, "Unable to enable Bluetooth low energy only mode");
+                return false;
+            }
+            return waitForAdapterStateLocked(STATE_BLE_ON, bluetoothAdapter);
+        } catch (InterruptedException e) {
+            Log.w(TAG, "enableBLE(): interrupted", e);
+        } finally {
+            sBluetoothAdapterLock.unlock();
+        }
+        return false;
+    }
+
+    /**
+     * Disable Bluetooth Low Energy mode
+     */
+    public static boolean disableBLE(BluetoothAdapter bluetoothAdapter, Context context) {
+        if (!sAdapterVarsInitialized) {
+            initAdapterStateVariables(context);
+        }
+
+        if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) {
+            return true;
+        }
+
+        sBluetoothAdapterLock.lock();
+        try {
+            if (DBG) {
+                Log.d(TAG, "Disabling Bluetooth low energy");
+            }
+            bluetoothAdapter.disableBLE();
+            return waitForAdapterStateLocked(BluetoothAdapter.STATE_OFF, bluetoothAdapter);
+        } catch (InterruptedException e) {
+            Log.w(TAG, "disableBLE(): interrupted", e);
+        } finally {
+            sBluetoothAdapterLock.unlock();
+        }
+        return false;
+    }
+
+    /**
+     * Enables the Bluetooth Adapter. Return true if it is already enabled or is enabled.
+     */
+    public static boolean enableAdapter(BluetoothAdapter bluetoothAdapter, Context context) {
+        if (!sAdapterVarsInitialized) {
+            initAdapterStateVariables(context);
+        }
+
+        if (bluetoothAdapter.isEnabled()) {
+            return true;
+        }
+
+        Set<String> permissionsAdopted = getPermissionsAdoptedAsShellUid();
+        sBluetoothAdapterLock.lock();
+        try {
+            if (DBG) {
+                Log.d(TAG, "Enabling Bluetooth adapter");
+            }
+            adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
+            bluetoothAdapter.enable();
+            return waitForAdapterStateLocked(BluetoothAdapter.STATE_ON, bluetoothAdapter);
+        } catch (InterruptedException e) {
+            Log.w(TAG, "enableAdapter(): interrupted", e);
+        } finally {
+            adoptPermissionAsShellUid(permissionsAdopted.toArray(new String[0]));
+            sBluetoothAdapterLock.unlock();
+        }
+        return false;
+    }
+
+    /**
+     * Disable the Bluetooth Adapter. Return true if it is already disabled or is disabled.
+     */
+    public static boolean disableAdapter(BluetoothAdapter bluetoothAdapter, Context context) {
+        if (!sAdapterVarsInitialized) {
+            initAdapterStateVariables(context);
+        }
+
+        if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) {
+            return true;
+        }
+
+        if (DBG) {
+            Log.d(TAG, "Disabling Bluetooth adapter");
+        }
+
+        Set<String> permissionsAdopted = getPermissionsAdoptedAsShellUid();
+        sBluetoothAdapterLock.lock();
+        try {
+            adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
+            bluetoothAdapter.disable();
+            return waitForAdapterStateLocked(BluetoothAdapter.STATE_OFF, bluetoothAdapter);
+        } catch (InterruptedException e) {
+            Log.w(TAG, "disableAdapter(): interrupted", e);
+        } finally {
+            adoptPermissionAsShellUid(permissionsAdopted.toArray(new String[0]));
+            sBluetoothAdapterLock.unlock();
+        }
+        return false;
+    }
+
+    /**
+     * Disable the Bluetooth Adapter with then option to persist the off state or not.
+     *
+     * Returns true if the adapter is already disabled or was disabled.
+     */
+    public static boolean disableAdapter(BluetoothAdapter bluetoothAdapter, boolean persist,
+            Context context) {
+        if (!sAdapterVarsInitialized) {
+            initAdapterStateVariables(context);
+        }
+
+        if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) {
+            return true;
+        }
+
+        Set<String> permissionsAdopted = getPermissionsAdoptedAsShellUid();
+        sBluetoothAdapterLock.lock();
+        try {
+            if (DBG) {
+                Log.d(TAG, "Disabling Bluetooth adapter, persist=" + persist);
+            }
+            adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
+            bluetoothAdapter.disable(persist);
+            return waitForAdapterStateLocked(BluetoothAdapter.STATE_OFF, bluetoothAdapter);
+        } catch (InterruptedException e) {
+            Log.w(TAG, "disableAdapter(persist=" + persist + "): interrupted", e);
+        } finally {
+            adoptPermissionAsShellUid(permissionsAdopted.toArray(new String[0]));
+            sBluetoothAdapterLock.unlock();
+        }
+        return false;
+    }
+
+    /**
+     * Adopt shell UID's permission via {@link android.app.UiAutomation}
+     * @param permission permission to adopt
+     */
+    private static void adoptPermissionAsShellUid(String... permission) {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity(permission);
+    }
+
+    /**
+     * Gets all the permissions adopted as the shell UID
+     *
+     * @return a {@link java.util.Set} of the adopted shell permissions
+     */
+    private static Set<String> getPermissionsAdoptedAsShellUid() {
+        return InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .getAdoptedShellPermissions();
     }
 }
\ No newline at end of file
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/AdvertiseSettingsTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/AdvertiseSettingsTest.java
index 19b7c29..4f472c7 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/AdvertiseSettingsTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/AdvertiseSettingsTest.java
@@ -17,6 +17,7 @@
 package android.bluetooth.cts;
 
 import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.AdvertisingSetParameters;
 import android.os.Parcel;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -50,6 +51,7 @@
                 .setConnectable(false)
                 .setTimeout(timeoutMillis)
                 .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
+                .setOwnAddressType(AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT)
                 .build();
         settings.writeToParcel(parcel, 0);
         parcel.setDataPosition(0);
@@ -59,6 +61,7 @@
                 settingsFromParcel.getTxPowerLevel());
         assertEquals(timeoutMillis, settingsFromParcel.getTimeout());
         assertFalse(settings.isConnectable());
+        assertEquals(AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT, settings.getOwnAddressType());
     }
 
     @SmallTest
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
index ca44d16..515f0ef 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
@@ -143,6 +143,7 @@
     public void test_getCodecStatus() {
         if (!(mHasBluetooth && mIsA2dpSupported)) return;
 
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
         assertTrue(waitForProfileConnect());
         assertNotNull(mBluetoothA2dp);
 
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java
index 5575efe..44f34f6 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java
@@ -17,6 +17,7 @@
 package android.bluetooth.cts;
 
 import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
 
 import static org.junit.Assert.assertThrows;
 
@@ -43,6 +44,7 @@
 import com.android.compatibility.common.util.ApiLevelUtil;
 
 import java.io.IOException;
+import java.time.Duration;
 import java.util.List;
 import java.util.Set;
 import java.util.UUID;
@@ -363,12 +365,21 @@
             // Skip the test if bluetooth is not present.
             return;
         }
+
+        Duration minute = Duration.ofMinutes(1);
+
         assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
         assertEquals(null, mAdapter.getDiscoverableTimeout());
-        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        assertEquals(BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
+                mAdapter.setDiscoverableTimeout(minute));
 
-        mUiAutomation.dropShellPermissionIdentity();
-        assertEquals(120, mAdapter.getDiscoverableTimeout().toSeconds());
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
+        assertThrows(IllegalArgumentException.class, () -> mAdapter.setDiscoverableTimeout(
+                Duration.ofDays(25000)));
+        assertEquals(BluetoothStatusCodes.SUCCESS,
+                mAdapter.setDiscoverableTimeout(minute));
+        assertEquals(minute, mAdapter.getDiscoverableTimeout());
     }
 
     public void test_getConnectionState() {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java
index 15c15eb..a3ea455 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java
@@ -17,6 +17,7 @@
 package android.bluetooth.cts;
 
 import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
 import static android.bluetooth.BluetoothDevice.ACCESS_ALLOWED;
 import static android.bluetooth.BluetoothDevice.ACCESS_REJECTED;
 import static android.bluetooth.BluetoothDevice.ACCESS_UNKNOWN;
@@ -170,38 +171,6 @@
         assertEquals(BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF, mFakeDevice.getBatteryLevel());
     }
 
-    public void test_getMessageAccessPermission() {
-        if (!mHasBluetooth || !mHasCompanionDevice) {
-            // Skip the test if bluetooth or companion device are not present.
-            return;
-        }
-
-        assertEquals(BluetoothDevice.ACCESS_UNKNOWN, mFakeDevice.getMessageAccessPermission());
-
-        mUiAutomation.dropShellPermissionIdentity();
-        assertThrows(SecurityException.class, () -> mFakeDevice.getMessageAccessPermission());
-        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
-
-        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        assertEquals(BluetoothDevice.ACCESS_UNKNOWN, mFakeDevice.getMessageAccessPermission());
-    }
-
-    public void test_getPhonebookAccessPermission() {
-        if (!mHasBluetooth || !mHasCompanionDevice) {
-            // Skip the test if bluetooth or companion device are not present.
-            return;
-        }
-
-        assertEquals(BluetoothDevice.ACCESS_UNKNOWN, mFakeDevice.getPhonebookAccessPermission());
-
-        mUiAutomation.dropShellPermissionIdentity();
-        assertThrows(SecurityException.class, () -> mFakeDevice.getPhonebookAccessPermission());
-        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
-
-        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        assertEquals(BluetoothDevice.ACCESS_UNKNOWN, mFakeDevice.getPhonebookAccessPermission());
-    }
-
     public void test_isBondingInitiatedLocally() {
         if (!mHasBluetooth || !mHasCompanionDevice) {
             // Skip the test if bluetooth or companion device are not present.
@@ -303,31 +272,13 @@
         mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
     }
 
-    public void test_getSimAccessPermission() {
-        if (!mHasBluetooth || !mHasCompanionDevice) {
-            // Skip the test if bluetooth or companion device are not present.
-            return;
-        }
-
-        //Access is unknown as device is not bonded
-        assertEquals(ACCESS_UNKNOWN, mFakeDevice.getSimAccessPermission());
-
-        mUiAutomation.dropShellPermissionIdentity();
-        assertThrows(SecurityException.class, () -> mFakeDevice.getSimAccessPermission());
-        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
-
-        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        assertEquals(ACCESS_UNKNOWN, mFakeDevice.getSimAccessPermission());
-    }
-
     public void test_getUuids() {
         if (!mHasBluetooth || !mHasCompanionDevice) {
             // Skip the test if bluetooth or companion device are not present.
             return;
         }
 
-        assertNotNull(mFakeDevice.getUuids());
-        assertEquals(0, mFakeDevice.getUuids().length);
+        assertNull(mFakeDevice.getUuids());
         mUiAutomation.dropShellPermissionIdentity();
         assertThrows(SecurityException.class, () -> mFakeDevice.getUuids());
         mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
@@ -423,7 +374,7 @@
         assertFalse(mFakeDevice.fetchUuidsWithSdp(TRANSPORT_AUTO));
     }
 
-    public void test_setMessageAccessPermission() {
+    public void test_messageAccessPermission() {
         if (!mHasBluetooth || !mHasCompanionDevice) {
             // Skip the test if bluetooth or companion device are not present.
             return;
@@ -436,9 +387,19 @@
                 .setMessageAccessPermission(ACCESS_UNKNOWN));
         assertThrows(SecurityException.class, () -> mFakeDevice
                 .setMessageAccessPermission(ACCESS_REJECTED));
+
+        TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
+
+        // Should be able to set permissions after adopting the BLUETOOTH_PRIVILEGED permission
+        assertTrue(mFakeDevice.setMessageAccessPermission(ACCESS_UNKNOWN));
+        assertEquals(ACCESS_UNKNOWN, mFakeDevice.getMessageAccessPermission());
+        assertTrue(mFakeDevice.setMessageAccessPermission(ACCESS_ALLOWED));
+        assertEquals(ACCESS_ALLOWED, mFakeDevice.getMessageAccessPermission());
+        assertTrue(mFakeDevice.setMessageAccessPermission(ACCESS_REJECTED));
+        assertEquals(ACCESS_REJECTED, mFakeDevice.getMessageAccessPermission());
     }
 
-    public void test_setPhonebookAccessPermission() {
+    public void test_phonebookAccessPermission() {
         if (!mHasBluetooth || !mHasCompanionDevice) {
             // Skip the test if bluetooth or companion device are not present.
             return;
@@ -451,9 +412,19 @@
                 .setPhonebookAccessPermission(ACCESS_UNKNOWN));
         assertThrows(SecurityException.class, () -> mFakeDevice
                 .setPhonebookAccessPermission(ACCESS_REJECTED));
+
+        TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
+
+        // Should be able to set permissions after adopting the BLUETOOTH_PRIVILEGED permission
+        assertTrue(mFakeDevice.setPhonebookAccessPermission(ACCESS_UNKNOWN));
+        assertEquals(ACCESS_UNKNOWN, mFakeDevice.getPhonebookAccessPermission());
+        assertTrue(mFakeDevice.setPhonebookAccessPermission(ACCESS_ALLOWED));
+        assertEquals(ACCESS_ALLOWED, mFakeDevice.getPhonebookAccessPermission());
+        assertTrue(mFakeDevice.setPhonebookAccessPermission(ACCESS_REJECTED));
+        assertEquals(ACCESS_REJECTED, mFakeDevice.getPhonebookAccessPermission());
     }
 
-    public void test_setSimAccessPermission() {
+    public void test_simAccessPermission() {
         if (!mHasBluetooth || !mHasCompanionDevice) {
             // Skip the test if bluetooth or companion device are not present.
             return;
@@ -466,6 +437,16 @@
                 .setSimAccessPermission(ACCESS_UNKNOWN));
         assertThrows(SecurityException.class, () -> mFakeDevice
                 .setSimAccessPermission(ACCESS_REJECTED));
+
+        TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
+
+        // Should be able to set permissions after adopting the BLUETOOTH_PRIVILEGED permission
+        assertTrue(mFakeDevice.setSimAccessPermission(ACCESS_UNKNOWN));
+        assertEquals(ACCESS_UNKNOWN, mFakeDevice.getSimAccessPermission());
+        assertTrue(mFakeDevice.setSimAccessPermission(ACCESS_ALLOWED));
+        assertEquals(ACCESS_ALLOWED, mFakeDevice.getSimAccessPermission());
+        assertTrue(mFakeDevice.setSimAccessPermission(ACCESS_REJECTED));
+        assertEquals(ACCESS_REJECTED, mFakeDevice.getSimAccessPermission());
     }
 
     private byte[] convertPinToBytes(String pin) {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java
index ccf7fdb..ddb6bca 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java
@@ -49,6 +49,8 @@
     // German language code in ISO 639-3
     // In byte it is ASCII, 0x64, 0x65, 0x75
     private static final String TEST_LANGUAGE = "deu";
+    // Same as TEST_LANGUAGE, but with whitespace before and after
+    private static final String TEST_LANGUAGE_WITH_WHITESPACE = "   deu     ";
     // See Page 6 of Generic Audio assigned number specification
     private static final byte[] TEST_METADATA_BYTES = {
             // length is 0x05, type is 0x03, data is "Test" in UTF-8 "54 65 73 74" hex
@@ -118,6 +120,15 @@
         assertEquals(TEST_PROGRAM_INFO, contentMetadata.getProgramInfo());
         assertEquals(TEST_LANGUAGE, contentMetadata.getLanguage());
         assertArrayEquals(TEST_METADATA_BYTES, contentMetadata.getRawMetadata());
+
+        // Verifies that the language string is stripped when generating the raw metadata
+        BluetoothLeAudioContentMetadata contentMetadataStrippedLanguage =
+                new BluetoothLeAudioContentMetadata.Builder()
+                        .setProgramInfo(TEST_PROGRAM_INFO)
+                        .setLanguage(TEST_LANGUAGE_WITH_WHITESPACE.toLowerCase().strip())
+                        .build();
+        assertArrayEquals(contentMetadata.getRawMetadata(),
+                contentMetadataStrippedLanguage.getRawMetadata());
     }
 
     @Test
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPanTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPanTest.java
new file mode 100644
index 0000000..733d9f3
--- /dev/null
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPanTest.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.cts;
+
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
+import static android.Manifest.permission.TETHER_PRIVILEGED;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothProfile;
+import android.content.pm.PackageManager;
+import android.sysprop.BluetoothProperties;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class BluetoothPanTest extends AndroidTestCase {
+    private static final String TAG = BluetoothPanTest.class.getSimpleName();
+
+    private static final int PROXY_CONNECTION_TIMEOUT_MS = 500;  // ms timeout for Proxy Connect
+
+    private boolean mHasBluetooth;
+    private BluetoothAdapter mAdapter;
+
+    private BluetoothPan mBluetoothPan;
+    private boolean mIsPanSupported;
+    private boolean mIsProfileReady;
+    private Condition mConditionProfileIsConnected;
+    private ReentrantLock mProfileConnectedlock;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_BLUETOOTH);
+        if (!mHasBluetooth) return;
+
+        mIsPanSupported = BluetoothProperties.isProfilePanPanuEnabled().orElse(false)
+                || BluetoothProperties.isProfilePanNapEnabled().orElse(false);
+        if (!mIsPanSupported) return;
+
+        TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT);
+
+        BluetoothManager manager = getContext().getSystemService(BluetoothManager.class);
+        mAdapter = manager.getAdapter();
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        mProfileConnectedlock = new ReentrantLock();
+        mConditionProfileIsConnected = mProfileConnectedlock.newCondition();
+        mIsProfileReady = false;
+        mBluetoothPan = null;
+
+        mAdapter.getProfileProxy(getContext(), new BluetoothPanServiceListener(),
+                BluetoothProfile.PAN);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (!(mHasBluetooth && mIsPanSupported)) {
+            return;
+        }
+        if (mAdapter != null && mBluetoothPan != null) {
+            mAdapter.closeProfileProxy(BluetoothProfile.PAN, mBluetoothPan);
+            mBluetoothPan = null;
+            mIsProfileReady = false;
+        }
+        if (mAdapter != null) {
+            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        }
+        mAdapter = null;
+        TestUtils.dropPermissionAsShellUid();
+    }
+
+    public void test_getConnectedDevices() {
+        if (!(mHasBluetooth && mIsPanSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothPan);
+
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+
+        // Verify returns empty list if bluetooth is not enabled
+        List<BluetoothDevice> connectedDevices = mBluetoothPan.getConnectedDevices();
+        assertTrue(connectedDevices.isEmpty());
+    }
+
+    public void test_getDevicesMatchingConnectionStates() {
+        if (!(mHasBluetooth && mIsPanSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothPan);
+
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+
+        // Verify returns empty list if bluetooth is not enabled
+        List<BluetoothDevice> connectedDevices =
+                mBluetoothPan.getDevicesMatchingConnectionStates(null);
+        assertTrue(connectedDevices.isEmpty());
+    }
+
+    public void test_getConnectionState() {
+        if (!(mHasBluetooth && mIsPanSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothPan);
+
+        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+
+        // Verify returns false when invalid input is given
+        assertEquals(BluetoothProfile.STATE_DISCONNECTED,
+                mBluetoothPan.getConnectionState(null));
+
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+
+        // Verify returns false if bluetooth is not enabled
+        assertEquals(BluetoothProfile.STATE_DISCONNECTED,
+                mBluetoothPan.getConnectionState(testDevice));
+    }
+
+    public void test_setConnectionPolicy() {
+        if (!(mHasBluetooth && mIsPanSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothPan);
+
+        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+
+        // Verify returns false when invalid input is given
+        assertFalse(mBluetoothPan.setConnectionPolicy(
+                testDevice, BluetoothProfile.CONNECTION_POLICY_UNKNOWN));
+        assertFalse(mBluetoothPan.setConnectionPolicy(
+                null, BluetoothProfile.CONNECTION_POLICY_ALLOWED));
+
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+
+        // Verify returns false if bluetooth is not enabled
+        assertFalse(mBluetoothPan.setConnectionPolicy(
+                testDevice, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN));
+    }
+
+    public void test_setAndCheckBluetoothTethering() {
+        if (!(mHasBluetooth && mIsPanSupported)) return;
+
+        TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED,
+                TETHER_PRIVILEGED);
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothPan);
+
+        assertFalse(mBluetoothPan.isTetheringOn());
+        mBluetoothPan.setBluetoothTethering(true);
+        assertTrue(mBluetoothPan.isTetheringOn());
+        mBluetoothPan.setBluetoothTethering(false);
+        assertFalse(mBluetoothPan.isTetheringOn());
+    }
+
+    private boolean waitForProfileConnect() {
+        mProfileConnectedlock.lock();
+        try {
+            // Wait for the Adapter to be disabled
+            while (!mIsProfileReady) {
+                if (!mConditionProfileIsConnected.await(
+                        PROXY_CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                    // Timeout
+                    Log.e(TAG, "Timeout while waiting for Profile Connect");
+                    break;
+                } // else spurious wakeups
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "waitForProfileConnect: interrrupted");
+        } finally {
+            mProfileConnectedlock.unlock();
+        }
+        return mIsProfileReady;
+    }
+
+    private final class BluetoothPanServiceListener implements BluetoothProfile.ServiceListener {
+
+        @Override
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            mProfileConnectedlock.lock();
+            mBluetoothPan = (BluetoothPan) proxy;
+            mIsProfileReady = true;
+            try {
+                mConditionProfileIsConnected.signal();
+            } finally {
+                mProfileConnectedlock.unlock();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(int profile) {
+        }
+    }
+}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothVolumeControlTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothVolumeControlTest.java
index 321107a..26237c1 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothVolumeControlTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothVolumeControlTest.java
@@ -21,22 +21,15 @@
 
 import static org.junit.Assert.assertThrows;
 
-import android.app.UiAutomation;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothVolumeControl;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothVolumeControl;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.os.Build;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-import androidx.test.InstrumentationRegistry;
-
-import com.android.compatibility.common.util.ApiLevelUtil;
-
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
@@ -69,47 +62,45 @@
             assertTrue(device == mTestDevice);
             assertTrue(volumeOffset == mTestVolumeOffset);
         }
-    };
+    }
 
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
-            mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
-                    PackageManager.FEATURE_BLUETOOTH);
+        mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_BLUETOOTH);
 
-            if (!mHasBluetooth) return;
+        if (!mHasBluetooth) return;
 
-            TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
+        TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
 
-            BluetoothManager manager = getContext().getSystemService(BluetoothManager.class);
-            mAdapter = manager.getAdapter();
-            assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        BluetoothManager manager = getContext().getSystemService(BluetoothManager.class);
+        mAdapter = manager.getAdapter();
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
 
-            mProfileConnectedlock = new ReentrantLock();
-            mConditionProfileIsConnected  = mProfileConnectedlock.newCondition();
-            mIsProfileReady = false;
-            mBluetoothVolumeControl = null;
+        mProfileConnectedlock = new ReentrantLock();
+        mConditionProfileIsConnected = mProfileConnectedlock.newCondition();
+        mIsProfileReady = false;
+        mBluetoothVolumeControl = null;
 
-            boolean isLeAudioSupportedInConfig =
-                     TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO);
-            boolean isVolumeControlEnabledInConfig =
-                     TestUtils.isProfileEnabled(BluetoothProfile.VOLUME_CONTROL);
-            if (isLeAudioSupportedInConfig) {
-                /* If Le Audio is supported then Volume Control shall be supported */
-                assertTrue("Config must be true when profile is supported",
-                        isVolumeControlEnabledInConfig);
-            }
+        boolean isLeAudioSupportedInConfig =
+                TestUtils.isProfileEnabled(BluetoothProfile.LE_AUDIO);
+        boolean isVolumeControlEnabledInConfig =
+                TestUtils.isProfileEnabled(BluetoothProfile.VOLUME_CONTROL);
+        if (isLeAudioSupportedInConfig) {
+            /* If Le Audio is supported then Volume Control shall be supported */
+            assertTrue("Config must be true when profile is supported",
+                    isVolumeControlEnabledInConfig);
+        }
 
-            if (isVolumeControlEnabledInConfig) {
-                mIsVolumeControlSupported = mAdapter.getProfileProxy(getContext(),
-                        new BluetoothVolumeControlServiceListener(),
-                        BluetoothProfile.VOLUME_CONTROL);
-                assertTrue("Service shall be supported ", mIsVolumeControlSupported);
+        if (isVolumeControlEnabledInConfig) {
+            mIsVolumeControlSupported = mAdapter.getProfileProxy(getContext(),
+                    new BluetoothVolumeControlServiceListener(),
+                    BluetoothProfile.VOLUME_CONTROL);
+            assertTrue("Service shall be supported ", mIsVolumeControlSupported);
 
-                mTestCallback = new TestCallback();
-                mTestExecutor = mContext.getMainExecutor();
-            }
+            mTestCallback = new TestCallback();
+            mTestExecutor = mContext.getMainExecutor();
         }
     }
 
@@ -126,7 +117,7 @@
                 mTestCallback = null;
                 mTestExecutor = null;
             }
-            if (mAdapter != null ) {
+            if (mAdapter != null) {
                 assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
                 mAdapter = null;
             }
@@ -161,7 +152,7 @@
         assertTrue(connectedDevices.isEmpty());
     }
 
-    public void  testRegisterUnregisterCallback() {
+    public void testRegisterUnregisterCallback() {
         if (!(mHasBluetooth && mIsVolumeControlSupported)) return;
 
         assertTrue(waitForProfileConnect());
@@ -239,6 +230,65 @@
         assertTrue(mVolumeOffsetChangedCallbackCalled);
     }
 
+    public void testGetConnectionState() {
+        if (!(mHasBluetooth && mIsVolumeControlSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothVolumeControl);
+
+        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+
+        // Verify returns false when invalid input is given
+        assertEquals(BluetoothProfile.STATE_DISCONNECTED,
+                mBluetoothVolumeControl.getConnectionState(null));
+
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+
+        // Verify returns false if bluetooth is not enabled
+        assertEquals(BluetoothProfile.STATE_DISCONNECTED,
+                mBluetoothVolumeControl.getConnectionState(testDevice));
+    }
+
+    public void testGetConnectionPolicy() {
+        if (!(mHasBluetooth && mIsVolumeControlSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothVolumeControl);
+
+        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+
+        // Verify returns false when invalid input is given
+        assertEquals(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN,
+                mBluetoothVolumeControl.getConnectionPolicy(null));
+
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+
+        // Verify returns false if bluetooth is not enabled
+        assertEquals(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN,
+                mBluetoothVolumeControl.getConnectionPolicy(testDevice));
+    }
+
+    public void testSetConnectionPolicy() {
+        if (!(mHasBluetooth && mIsVolumeControlSupported)) return;
+
+        assertTrue(waitForProfileConnect());
+        assertNotNull(mBluetoothVolumeControl);
+
+        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+
+        // Verify returns false when invalid input is given
+        assertFalse(mBluetoothVolumeControl.setConnectionPolicy(
+                testDevice, BluetoothProfile.CONNECTION_POLICY_UNKNOWN));
+        assertFalse(mBluetoothVolumeControl.setConnectionPolicy(
+                null, BluetoothProfile.CONNECTION_POLICY_ALLOWED));
+
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+
+        // Verify returns false if bluetooth is not enabled
+        assertFalse(mBluetoothVolumeControl.setConnectionPolicy(
+                testDevice, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN));
+    }
+
     private boolean waitForProfileConnect() {
         mProfileConnectedlock.lock();
         try {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/SystemBluetoothTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/SystemBluetoothTest.java
new file mode 100644
index 0000000..e9a9314
--- /dev/null
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/SystemBluetoothTest.java
@@ -0,0 +1,462 @@
+/*
+ * 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.bluetooth.cts;
+
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import android.app.UiAutomation;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothStatusCodes;
+import android.bluetooth.BluetoothUuid;
+import android.bluetooth.OobData;
+import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.AdvertisingSetParameters;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.ParcelUuid;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.InstrumentationRegistry;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class SystemBluetoothTest extends AndroidTestCase {
+    private static final String TAG = SystemBluetoothTest.class.getSimpleName();
+
+    private static final long DEFAULT_DISCOVERY_TIMEOUT_MS = 12800;
+    private static final int DISCOVERY_START_TIMEOUT = 500;
+    private static final String BLE_SCAN_ALWAYS_AVAILABLE = "ble_scan_always_enabled";
+
+    private boolean mHasBluetooth;
+    private BluetoothAdapter mAdapter;
+    private UiAutomation mUiAutomation;
+
+    private ReentrantLock mDiscoveryStartedLock;
+    private Condition mConditionDiscoveryStarted;
+    private boolean mIsDiscoveryStarted;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_BLUETOOTH);
+        if (!mHasBluetooth) return;
+
+        mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
+
+        BluetoothManager manager = getContext().getSystemService(BluetoothManager.class);
+        mAdapter = manager.getAdapter();
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (mHasBluetooth) {
+            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        }
+    }
+
+    /**
+     * Test enable/disable silence mode and check whether the device is in correct state.
+     */
+    public void testSilenceMode() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        BluetoothDevice device = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+        assertTrue(device.setSilenceMode(true));
+        assertFalse(device.isInSilenceMode());
+
+        assertTrue(device.setSilenceMode(false));
+        assertFalse(device.isInSilenceMode());
+    }
+
+    /**
+     * Test whether the metadata would be stored in Bluetooth storage successfully,
+     * also test whether OnMetadataChangedListener would callback correct values when
+     * metadata is changed..
+     */
+    public void testSetGetMetadata() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        byte[] testByteData = "Test Data".getBytes();
+        BluetoothDevice device = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+        BluetoothAdapter.OnMetadataChangedListener listener =
+                new BluetoothAdapter.OnMetadataChangedListener() {
+                    @Override
+                    public void onMetadataChanged(BluetoothDevice dev, int key, byte[] value) {
+                        assertEquals(dev, device);
+                        assertEquals(key, BluetoothDevice.METADATA_MANUFACTURER_NAME);
+                        assertArrayEquals(value, testByteData);
+                    }
+                };
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        assertTrue(adapter.addOnMetadataChangedListener(device,
+                getContext().getMainExecutor(), listener));
+        assertTrue(device.setMetadata(
+                BluetoothDevice.METADATA_MANUFACTURER_NAME, testByteData));
+        assertArrayEquals(device.getMetadata(
+                BluetoothDevice.METADATA_MANUFACTURER_NAME), testByteData);
+        assertTrue(adapter.removeOnMetadataChangedListener(device, listener));
+    }
+
+    public void testDiscoveryEndMillis() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        mDiscoveryStartedLock = new ReentrantLock();
+        mConditionDiscoveryStarted = mDiscoveryStartedLock.newCondition();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
+        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+        mContext.registerReceiver(mDiscoveryStartedReceiver, filter);
+
+        mAdapter.startDiscovery();
+        assertTrue(waitForDiscoveryStart());
+        long discoveryEndTime = mAdapter.getDiscoveryEndMillis();
+        long currentTime = System.currentTimeMillis();
+        assertTrue(discoveryEndTime > currentTime);
+        assertTrue(discoveryEndTime - currentTime < DEFAULT_DISCOVERY_TIMEOUT_MS);
+        mContext.unregisterReceiver(mDiscoveryStartedReceiver);
+    }
+
+    /**
+     * Tests whether the static function BluetoothUuid#containsAnyUuid properly identifies whether
+     * the ParcelUuid arrays have at least one common element.
+     */
+    public void testContainsAnyUuid() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        ParcelUuid[] deviceAUuids = new ParcelUuid[]{BluetoothUuid.A2DP_SOURCE, BluetoothUuid.HFP,
+                BluetoothUuid.ADV_AUDIO_DIST, BluetoothUuid.AVRCP_CONTROLLER,
+                BluetoothUuid.BASE_UUID, BluetoothUuid.HID, BluetoothUuid.HEARING_AID};
+        ParcelUuid[] deviceBUuids = new ParcelUuid[]{BluetoothUuid.A2DP_SINK, BluetoothUuid.BNEP,
+                BluetoothUuid.AVRCP_TARGET, BluetoothUuid.HFP_AG,
+                BluetoothUuid.HOGP, BluetoothUuid.HSP_AG};
+        ParcelUuid[] deviceCUuids = new ParcelUuid[]{BluetoothUuid.HSP, BluetoothUuid.MAP,
+                BluetoothUuid.MAS, BluetoothUuid.MNS, BluetoothUuid.NAP,
+                BluetoothUuid.OBEX_OBJECT_PUSH, BluetoothUuid.PANU, BluetoothUuid.PBAP_PCE,
+                BluetoothUuid.PBAP_PSE, BluetoothUuid.SAP, BluetoothUuid.A2DP_SOURCE};
+        assertTrue(BluetoothUuid.containsAnyUuid(null, null));
+        assertTrue(BluetoothUuid.containsAnyUuid(new ParcelUuid[]{}, null));
+        assertTrue(BluetoothUuid.containsAnyUuid(null, new ParcelUuid[]{}));
+        assertFalse(BluetoothUuid.containsAnyUuid(null, deviceAUuids));
+        assertFalse(BluetoothUuid.containsAnyUuid(deviceAUuids, null));
+        assertFalse(BluetoothUuid.containsAnyUuid(deviceAUuids, deviceBUuids));
+        assertTrue(BluetoothUuid.containsAnyUuid(deviceAUuids, deviceCUuids));
+        assertTrue(BluetoothUuid.containsAnyUuid(deviceBUuids, deviceBUuids));
+    }
+
+    public void testParseUuidFrom() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        byte[] uuid16 = new byte[]{0x0B, 0x11};
+        assertEquals(BluetoothUuid.A2DP_SINK, BluetoothUuid.parseUuidFrom(uuid16));
+
+        byte[] uuid32 = new byte[]{(byte) 0xF0, (byte) 0xFD, 0x00, 0x00};
+        assertEquals(BluetoothUuid.HEARING_AID, BluetoothUuid.parseUuidFrom(uuid32));
+
+        byte[] uuid128 = new byte[]{(byte) 0xFB, 0x34, (byte) 0x9B, 0x5F, (byte) 0x80, 0x00, 0x00,
+                (byte) 0x80, 0x00, 0x10, 0x00, 0x00, 0x1F, 0x11, 0x00, 0x00};
+        assertEquals(BluetoothUuid.HFP_AG, BluetoothUuid.parseUuidFrom(uuid128));
+    }
+
+    public void testCanBondWithoutDialog() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        // Verify the method returns false on a device that doesn't meet the criteria
+        BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+        assertFalse(testDevice.canBondWithoutDialog());
+    }
+
+    public void testBleOnlyMode() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        int originalScanAlwaysAvailableValue = 0;
+
+        try {
+            originalScanAlwaysAvailableValue = Settings.Global.getInt(mContext.getContentResolver(),
+                    BLE_SCAN_ALWAYS_AVAILABLE);
+        } catch (Settings.SettingNotFoundException e) { // Uses 0 or not available as original
+        }
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        // Allows BLE scanning to be performed even if the adapter is off
+        Settings.Global.putInt(mContext.getContentResolver(), BLE_SCAN_ALWAYS_AVAILABLE, 1);
+
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        assertFalse(mAdapter.isEnabled());
+
+        assertTrue(BTAdapterUtils.enableBLE(mAdapter, mContext));
+        assertTrue(BTAdapterUtils.disableBLE(mAdapter, mContext));
+
+        Settings.Global.putInt(mContext.getContentResolver(), BLE_SCAN_ALWAYS_AVAILABLE,
+                originalScanAlwaysAvailableValue);
+    }
+
+    public void testSetGetOwnAddressType() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        AdvertisingSetParameters.Builder paramsBuilder = new AdvertisingSetParameters.Builder();
+
+        assertEquals(paramsBuilder,
+                paramsBuilder.setOwnAddressType(AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT));
+        assertEquals(AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT,
+                paramsBuilder.build().getOwnAddressType());
+
+        assertEquals(paramsBuilder,
+                paramsBuilder.setOwnAddressType(AdvertisingSetParameters.ADDRESS_TYPE_PUBLIC));
+        assertEquals(AdvertisingSetParameters.ADDRESS_TYPE_PUBLIC,
+                paramsBuilder.build().getOwnAddressType());
+
+        assertEquals(paramsBuilder,
+                paramsBuilder.setOwnAddressType(AdvertisingSetParameters.ADDRESS_TYPE_RANDOM));
+        assertEquals(AdvertisingSetParameters.ADDRESS_TYPE_RANDOM,
+                paramsBuilder.build().getOwnAddressType());
+
+        AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
+
+        assertEquals(settingsBuilder,
+                settingsBuilder.setOwnAddressType(AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT));
+        assertEquals(AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT,
+                settingsBuilder.build().getOwnAddressType());
+
+        assertEquals(settingsBuilder,
+                settingsBuilder.setOwnAddressType(AdvertisingSetParameters.ADDRESS_TYPE_PUBLIC));
+        assertEquals(AdvertisingSetParameters.ADDRESS_TYPE_PUBLIC,
+                settingsBuilder.build().getOwnAddressType());
+
+        assertEquals(settingsBuilder,
+                settingsBuilder.setOwnAddressType(AdvertisingSetParameters.ADDRESS_TYPE_RANDOM));
+        assertEquals(AdvertisingSetParameters.ADDRESS_TYPE_RANDOM,
+                settingsBuilder.build().getOwnAddressType());
+    }
+
+    public void testGetSupportedProfiles() {
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+
+        List<Integer> profiles = mAdapter.getSupportedProfiles();
+        assertNotNull(profiles);
+    }
+
+    public void testEnableNoAutoConnect() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        // Assert that when Bluetooth is already enabled, the method immediately returns true
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        assertTrue(mAdapter.enableNoAutoConnect());
+    }
+
+    private boolean isBluetoothPersistedOff() {
+        // A value of "0" in Settings.Global.BLUETOOTH_ON means the OFF state was persisted
+        return (Settings.Global.getInt(
+                mContext.getContentResolver(), Settings.Global.BLUETOOTH_ON, -1) == 0);
+    }
+
+    public void testDisableBluetoothPersistFalse() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, /* persist= */ false, mContext));
+        assertFalse(isBluetoothPersistedOff());
+    }
+
+    public void testDisableBluetoothPersistTrue() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, /* persist= */ true, mContext));
+        assertTrue(isBluetoothPersistedOff());
+    }
+
+    public void testSetLowLatencyAudioAllowed() {
+        if (!mHasBluetooth) {
+            return;
+        }
+        BluetoothDevice device = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+        assertFalse(device.setLowLatencyAudioAllowed(true));
+        assertFalse(device.setLowLatencyAudioAllowed(false));
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        assertTrue(device.setLowLatencyAudioAllowed(true));
+        assertTrue(device.setLowLatencyAudioAllowed(false));
+    }
+
+    public void testGenerateLocalOobData() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        Executor executor = new Executor() {
+            @Override
+            public void execute(Runnable command) {
+            }
+        };
+        BluetoothAdapter.OobDataCallback callback = new BluetoothAdapter.OobDataCallback() {
+            @Override
+            public void onOobData(int transport, @NonNull OobData oobData) {
+                fail("Should have failed to generate local oob data as Bluetooth is disabled");
+            }
+
+            @Override
+            public void onError(int errorCode) {
+            }
+        };
+
+        try {
+            mAdapter.generateLocalOobData(BluetoothDevice.TRANSPORT_AUTO, executor, callback);
+            fail("generateLocalOobData should throw an IllegalArgumentException due to invalid "
+                    + "transport");
+        } catch (IllegalArgumentException ignored) {
+        }
+
+        try {
+            mAdapter.generateLocalOobData(BluetoothDevice.TRANSPORT_BREDR, executor, null);
+            fail("generateLocalOobData should throw a NullPointerException due to passing a null "
+                    + "callback");
+        } catch (NullPointerException ignored) {
+        }
+
+        mAdapter.generateLocalOobData(BluetoothDevice.TRANSPORT_BREDR, executor, callback);
+    }
+
+    public void testSetScanMode() {
+        if (!mHasBluetooth) {
+            return;
+        }
+
+        assertEquals(BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
+                mAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
+
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        try {
+            mAdapter.setScanMode(0);
+            fail("Invalid scan mode");
+        } catch (IllegalArgumentException ignored) {
+        }
+
+        /* TODO(rahulsabnis): Fix the callback system so these work as intended
+        assertEquals(BluetoothStatusCodes.SUCCESS,
+                mAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_NONE));
+        assertEquals(BluetoothAdapter.SCAN_MODE_NONE, mAdapter.getScanMode());
+        assertEquals(BluetoothStatusCodes.SUCCESS,
+                mAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
+        assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE, mAdapter.getScanMode());
+
+        assertEquals(BluetoothStatusCodes.SUCCESS,
+                mAdapter.setDiscoverableTimeout(Duration.ofSeconds(1)));
+        assertEquals(BluetoothStatusCodes.SUCCESS,
+                mAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
+        assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, mAdapter.getScanMode());
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE, mAdapter.getScanMode());
+        */
+    }
+
+    private boolean waitForDiscoveryStart() {
+        mDiscoveryStartedLock.lock();
+        try {
+            // Wait for discovery to be started
+            while (!mIsDiscoveryStarted) {
+                if (!mConditionDiscoveryStarted.await(
+                        DISCOVERY_START_TIMEOUT, TimeUnit.MILLISECONDS)) {
+                    Log.e(TAG, "Timeout while waiting for discovery to start");
+                    break;
+                }
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "waitForDiscoveryStart: interrrupted");
+        } finally {
+            mDiscoveryStartedLock.unlock();
+        }
+        return mIsDiscoveryStarted;
+    }
+
+    private final BroadcastReceiver mDiscoveryStartedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) {
+                Log.i(TAG, "Discovery started");
+                mDiscoveryStartedLock.lock();
+                mIsDiscoveryStarted = true;
+                try {
+                    mConditionDiscoveryStarted.signal();
+                } catch (IllegalMonitorStateException ex) {
+                } finally {
+                    mDiscoveryStartedLock.unlock();
+                }
+            }
+        }
+    };
+}
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
index e4fbee6..5afdbb1 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
@@ -525,10 +525,9 @@
             mTelephonyManager.getServiceState();
             mTelephonyManager.getManualNetworkSelectionPlmn();
             mTelephonyManager.setForbiddenPlmns(new ArrayList<String>());
-            int activeModemCount = mTelephonyManager.getActiveModemCount();
-            for (int i = 0; i < activeModemCount; i++) {
-                mTelephonyManager.isModemEnabledForSlot(i);
-            }
+            // TODO(b/235490259): test all slots once TM#isModemEnabledForSlot allows
+            mTelephonyManager.isModemEnabledForSlot(
+                    SubscriptionManager.getSlotIndex(mTelephonyManager.getSubscriptionId()));
         } catch (SecurityException e) {
             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
         }
@@ -1105,7 +1104,7 @@
         }
 
         // Set subscription group with current sub Id.
-        int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+        int subId = SubscriptionManager.getDefaultSubscriptionId();
         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
         ParcelUuid uuid = ShellIdentityUtils.invokeMethodWithShellPermissions(mSubscriptionManager,
                 (sm) -> sm.createSubscriptionGroup(Arrays.asList(subId)));
@@ -1142,7 +1141,7 @@
     @Test
     public void testAddSubscriptionToExistingGroupForEsim() {
         // Set subscription group with current sub Id.
-        int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+        int subId = SubscriptionManager.getDefaultSubscriptionId();
         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
         ParcelUuid uuid = mSubscriptionManager.createSubscriptionGroup(Arrays.asList(subId));
 
@@ -1172,7 +1171,7 @@
      */
     @Test
     public void testOpportunistic() {
-        int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+        int subId = SubscriptionManager.getDefaultSubscriptionId();
         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
         SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
         boolean oldOpportunistic = info.isOpportunistic();
diff --git a/tests/tests/companion/common/src/android/companion/cts/common/TestBase.kt b/tests/tests/companion/common/src/android/companion/cts/common/TestBase.kt
index 8c03abd..ef9d958 100644
--- a/tests/tests/companion/common/src/android/companion/cts/common/TestBase.kt
+++ b/tests/tests/companion/common/src/android/companion/cts/common/TestBase.kt
@@ -79,8 +79,7 @@
         })
 
         // Make sure CompanionDeviceServices are not bound.
-        assertFalse(PrimaryCompanionService.isBound)
-        assertFalse(SecondaryCompanionService.isBound)
+        assertValidCompanionDeviceServicesUnbind()
 
         setUp()
     }
diff --git a/tests/tests/companion/core/src/android/companion/cts/core/DumpSysTest.kt b/tests/tests/companion/core/src/android/companion/cts/core/DumpSysTest.kt
new file mode 100644
index 0000000..dce993a
--- /dev/null
+++ b/tests/tests/companion/core/src/android/companion/cts/core/DumpSysTest.kt
@@ -0,0 +1,113 @@
+/*
+ * 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.companion.cts.core
+
+import android.companion.cts.common.DEVICE_DISPLAY_NAME_A
+import android.companion.cts.common.DEVICE_DISPLAY_NAME_B
+import android.platform.test.annotations.AppModeFull
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compatibility.common.util.SystemUtil
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+
+/**
+ * Test CDM system dump.
+ *
+ * Run: atest CtsCompanionDeviceManagerCoreTestCases:DumpSysTest
+ */
+@AppModeFull(reason = "CompanionDeviceManager APIs are not available to the instant apps.")
+@RunWith(AndroidJUnit4::class)
+class DumpSysTest : CoreTestBase() {
+
+    @Test
+    fun test_dump_noAssociation() {
+        // Dump without creating any association.
+        val out = dumpCurrentState()
+        assertTrue(out[0].contains("Companion Device Associations: <empty>"))
+        assertTrue(out[1].contains("Companion Device Present: <empty>"))
+        assertFalse(out[2].contains("u/$userId"))
+    }
+
+    @Test
+    fun test_dump_singleDevice() {
+        // Create a self-managed association.
+        val associationId = createSelfManagedAssociation(DEVICE_DISPLAY_NAME_A)
+
+        var out = dumpCurrentState()
+        assertTrue(out[0].contains("mId=$associationId")) // Device is associated
+        assertFalse(out[1].contains("id=$associationId")) // But not present yet
+        assertFalse(out[2].contains("u$userId\\$targetPackageName")) // App is not bound yet
+
+        // Publish device's presence.
+        cdm.notifyDeviceAppeared(associationId)
+
+        out = dumpCurrentState()
+        assertTrue(out[0].contains("mId=$associationId")) // Device is still associated
+        assertTrue(out[1].contains("id=$associationId")) // And also present
+        assertTrue(out[2].contains("u$userId\\$targetPackageName")) // App is now bound
+
+        cdm.notifyDeviceDisappeared(associationId)
+    }
+
+    @Test
+    fun test_dump_multiDevice() {
+        // Associate with multiple devices.
+        val idA = createSelfManagedAssociation(DEVICE_DISPLAY_NAME_A)
+        val idB = createSelfManagedAssociation(DEVICE_DISPLAY_NAME_B)
+
+        var out = dumpCurrentState()
+        assertTrue(out[0].contains("mId=$idA")) // Device A associated
+        assertTrue(out[0].contains("mId=$idB")) // Device B associated
+        assertFalse(out[1].contains("id=$idA")) // Device A not present
+        assertFalse(out[1].contains("id=$idB")) // Device B not present
+        assertFalse(out[2].contains("u$userId\\$targetPackageName")) // App is not bound yet
+
+        // Only publish device A's presence.
+        cdm.notifyDeviceAppeared(idA)
+
+        out = dumpCurrentState()
+        assertTrue(out[1].contains("id=$idA")) // Device A is now present
+        assertFalse(out[1].contains("id=$idB")) // Device B still not present
+        assertTrue(out[2].contains("u$userId\\$targetPackageName")) // App is now bound
+
+        cdm.notifyDeviceDisappeared(idA)
+    }
+
+    /**
+     * Uses adb shell command to dump current state of CDM and splits output into its components.
+     */
+    private fun dumpCurrentState(): Array<String> {
+        val dump = SystemUtil.runShellCommand("dumpsys companiondevice")
+
+        val headerIndex0 = dump.indexOf("Companion Device Associations:")
+        assertTrue(headerIndex0 >= 0)
+
+        val headerIndex1 = dump.indexOf("Companion Device Present:")
+        assertTrue(headerIndex1 >= 0)
+
+        val headerIndex2 = dump.indexOf("Companion Device Application Controller:")
+        assertTrue(headerIndex2 >= 0)
+
+        return arrayOf(
+                dump.substring(headerIndex0, headerIndex1),
+                dump.substring(headerIndex1, headerIndex2),
+                dump.substring(headerIndex2)
+        )
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/content/AndroidTest.xml b/tests/tests/content/AndroidTest.xml
index a8d48fa..6ae7045 100644
--- a/tests/tests/content/AndroidTest.xml
+++ b/tests/tests/content/AndroidTest.xml
@@ -44,6 +44,7 @@
         <option name="push" value="CtsContentMockLauncherTestApp.apk->/data/local/tmp/cts/content/CtsContentMockLauncherTestApp.apk" />
         <option name="push" value="CtsContentLongLabelNameTestApp.apk->/data/local/tmp/cts/content/CtsContentLongLabelNameTestApp.apk" />
         <option name="push" value="CtsSyncAccountAccessStubs.apk->/data/local/tmp/cts/content/CtsSyncAccountAccessStubs.apk" />
+        <option name="push" value="CtsSyncAccountAccessStubs_mdpi-v4.apk->/data/local/tmp/cts/content/CtsSyncAccountAccessStubs_mdpi-v4.apk" />
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
diff --git a/tests/tests/content/SyncAccountAccessStubs/Android.bp b/tests/tests/content/SyncAccountAccessStubs/Android.bp
index 9f1e9ab..5bfd89c 100644
--- a/tests/tests/content/SyncAccountAccessStubs/Android.bp
+++ b/tests/tests/content/SyncAccountAccessStubs/Android.bp
@@ -24,6 +24,9 @@
     static_libs: ["android-support-annotations"],
     srcs: ["src/**/*.java"],
     sdk_version: "current",
+    package_splits: [
+        "mdpi-v4",
+    ],
     test_suites: [
         "mts",
         "cts",
@@ -35,5 +38,5 @@
     dex_preopt: {
         enabled: false,
     },
-    min_sdk_version : "29"
+    min_sdk_version: "29",
 }
diff --git a/tests/tests/content/src/android/content/cts/ContentProviderTest.java b/tests/tests/content/src/android/content/cts/ContentProviderTest.java
index a2b4d83..986ece1 100644
--- a/tests/tests/content/src/android/content/cts/ContentProviderTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentProviderTest.java
@@ -34,15 +34,19 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
+import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.UserHandle;
 import android.platform.test.annotations.AppModeFull;
 import android.provider.MediaStore;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.bedstead.harrier.BedsteadJUnit4;
@@ -56,9 +60,14 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 
 /**
  * Test {@link ContentProvider}.
@@ -226,13 +235,12 @@
 
     @Test
     public void testOpenFileHelper() throws IOException {
-
         // create a temporary File
         sContext.openFileOutput(TEST_FILE_NAME, Context.MODE_PRIVATE).close();
         File file = sContext.getFileStreamPath(TEST_FILE_NAME);
         assertTrue(file.exists());
 
-        ContentProvider cp = new OpenFileContentProvider(file.getAbsolutePath(), TEST_DB_NAME);
+        ContentProvider cp = new OpenFilePipeContentProvider(file.getAbsolutePath(), TEST_DB_NAME);
 
         Uri uri = Uri.parse("content://test");
         assertNotNull(cp.openFile(uri, "r"));
@@ -261,6 +269,42 @@
         }
     }
 
+    private static void assertAssetFileContents(AssetFileDescriptor assetFileDescriptor,
+            String message) throws IOException {
+        assertNotNull(assetFileDescriptor);
+        try (DataInputStream dis = new DataInputStream(
+                new FileInputStream(assetFileDescriptor.getFileDescriptor()))) {
+            assertEquals(message, dis.readUTF());
+        }
+    }
+
+    @Test
+    public void testOpenPipeHelper() throws IOException {
+        // create a temporary File
+        sContext.openFileOutput(TEST_FILE_NAME, Context.MODE_PRIVATE).close();
+        File file = sContext.getFileStreamPath(TEST_FILE_NAME);
+        assertTrue(file.exists());
+
+        ContentProvider cp = new OpenFilePipeContentProvider(file.getAbsolutePath(), TEST_DB_NAME);
+
+        Uri uri = Uri.parse("content://test");
+        assertAssetFileContents(cp.openAssetFile(uri, "r"), "OK");
+
+        uri = Uri.parse("content://test");
+        assertAssetFileContents(cp.openAssetFile(uri, "wrong"),
+                "java.lang.IllegalArgumentException: Bad mode: wrong");
+
+        // delete the temporary file
+        file.delete();
+
+        uri = Uri.parse("content://test");
+        assertAssetFileContents(cp.openAssetFile(uri, "r"),
+                "java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)");
+
+        assertAssetFileContents(cp.openAssetFile((Uri) null, "r"),
+                "java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)");
+    }
+
     @Test
     public void testOnConfigurationChanged() {
         // cannot trigger this callback reliably
@@ -440,12 +484,14 @@
     }
 
     /**
-     * This provider implements openFile() using ContentProvider.openFileHelper().
+     * This provider implements openFile/openAssetFile() using
+     * ContentProvider.openFileHelper/openPipeHelper().
      */
-    private class OpenFileContentProvider extends ContentProvider {
+    private class OpenFilePipeContentProvider extends ContentProvider implements
+            ContentProvider.PipeDataWriter<String> {
         private SQLiteDatabase mDb;
 
-        OpenFileContentProvider(String fileName, String dbName) {
+        OpenFilePipeContentProvider(String fileName, String dbName) {
             // delete the database if it already exists
             sContext.deleteDatabase(dbName);
             mDb = sContext.openOrCreateDatabase(dbName, Context.MODE_PRIVATE, null);
@@ -488,5 +534,29 @@
         public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
             return openFileHelper(uri, mode);
         }
+
+        @Override
+        public AssetFileDescriptor openAssetFile(Uri uri, String mode)
+                throws FileNotFoundException {
+            return new AssetFileDescriptor(openPipeHelper(uri, "text/html", null,
+                    mode, this), 0,
+                    AssetFileDescriptor.UNKNOWN_LENGTH);
+        }
+
+        @Override
+        public void writeDataToPipe(@NonNull ParcelFileDescriptor output, @NonNull Uri uri,
+                @NonNull String mimeType, @Nullable Bundle opts, @Nullable String args) {
+            try (DataOutputStream dos = new DataOutputStream(
+                    new FileOutputStream(output.getFileDescriptor()))) {
+                try (InputStream is = new FileInputStream(
+                        openFile(uri, args).getFileDescriptor())) {
+                    dos.writeUTF("OK");
+                } catch (Throwable t) {
+                    dos.writeUTF(t.toString());
+                }
+            } catch (IOException ignored) {
+
+            }
+        }
     }
 }
diff --git a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
index 02ee351..2b2e10f 100644
--- a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
@@ -330,8 +330,8 @@
         final String systemPath = Environment.getRootDirectory().getAbsolutePath();
         final String vendorPath = Environment.getVendorDirectory().getAbsolutePath();
         final String packageName = getPartitionFirstPackageName(systemPath, vendorPath);
-        assertNotNull("Can not find any vendor packages on " + vendorPath + " or "
-                + systemPath + vendorPath, packageName);
+        // vendor package may not exist in every builds
+        assumeNotNull(packageName);
 
         final PackageInfo info = getContext().getPackageManager().getPackageInfo(
                 packageName.trim(), PackageManager.PackageInfoFlags.of(0));
diff --git a/tests/tests/content/src/android/content/pm/cts/ChecksumsTest.java b/tests/tests/content/src/android/content/pm/cts/ChecksumsTest.java
index 5cb59c2..4359d7d 100644
--- a/tests/tests/content/src/android/content/pm/cts/ChecksumsTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ChecksumsTest.java
@@ -52,10 +52,12 @@
 import android.content.pm.PackageManager;
 import android.content.pm.Signature;
 import android.content.pm.cts.util.AbandonAllPackageSessionsRule;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.SystemProperties;
 import android.platform.test.annotations.AppModeFull;
 import android.util.ExceptionUtils;
 
@@ -71,6 +73,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -152,6 +155,11 @@
             new Checksum(TYPE_WHOLE_SHA256, hexStringToBytes(TEST_FIXED_APK_SHA256)),
             new Checksum(TYPE_WHOLE_MD5, hexStringToBytes(TEST_FIXED_APK_MD5))};
 
+    /** Default is to not use fs-verity since it depends on kernel support. */
+    private static final int FSVERITY_DISABLED = 0;
+
+    /** Standard fs-verity. */
+    private static final int FSVERITY_ENABLED = 2;
 
     private static final byte[] NO_SIGNATURE = null;
 
@@ -315,6 +323,7 @@
     @LargeTest
     @Test
     public void testFixedFSVerityDefaultChecksums() throws Exception {
+        Assume.assumeTrue(isApkVerityEnabled());
         installApkWithFSVerity(TEST_FIXED_APK_FSVERITY, TEST_FIXED_APK_FSVERITY_FSVSIG);
         assertTrue(isAppInstalled(FIXED_FSVERITY_PACKAGE_NAME));
 
@@ -1513,6 +1522,13 @@
         return getPackageManager().hasSystemFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY);
     }
 
+    // From PackageManagerServiceUtils.
+    private static boolean isApkVerityEnabled() {
+        return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.R
+                || SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED)
+                == FSVERITY_ENABLED;
+    }
+
     private byte[] readSignature() throws IOException {
         return readSignature(TEST_FIXED_APK_DIGESTS_SIGNATURE);
     }
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandMultiUserTest.kt b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandMultiUserTest.kt
index cf9dde0..416d19f 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandMultiUserTest.kt
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandMultiUserTest.kt
@@ -237,19 +237,21 @@
         val intentFilter = IntentFilter()
         intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED)
         intentFilter.addDataScheme("package")
-        context.registerReceiver(
-            broadcastReceiverForPrimaryUser,
-            intentFilter,
-            null,
-            backgroundHandler,
-            RECEIVER_EXPORTED
-        )
         uiAutomation.adoptShellPermissionIdentity(
             Manifest.permission.INTERACT_ACROSS_USERS,
             Manifest.permission.INTERACT_ACROSS_USERS_FULL
         )
+        val contextPrimaryUser = context.createContextAsUser(primaryUser.userHandle(), 0)
+        val contextSecondaryUser = context.createContextAsUser(secondaryUser.userHandle(), 0)
         try {
-            context.createContextAsUser(secondaryUser.userHandle(), 0).registerReceiver(
+            contextPrimaryUser.registerReceiver(
+                broadcastReceiverForPrimaryUser,
+                intentFilter,
+                null,
+                backgroundHandler,
+                RECEIVER_EXPORTED
+            )
+            contextSecondaryUser.registerReceiver(
                 broadcastReceiverForSecondaryUser,
                 intentFilter,
                 null,
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
index ab5211e..c3b8a21 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
@@ -655,6 +655,42 @@
     }
 
     @Test
+    public void testDontKillRemovedWithBaseApkFullInstall() throws Exception {
+        installPackage(TEST_HW5);
+
+        getUiAutomation().adoptShellPermissionIdentity();
+        try {
+            final PackageInstaller installer = getPackageInstaller();
+            final SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
+            params.setAppPackageName(TEST_APP_PACKAGE);
+            params.setDontKillApp(true);
+
+            final int sessionId = installer.createSession(params);
+            PackageInstaller.Session session = installer.openSession(sessionId);
+            assertTrue((session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0);
+
+            writeFileToSession(session, "hw7", TEST_HW7);
+
+            final CompletableFuture<Boolean> result = new CompletableFuture<>();
+            session.commit(new IntentSender((IIntentSender) new IIntentSender.Stub() {
+                @Override
+                public void send(int code, Intent intent, String resolvedType,
+                        IBinder whitelistToken, IIntentReceiver finishedReceiver,
+                        String requiredPermission, Bundle options) throws RemoteException {
+                    boolean dontKillApp =
+                            (session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0;
+                    result.complete(dontKillApp);
+                }
+            }));
+
+            // We are updating base.apk. Flag to be removed.
+            assertFalse(result.get());
+        } finally {
+            getUiAutomation().dropShellPermissionIdentity();
+        }
+    }
+
+    @Test
     public void testDontKillRemovedWithBaseApk() throws Exception {
         installPackage(TEST_HW5);
 
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
index 51286e0..b429278 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
@@ -203,6 +203,8 @@
     private static final String NON_EXISTENT_PACKAGE_NAME = "android.content.cts.nonexistent.pkg";
     private static final String STUB_PACKAGE_APK = SAMPLE_APK_BASE
             + "CtsSyncAccountAccessStubs.apk";
+    private static final String STUB_PACKAGE_SPLIT =
+            SAMPLE_APK_BASE + "CtsSyncAccountAccessStubs_mdpi-v4.apk";
 
     private static final int MAX_SAFE_LABEL_LENGTH = 1000;
 
@@ -1796,12 +1798,14 @@
     }
 
     private boolean installPackage(String apkPath) {
-        return installPackage(apkPath, false /* dontKill */);
+        return SystemUtil.runShellCommand(
+                "pm install -t " + apkPath).equals("Success\n");
     }
 
-    private boolean installPackage(String apkPath, boolean dontKill) {
+    private boolean addSplitDontKill(String packageName, String splitPath) {
         return SystemUtil.runShellCommand(
-                "pm install -t " + (dontKill ? "--dont-kill " : "") + apkPath).equals("Success\n");
+                "pm install-streaming -p " + packageName + " --dont-kill -t " + splitPath).equals(
+                "Success\n");
     }
 
     private void uninstallPackage(String packageName) {
@@ -2188,6 +2192,8 @@
 
     @Test
     public void testInstallUpdate_dontKill_applicationIsNotKilled() throws Exception {
+        installPackage(STUB_PACKAGE_APK);
+
         final Intent intent = new Intent();
         intent.setComponent(STUB_SERVICE_COMPONENT);
         final AtomicBoolean killed = new AtomicBoolean();
@@ -2202,7 +2208,7 @@
             }
         }, Context.BIND_AUTO_CREATE);
 
-        installPackage(STUB_PACKAGE_APK, true /* dontKill */);
+        addSplitDontKill(STUB_PACKAGE_NAME, STUB_PACKAGE_SPLIT);
         // The application shouldn't be killed after updating with --dont-kill.
         assertThrows(AssertionFailedError.class,
                 () -> TestUtils.waitUntil(
diff --git a/tests/tests/dreams/src/android/service/dreams/cts/DreamServiceTest.java b/tests/tests/dreams/src/android/service/dreams/cts/DreamServiceTest.java
index 227c81e..166227a 100644
--- a/tests/tests/dreams/src/android/service/dreams/cts/DreamServiceTest.java
+++ b/tests/tests/dreams/src/android/service/dreams/cts/DreamServiceTest.java
@@ -16,8 +16,10 @@
 package android.service.dreams.cts;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeFalse;
 
 import android.content.ComponentName;
+import android.content.pm.PackageManager;
 import android.server.wm.ActivityManagerTestBase;
 import android.server.wm.DreamCoordinator;
 import android.service.dreams.DreamService;
@@ -65,6 +67,9 @@
 
     @Test
     public void testDreamInSeparateProcess() {
+        assumeFalse(mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_AUTOMOTIVE));
+
         final ComponentName dreamService =
                 ComponentName.unflattenFromString(DREAM_SERVICE_COMPONENT);
         final ComponentName dreamActivity = mDreamCoordinator.setActiveDream(dreamService);
diff --git a/tests/tests/graphics/AndroidManifest.xml b/tests/tests/graphics/AndroidManifest.xml
index 6406133..9a1c591 100644
--- a/tests/tests/graphics/AndroidManifest.xml
+++ b/tests/tests/graphics/AndroidManifest.xml
@@ -55,6 +55,23 @@
         <activity android:name="android.graphics.drawable.cts.DrawableStubActivity"
              android:theme="@style/WhiteBackgroundNoWindowAnimation"
              android:screenOrientation="locked"/>
+
+        <activity android:name="android.graphics.cts.EmptyActivity"
+                  android:label="Empty Activity"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+        <activity android:name="android.graphics.cts.EmptyActivity2"
+                  android:label="Empty Activity 2"
+                  android:exported="true">
+            <intent-filter>
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+            </intent-filter>
+        </activity>
         <activity android:name="android.graphics.drawable.cts.AnimatedImageActivity"
              android:theme="@style/WhiteBackgroundNoWindowAnimation"
              android:screenOrientation="locked">
diff --git a/tests/tests/graphics/res/xml/valid_themes.xml b/tests/tests/graphics/res/xml/valid_themes.xml
index a7619d4..a7e2304 100644
--- a/tests/tests/graphics/res/xml/valid_themes.xml
+++ b/tests/tests/graphics/res/xml/valid_themes.xml
@@ -19,7 +19,7 @@
     <theme color="ffb9577a">
         <spritz>ffffff,fffbff,ffecf0,f9dbe2,dcbfc6,c0a4ab,a48a90,887076,6f595e,564147,3e2b31,27171c,000000,ffffff,fffbff,ffecf0,f2dde1,d5c2c6,b9a7aa,9e8c90,827276,6a5b5e,514347,3a2d30,24191c,000000,ffffff,fffbff,ffecf0,ffd9e2,e3bdc6,c6a2ab,aa8891,8d6e76,74565f,5b3f47,422931,2b151c,000000,ffffff,fffbff,f7efef,e8e1e1,ccc5c5,b0aaaa,958f90,7a7575,625d5e,4a4646,332f30,1e1b1b,000000,ffffff,fffbff,f7efef,e8e1e1,ccc5c5,b0aaaa,958f90,7a7575,625d5e,4a4646,332f30,1e1b1b,000000</spritz>
         <tonal_spot>ffffff,fffbff,ffecf0,ffd9e2,ffb1c8,e494ad,c67b92,a76178,8c4a60,703348,541d32,3a071d,000000,ffffff,fffbff,ffecf0,ffd9e2,e3bdc6,c6a2ab,aa8891,8d6e76,74565f,5b3f47,422931,2b151c,000000,ffffff,fffbff,ffeee2,ffdcc1,efbd94,d1a27b,b48862,976d4a,7c5635,613f20,48290b,2e1500,000000,ffffff,fffbff,faeeef,ebe0e1,cfc4c5,b3a9aa,988e90,7d7475,645c5e,4c4546,352f30,201a1b,000000,ffffff,fffbff,ffecf0,f2dde1,d5c2c6,b9a7aa,9e8c90,827276,6a5b5e,514347,3a2d30,24191c,000000</tonal_spot>
-        <vibrant>ffffff,fffbff,ffecf0,ffd9e2,ffb1c8,ff84ae,ff4896,e5007b,b90063,8e004a,650033,3e001d,000000,ffffff,fffbff,ffedec,ffdad9,f5b7b7,d79c9c,ba8382,9c6968,815252,663b3b,4c2526,331112,000000,ffffff,fffbff,ffede8,ffdbd1,ffb59f,e49982,c67f6a,a76551,8b4e3c,6e3726,532212,370d02,000000,ffffff,fffbff,ffecf0,f2dde1,d5c2c6,b9a7aa,9e8c90,827276,6a5b5e,514347,3a2d30,24191c,000000,ffffff,fffbff,ffecf0,f9dbe2,dcbfc6,c0a4ab,a48a90,887076,6f595e,564147,3e2b31,27171c,000000</vibrant>
+        <vibrant>ffffff,fffbff,ffecf0,ffd9e2,ffb1c8,ff84ae,ff4896,e5007b,b90063,8e004a,650033,3e001d,000000,ffffff,fffbff,ffedec,ffdad9,f5b7b7,d79c9c,ba8382,9c6968,815252,663b3b,4c2526,331112,000000,ffffff,fffbff,ffede8,ffdbd1,ffb59f,e49982,c67f6a,a76551,8b4e3c,6e3726,532212,370d02,000000,ffffff,fffbff,ffecf0,f6dce2,d9c0c6,bca5ab,a18b90,857176,6c5a5e,534247,3c2c30,25181c,000000,ffffff,fffbff,ffecf0,f9dbe2,dcbfc6,c0a4ab,a48a90,887076,6f595e,564147,3e2b31,27171c,000000</vibrant>
         <expressive>ffffff,fbfcff,e5f2ff,c8e6ff,8bcefd,6fb2e0,5298c4,337da8,0c648e,004c6d,00344d,001e2e,000000,ffffff,fffbff,ffede6,ffdbcb,f4ba9e,d69f85,b9856c,9b6b53,80543e,653d28,4b2714,311303,000000,ffffff,fcffdd,ebf8ad,dde9a0,c1cd86,a6b16e,8b9656,717b3e,596329,424b13,2c3400,181e00,000000,ffffff,fffbff,ffedec,f4dddd,d7c1c2,bba6a7,9f8c8c,847272,6b5a5b,524343,3b2d2d,241819,000000,ffffff,fffbff,ffedec,fcdbdb,debfc0,c2a4a5,a68a8b,8a7070,715859,584142,3f2b2c,281718,000000</expressive>
         <rainbow>ffffff,fffbff,ffecf0,ffd9e2,ffb1c8,f48bae,d57193,b55779,984061,7b2949,5e1132,3e001d,000000,ffffff,fffbff,ffecf0,ffd9e2,e3bdc6,c6a2ab,aa8891,8d6e76,74565f,5b3f47,422931,2b151c,000000,ffffff,fffbff,ffeee2,ffdcc1,efbd94,d1a27b,b48862,976d4a,7c5635,613f20,48290b,2e1500,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
         <fruit_salad>ffffff,fffbff,f9ecff,f0dbff,dcb8ff,c598f1,a97ed4,8d64b7,744c9d,5b3383,431a6b,2c0051,000000,ffffff,fffbff,f9ecff,f0dbff,dab9f9,be9edc,a384c0,876aa4,6e528a,553b71,3e2459,280d42,000000,ffffff,fffbff,ffecf0,ffd9e2,ffb1c8,e494ad,c67b92,a76178,8c4a60,703348,541d32,3a071d,000000,ffffff,fffbff,ffecf0,f6dce2,d9c0c6,bca5ab,a18b90,857176,6c5a5e,534247,3c2c30,25181c,000000,ffffff,fffbff,ffecf0,ffd9e2,e3bdc6,c6a2ab,aa8891,8d6e76,74565f,5b3f47,422931,2b151c,000000</fruit_salad>
@@ -27,7 +27,7 @@
     <theme color="ffb16407">
         <spritz>ffffff,fffbff,ffeee2,f9ddc9,dcc2ae,c0a793,a48c7a,887261,6f5a4a,564334,3d2d1f,27190c,000000,ffffff,fffbff,ffeee2,f2dfd1,d6c3b6,b9a89b,9e8e82,827368,6a5c51,51443a,3a2e25,231a11,000000,ffffff,fffbff,ffeee2,ffdcc1,e2c0a5,c6a58b,a98b72,8d7159,735943,5a422d,412c19,2a1706,000000,ffffff,fffbff,f7efec,e8e1dd,ccc5c2,b0aaa7,95908d,7a7572,625d5b,4a4644,33302e,1e1b19,000000,ffffff,fffbff,f7efec,e8e1dd,ccc5c2,b0aaa7,95908d,7a7572,625d5b,4a4644,33302e,1e1b19,000000</spritz>
         <tonal_spot>ffffff,fffbff,ffeee2,ffdcc1,ffb778,e09d60,c28349,a36931,87521c,6b3b04,4c2700,2e1500,000000,ffffff,fffbff,ffeee2,ffdcc1,e2c0a5,c6a58b,a98b72,8d7159,735943,5a422d,412c19,2a1706,000000,ffffff,fcffde,edf6bf,dfe7b2,c3cb98,a8b07e,8d9566,727a4d,5b6238,434a22,2d330e,181e00,000000,ffffff,fffbff,faefe8,ece0da,cfc4be,b3a9a3,988f89,7d746f,655d58,4c4541,352f2b,201b17,000000,ffffff,fffbff,ffeee2,f2dfd1,d6c3b6,b9a89b,9e8e82,827368,6a5c51,51443a,3a2e25,231a11,000000</tonal_spot>
-        <vibrant>ffffff,fffbff,ffeee2,ffdcc1,ffb778,fd9000,d77900,b06200,8e4e00,6c3a00,4c2700,2e1500,000000,ffffff,fffbff,ffeedc,ffddb2,e6c08d,c9a574,ad8b5c,907144,76592f,5c421a,432c06,291800,000000,ffffff,fffbff,ffefcf,ffe090,e1c477,c4a85f,a88e48,8c7330,725c1a,584401,3d2e00,241a00,000000,ffffff,fffbff,ffeee2,f2dfd1,d6c3b6,b9a89b,9e8e82,827368,6a5c51,51443a,3a2e25,231a11,000000,ffffff,fffbff,ffeee2,f9ddc9,dcc2ae,c0a793,a48c7a,887261,6f5a4a,564334,3d2d1f,27190c,000000</vibrant>
+        <vibrant>ffffff,fffbff,ffeee2,ffdcc1,ffb778,fd9000,d77900,b06200,8e4e00,6c3a00,4c2700,2e1500,000000,ffffff,fffbff,ffeedc,ffddb2,e6c08d,c9a574,ad8b5c,907144,76592f,5c421a,432c06,291800,000000,ffffff,fffbff,ffefcf,ffe090,e1c477,c4a85f,a88e48,8c7330,725c1a,584401,3d2e00,241a00,000000,ffffff,fffbff,ffeee2,f6decd,d9c2b2,bda797,a18d7e,857364,6c5b4e,534437,3c2e22,25190f,000000,ffffff,fffbff,ffeee2,f9ddc9,dcc2ae,c0a793,a48c7a,887261,6f5a4a,564334,3d2d1f,27190c,000000</vibrant>
         <expressive>ffffff,fffbff,f6edff,eaddff,d1bcff,b6a0e8,9b85cb,7f6baf,675395,4f3b7b,382463,220b4d,000000,ffffff,fffbff,fbf2b7,ece4aa,cfc890,b3ad77,98925f,7d7747,656031,4c481c,353107,1f1c00,000000,ffffff,fffbff,ffeed9,ffdeaa,ebc078,cda55f,b08b48,937030,79591b,5e4102,422c00,271900,000000,ffffff,fffbff,feeedd,efe0cf,d3c4b4,b7a99a,9b8f80,807466,675d50,4f4539,382f24,221a10,000000,ffffff,fffbff,ffeedc,f5dfc6,d8c3ab,bba891,a08e77,84735e,6b5c48,524432,3b2e1d,241a0a,000000</expressive>
         <rainbow>ffffff,fffbff,ffeee2,ffdcc1,ffb778,ee9743,ce7d2b,ae640f,8e4e00,6c3a00,4c2700,2e1500,000000,ffffff,fffbff,ffeee2,ffdcc1,e2c0a5,c6a58b,a98b72,8d7159,735943,5a422d,412c19,2a1706,000000,ffffff,fcffde,edf6bf,dfe7b2,c3cb98,a8b07e,8d9566,727a4d,5b6238,434a22,2d330e,181e00,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
         <fruit_salad>ffffff,fffbff,ffeced,ffd9dd,ffb2bb,f98a9b,d97181,b95767,9b4051,7d293a,5f1125,400012,000000,ffffff,fffbff,ffeced,ffd9dd,ffb2bb,e8949f,c97a85,aa606b,8e4954,72333d,561d28,3b0714,000000,ffffff,fffbff,ffeee2,ffdcc1,ffb778,e09d60,c28349,a36931,87521c,6b3b04,4c2700,2e1500,000000,ffffff,fffbff,ffeee2,f6decd,d9c2b2,bda797,a18d7e,857364,6c5b4e,534437,3c2e22,25190f,000000,ffffff,fffbff,ffeee2,ffdcc1,e2c0a5,c6a58b,a98b72,8d7159,735943,5a422d,412c19,2a1706,000000</fruit_salad>
@@ -35,7 +35,7 @@
     <theme color="ff6e7f10">
         <spritz>ffffff,fdfee4,f1f3d8,e3e4cb,c6c8b0,abad95,90937c,757862,5d604c,464835,2f3220,1a1d0d,000000,ffffff,fefdec,f2f2e1,e4e3d3,c7c7b7,acac9d,919283,767769,5e5f52,46483b,303126,1b1c12,000000,ffffff,fcffdd,f0f4d0,e2e5c2,c5c9a8,aaae8e,8f9375,74795b,5d6145,45492f,2e321b,1a1d08,000000,ffffff,fcffdd,f4f0ec,e5e2de,c9c6c2,adaba7,92908d,777672,5f5e5b,474744,31302e,1c1c19,000000,ffffff,fcffdd,f4f0ec,e5e2de,c9c6c2,adaba7,92908d,777672,5f5e5b,474744,31302e,1c1c19,000000</spritz>
         <tonal_spot>ffffff,fcffdd,eaf8a4,dcea97,c0ce7e,a5b265,8a974e,707c36,586420,414b08,2c3400,181e00,000000,ffffff,fcffdd,f0f4d0,e2e5c2,c5c9a8,aaae8e,8f9375,74795b,5d6145,45492f,2e321b,1a1d08,000000,ffffff,f3fffa,cbfbed,bdecdf,a2d0c3,87b4a8,6d998e,527e74,3a665c,224e45,05372f,00201a,000000,ffffff,fffcf4,f3f1e8,e5e2da,c8c7bf,adaba4,92918a,77766f,5f5f58,474741,31312b,1b1c17,000000,ffffff,fefdec,f2f2e1,e4e3d3,c7c7b7,acac9d,919283,767769,5e5f52,46483b,303126,1b1c12,000000</tonal_spot>
-        <vibrant>ffffff,fcffdd,e9f99b,d0f100,b7d300,9db600,859a00,6c7e00,566500,404c00,2c3400,181e00,000000,ffffff,f9ffe9,e4f8c7,d6e9ba,bacd9f,9fb286,85976d,6a7c54,53643e,3c4c28,263514,111f03,000000,ffffff,f6ffef,d0fdc6,c2eeb9,a7d29e,8cb685,729b6c,588053,41673d,2a4f28,133813,002203,000000,ffffff,fefdec,f2f2e1,e4e3d3,c7c7b7,acac9d,919283,767769,5e5f52,46483b,303126,1b1c12,000000,ffffff,fdfee4,f1f3d8,e3e4cb,c6c8b0,abad95,90937c,757862,5d604c,464835,2f3220,1a1d0d,000000</vibrant>
+        <vibrant>ffffff,fcffdd,e9f99b,d0f100,b7d300,9db600,859a00,6c7e00,566500,404c00,2c3400,181e00,000000,ffffff,f9ffe9,e4f8c7,d6e9ba,bacd9f,9fb286,85976d,6a7c54,53643e,3c4c28,263514,111f03,000000,ffffff,f6ffef,d0fdc6,c2eeb9,a7d29e,8cb685,729b6c,588053,41673d,2a4f28,133813,002203,000000,ffffff,fdfee8,f2f2dd,e3e4cf,c7c8b3,abad99,91927f,767766,5e604f,464838,2f3223,1b1d10,000000,ffffff,fdfee4,f1f3d8,e3e4cb,c6c8b0,abad95,90937c,757862,5d604c,464835,2f3220,1a1d0d,000000</vibrant>
         <expressive>ffffff,fffbff,ffecf0,ffd9e2,ffb1c8,e991ad,cb7893,ac5e78,904760,733049,581932,3c031d,000000,ffffff,f4fff6,d0fbe1,c2ecd4,a6d0b8,8bb49e,719984,577e6a,406653,284e3c,0f3726,002114,000000,ffffff,f7ffed,d5fcc1,c7eeb3,acd199,91b580,779a67,5d7f4f,466739,2f4e23,19370f,042100,000000,ffffff,fafeef,eff2e4,e0e4d6,c4c8ba,a9ada0,8e9286,73786c,5b6055,44483e,2d3228,191d14,000000,ffffff,f8ffeb,ebf4dd,dde6d0,c1cab4,a6ae9a,8b9480,717966,596150,414939,2b3324,171e10,000000</expressive>
         <rainbow>ffffff,fcffdd,e9f99b,d9ec7b,bdd062,a2b44a,879932,6d7d17,566500,404c00,2c3400,181e00,000000,ffffff,fcffdd,f0f4d0,e2e5c2,c5c9a8,aaae8e,8f9375,74795b,5d6145,45492f,2e321b,1a1d08,000000,ffffff,f3fffa,cbfbed,bdecdf,a2d0c3,87b4a8,6d998e,527e74,3a665c,224e45,05372f,00201a,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
         <fruit_salad>ffffff,fffbff,ffeede,ffddb8,ffb960,e59c37,c7821d,a66800,865300,653e00,472a00,2b1700,000000,ffffff,fffbff,ffeede,ffddb8,f8bb71,daa059,bc8642,9e6c2a,825513,653e00,472a00,2b1700,000000,ffffff,fcffdd,eaf8a4,dcea97,c0ce7e,a5b265,8a974e,707c36,586420,414b08,2c3400,181e00,000000,ffffff,fdfee8,f2f2dd,e3e4cf,c7c8b3,abad99,91927f,767766,5e604f,464838,2f3223,1b1d10,000000,ffffff,fcffdd,f0f4d0,e2e5c2,c5c9a8,aaae8e,8f9375,74795b,5d6145,45492f,2e321b,1a1d08,000000</fruit_salad>
@@ -43,7 +43,7 @@
     <theme color="ff008673">
         <spritz>ffffff,f3fffa,e2f5ee,d4e7e0,b8cbc4,9dafa9,83958f,687a74,51625d,3a4a46,23342f,0e1e1b,000000,ffffff,f4fffa,e9f3ef,dbe5e0,bec9c5,a3ada9,89938f,6e7875,57605d,3f4946,293230,141d1b,000000,ffffff,f3fffa,dbf7ee,cde8e0,b1ccc4,96b1a9,7c968f,627b74,4a635d,334b45,1d352f,06201b,000000,ffffff,fdfcfa,f2f0ef,e3e2e1,c7c6c5,ababaa,91918f,767675,5e5e5d,464746,2f3130,1b1c1b,000000,ffffff,fdfcfa,f2f0ef,e3e2e1,c7c6c5,ababaa,91918f,767675,5e5e5d,464746,2f3130,1b1c1b,000000</spritz>
         <tonal_spot>ffffff,f3fffa,b6ffed,a0f2de,84d6c2,69baa7,4d9f8d,2e8373,056b5b,005144,00382f,00201a,000000,ffffff,f3fffa,dbf7ee,cde8e0,b1ccc4,96b1a9,7c968f,627b74,4a635d,334b45,1d352f,06201b,000000,ffffff,fcfcff,e5f2ff,c8e6ff,abcae4,90afc8,7594ac,5b7a91,436278,2b4a5f,113348,001e2f,000000,ffffff,fafdfa,eff1ef,e0e3e1,c4c7c5,a9acaa,8e918f,737775,5c5f5d,444746,2e3130,191c1b,000000,ffffff,f4fffa,e9f3ef,dbe5e0,bec9c5,a3ada9,89938f,6e7875,57605d,3f4946,293230,141d1b,000000</tonal_spot>
-        <vibrant>ffffff,f3fffa,b6ffed,00fedc,00dfc1,00c1a6,00a38c,008572,006b5b,005144,00382f,00201a,000000,ffffff,f1fffe,c9faf8,bbecea,a0cfce,85b4b2,6b9998,507e7d,386665,1e4e4d,003736,00201f,000000,ffffff,f6feff,d1f8ff,a9eefa,8dd1dd,72b6c1,579ba6,3a808b,1b6772,004f58,00363d,001f24,000000,ffffff,f4fffa,e9f3ef,dbe5e0,bec9c5,a3ada9,89938f,6e7875,57605d,3f4946,293230,141d1b,000000,ffffff,f3fffa,e2f5ee,d4e7e0,b8cbc4,9dafa9,83958f,687a74,51625d,3a4a46,23342f,0e1e1b,000000</vibrant>
+        <vibrant>ffffff,f3fffa,b6ffed,00fedc,00dfc1,00c1a6,00a38c,008572,006b5b,005144,00382f,00201a,000000,ffffff,f1fffe,c9faf8,bbecea,a0cfce,85b4b2,6b9998,507e7d,386665,1e4e4d,003736,00201f,000000,ffffff,f6feff,d1f8ff,a9eefa,8dd1dd,72b6c1,579ba6,3a808b,1b6772,004f58,00363d,001f24,000000,ffffff,f3fffa,e6f4ee,d7e6e0,bbcac4,a0aea9,86948f,6b7975,54615d,3c4946,26332f,111e1b,000000,ffffff,f3fffa,e2f5ee,d4e7e0,b8cbc4,9dafa9,83958f,687a74,51625d,3a4a46,23342f,0e1e1b,000000</vibrant>
         <expressive>ffffff,fffbff,ffeee2,ffdcc1,ffb779,e59b57,c68140,a76728,8b5011,6c3a00,4c2700,2e1500,000000,ffffff,fafdff,def4ff,c0e9fb,a5cdde,8ab1c2,7096a7,557b8b,3d6473,244c5a,063543,001f29,000000,ffffff,f1ffff,bbfcff,a8eff2,8cd2d5,70b7ba,559c9f,388183,19686b,004f52,003739,002021,000000,ffffff,f4fefd,e8f3f2,dae5e3,bec9c8,a3adac,889392,6e7877,566060,3f4948,293232,141d1d,000000,ffffff,f1fffe,e2f5f3,d3e6e5,b8cac9,9dafae,829493,687979,506261,394a49,233333,0e1e1e,000000</expressive>
         <rainbow>ffffff,f3fffa,b6ffed,78f8dd,59dbc1,35bfa6,00a38c,008572,006b5b,005144,00382f,00201a,000000,ffffff,f3fffa,dbf7ee,cde8e0,b1ccc4,96b1a9,7c968f,627b74,4a635d,334b45,1d352f,06201b,000000,ffffff,fcfcff,e5f2ff,c8e6ff,abcae4,90afc8,7594ac,5b7a91,436278,2b4a5f,113348,001e2f,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
         <fruit_salad>ffffff,f9ffe7,dafca7,c6f08a,abd471,90b759,779c41,5d8128,466810,324f00,213600,111f00,000000,ffffff,f9ffe7,ddfbaf,cfeda2,b3d088,98b56f,7e9a57,647e3f,4d662a,364e14,213600,111f00,000000,ffffff,f3fffa,b6ffed,a0f2de,84d6c2,69baa7,4d9f8d,2e8373,056b5b,005144,00382f,00201a,000000,ffffff,f3fffa,e6f4ee,d7e6e0,bbcac4,a0aea9,86948f,6b7975,54615d,3c4946,26332f,111e1b,000000,ffffff,f3fffa,dbf7ee,cde8e0,b1ccc4,96b1a9,7c968f,627b74,4a635d,334b45,1d352f,06201b,000000</fruit_salad>
@@ -51,7 +51,7 @@
     <theme color="ff007fb4">
         <spritz>ffffff,fbfcff,e6f2fe,d8e4ef,bcc8d3,a1adb7,86929d,6c7781,546069,3d4851,26323a,121d25,000000,ffffff,fbfcff,ebf1f8,dde3ea,c1c7ce,a6acb2,8b9198,70777d,595f65,41484d,2b3136,161c21,000000,ffffff,fbfcff,e5f2ff,d2e5f5,b7c9d8,9cadbd,8193a2,677886,4f606e,384956,21323f,0b1d29,000000,ffffff,fefcfc,f2f0f1,e4e2e3,c7c6c7,acabac,919091,767677,5e5e5f,464748,303031,1b1c1c,000000,ffffff,fefcfc,f2f0f1,e4e2e3,c7c6c7,acabac,919091,767677,5e5e5f,464748,303031,1b1c1c,000000</spritz>
         <tonal_spot>ffffff,fbfcff,e5f2ff,c8e6ff,94cdf6,78b2da,5d97be,407ca1,246488,004c6d,00344d,001e2e,000000,ffffff,fbfcff,e5f2ff,d2e5f5,b7c9d8,9cadbd,8193a2,677886,4f606e,384956,21323f,0b1d29,000000,ffffff,fffbff,f6edff,e9ddff,cdc0e8,b2a5cc,978bb1,7c7095,63597c,4b4163,342b4b,1f1635,000000,ffffff,fcfcff,f0f0f3,e2e2e5,c5c6c9,aaabae,8f9193,747679,5d5e61,454749,2e3133,191c1e,000000,ffffff,fbfcff,ebf1f8,dde3ea,c1c7ce,a6acb2,8b9198,70777d,595f65,41484d,2b3136,161c21,000000</tonal_spot>
-        <vibrant>ffffff,fbfcff,e5f2ff,c8e6ff,87ceff,0eb6ff,009ad9,007eb2,006590,004c6d,00344d,001e2e,000000,ffffff,fdfcff,ebf1ff,d4e3ff,b3c8e9,98accc,7e92b1,637795,4c5f7c,344863,1d314b,051c35,000000,ffffff,fefbff,efefff,dce1ff,b8c4fa,9da9dd,838ec1,6874a4,505c8b,384472,212e5a,0a1844,000000,ffffff,fbfcff,ebf1f8,dde3ea,c1c7ce,a6acb2,8b9198,70777d,595f65,41484d,2b3136,161c21,000000,ffffff,fbfcff,e6f2fe,d8e4ef,bcc8d3,a1adb7,86929d,6c7781,546069,3d4851,26323a,121d25,000000</vibrant>
+        <vibrant>ffffff,fbfcff,e5f2ff,c8e6ff,87ceff,0eb6ff,009ad9,007eb2,006590,004c6d,00344d,001e2e,000000,ffffff,fdfcff,ebf1ff,d4e3ff,b3c8e9,98accc,7e92b1,637795,4c5f7c,344863,1d314b,051c35,000000,ffffff,fefbff,efefff,dce1ff,b8c4fa,9da9dd,838ec1,6874a4,505c8b,384472,212e5a,0a1844,000000,ffffff,fbfcff,e9f2fb,dbe4ed,bfc8d0,a3acb5,89929a,6e777f,575f67,3f484f,293138,141d23,000000,ffffff,fbfcff,e6f2fe,d8e4ef,bcc8d3,a1adb7,86929d,6c7781,546069,3d4851,26323a,121d25,000000</vibrant>
         <expressive>ffffff,fcffdd,e9f99a,dbeb8e,bfce75,a4b35c,8a9845,6f7c2d,586416,414c00,2c3400,191e00,000000,ffffff,fffbff,ffebfa,fed7f9,e0bbdd,c4a0c1,a886a6,8c6c8a,735572,593d59,412742,2a122c,000000,ffffff,fdfcff,eaf1ff,d2e4ff,a7c9f6,8caed9,7293bd,5778a1,3f6088,25496f,073257,001c37,000000,ffffff,fdfcff,edf1fa,dfe2eb,c3c6cf,a7abb4,8d9199,72767e,5a5f66,43474e,2c3137,171c22,000000,ffffff,fdfcff,eaf1ff,dbe3f1,bfc7d5,a4acb9,89919e,6f7783,575f6b,3f4753,29313c,141c26,000000</expressive>
         <rainbow>ffffff,fbfcff,e5f2ff,c8e6ff,87ceff,55b4ed,3399d1,007eb2,006590,004c6d,00344d,001e2e,000000,ffffff,fbfcff,e5f2ff,d2e5f5,b7c9d8,9cadbd,8193a2,677886,4f606e,384956,21323f,0b1d29,000000,ffffff,fffbff,f6edff,e9ddff,cdc0e8,b2a5cc,978bb1,7c7095,63597c,4b4163,342b4b,1f1635,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
         <fruit_salad>ffffff,f2fffc,b1fff7,71f7ec,50dbd0,25beb5,00a299,00847d,006a64,00504b,003734,00201e,000000,ffffff,f2fffc,b1fff7,9df2e9,81d5cd,65b9b2,489e97,28837c,006a64,00504b,003734,00201e,000000,ffffff,fbfcff,e5f2ff,c8e6ff,94cdf6,78b2da,5d97be,407ca1,246488,004c6d,00344d,001e2e,000000,ffffff,fbfcff,e9f2fb,dbe4ed,bfc8d0,a3acb5,89929a,6e777f,575f67,3f484f,293138,141d23,000000,ffffff,fbfcff,e5f2ff,d2e5f5,b7c9d8,9cadbd,8193a2,677886,4f606e,384956,21323f,0b1d29,000000</fruit_salad>
@@ -59,7 +59,7 @@
     <theme color="ff8267c2">
         <spritz>ffffff,fffbff,f6edff,e8dff2,cbc3d5,afa8b9,958e9e,797383,615c6b,494453,332e3c,1d1a26,000000,ffffff,fffbff,f5eefa,e7e0eb,cac4cf,afa9b4,948f99,79747e,615d66,49454e,322f37,1d1a22,000000,ffffff,fffbff,f6edff,e8def8,ccc2db,b0a7bf,958da4,7a7289,625b70,4a4458,332d41,1e192b,000000,ffffff,fffbff,f4eff1,e6e1e3,c9c5c7,aeaaac,939092,787577,605e5f,484648,313031,1c1b1d,000000,ffffff,fffbff,f4eff1,e6e1e3,c9c5c7,aeaaac,939092,787577,605e5f,484648,313031,1c1b1d,000000</spritz>
         <tonal_spot>ffffff,fffbff,f6edff,e9ddff,d0bcfe,b5a1e1,9987c4,7e6ca8,66558e,4e3d75,37265d,210f47,000000,ffffff,fffbff,f6edff,e8def8,ccc2db,b0a7bf,958da4,7a7289,625b70,4a4458,332d41,1e192b,000000,ffffff,fffbff,ffecef,ffd9e2,f0b8c7,d29dac,b58391,986977,7e525f,633b47,4a2531,31101c,000000,ffffff,fffbff,f5eff4,e6e1e6,cac5ca,aeaaae,938f94,787579,605d61,48464a,323033,1c1b1e,000000,ffffff,fffbff,f5eefa,e7e0eb,cac4cf,afa9b4,948f99,79747e,615d66,49454e,322f37,1d1a22,000000</tonal_spot>
-        <vibrant>ffffff,fffbff,f6edff,e9ddff,d1bcff,b89bff,a078ff,884fff,7212ff,5700c9,3c0090,23005b,000000,ffffff,fffbff,fbecff,f4daff,d7bde4,bba2c8,a088ac,846e90,6c5778,533f5f,3b2947,251431,000000,ffffff,fffbff,ffebfa,ffd6fa,e9b6e6,cc9cc9,b082ae,936792,7a5079,603960,472348,2f0d32,000000,ffffff,fffbff,f5eefa,e7e0eb,cac4cf,afa9b4,948f99,79747e,615d66,49454e,322f37,1d1a22,000000,ffffff,fffbff,f6edff,e8dff2,cbc3d5,afa8b9,958e9e,797383,615c6b,494453,332e3c,1d1a26,000000</vibrant>
+        <vibrant>ffffff,fffbff,f6edff,e9ddff,d1bcff,b89bff,a078ff,884fff,7212ff,5700c9,3c0090,23005b,000000,ffffff,fffbff,fbecff,f4daff,d7bde4,bba2c8,a088ac,846e90,6c5778,533f5f,3b2947,251431,000000,ffffff,fffbff,ffebfa,ffd6fa,e9b6e6,cc9cc9,b082ae,936792,7a5079,603960,472348,2f0d32,000000,ffffff,fffbff,f6eefd,e7e0ee,cbc4d2,afa9b7,948e9c,797481,615c69,494551,322f3a,1d1a24,000000,ffffff,fffbff,f6edff,e8dff2,cbc3d5,afa8b9,958e9e,797383,615c6b,494453,332e3c,1d1a26,000000</vibrant>
         <expressive>ffffff,f3fffa,b7ffed,94f4de,78d7c2,5bbba7,3da08d,168572,006b5b,005144,00382f,00201a,000000,ffffff,fffbff,ffecf4,ffd8ec,e9b9d3,cc9eb7,b0849c,936a81,795369,5f3c51,46263a,2f1124,000000,ffffff,fffbff,feebff,f8d8ff,e1b9ed,c49ed0,a984b5,8c6998,73527f,5a3b66,42244e,2b0e38,000000,ffffff,fffbff,f8edf8,eadfea,cdc3ce,b2a8b2,978e98,7b737d,635c65,4b454d,342e36,1f1a21,000000,ffffff,fffbff,fbecfe,ecdeef,d0c2d3,b4a7b7,998d9d,7d7281,655b69,4d4351,362d3a,201925,000000</expressive>
         <rainbow>ffffff,fffbff,f6edff,e9ddff,d1bcff,b79cf7,9c82da,8167bd,684fa3,50378a,391e72,23005b,000000,ffffff,fffbff,f6edff,e8def8,ccc2db,b0a7bf,958da4,7a7289,625b70,4a4458,332d41,1e192b,000000,ffffff,fffbff,ffecef,ffd9e2,f0b8c7,d29dac,b58391,986977,7e525f,633b47,4a2531,31101c,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
         <fruit_salad>ffffff,fcfcff,e8f1ff,cfe5ff,99cbff,68b1f4,4a96d8,277bbb,00629e,004a78,003355,001d34,000000,ffffff,fcfcff,e8f1ff,cfe5ff,9dcbfb,82afdf,6794c2,4b7aa6,31628d,124a73,003355,001d34,000000,ffffff,fffbff,f6edff,e9ddff,d0bcfe,b5a1e1,9987c4,7e6ca8,66558e,4e3d75,37265d,210f47,000000,ffffff,fffbff,f6eefd,e7e0ee,cbc4d2,afa9b7,948e9c,797481,615c69,494551,322f3a,1d1a24,000000,ffffff,fffbff,f6edff,e8def8,ccc2db,b0a7bf,958da4,7a7289,625b70,4a4458,332d41,1e192b,000000</fruit_salad>
diff --git a/tests/tests/graphics/src/android/graphics/cts/AnimatorLeakTest.java b/tests/tests/graphics/src/android/graphics/cts/AnimatorLeakTest.java
new file mode 100644
index 0000000..b21edd5
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/AnimatorLeakTest.java
@@ -0,0 +1,255 @@
+/*
+ * 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.graphics.cts;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.support.test.uiautomator.UiDevice;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AnimatorLeakTest {
+
+    @Rule
+    public  ActivityTestRule<EmptyActivity> mActivityRule =
+            new ActivityTestRule<>(EmptyActivity.class, false, true);
+    public  ActivityTestRule<EmptyActivity2> mActivityRule2 =
+            new ActivityTestRule<>(EmptyActivity2.class, false, false);
+
+    boolean mPaused = false;
+    boolean mPausedSet = false;
+    boolean mFinitePaused = false;
+    boolean mFinitePausedSet = false;
+    boolean mResumed = false;
+
+    @After
+    public void cleanup() {
+        Animator.setAnimatorPausingEnabled(true);
+    }
+
+    /**
+     * The approach of this test is to start animators in the main activity for the test.
+     * That activity is forced into the background and the test checks whether the animators
+     * are paused appropriately. The activity is then forced back into the foreground again
+     * and the test checks whether the animators previously paused are resumed. There are also
+     * checks to make sure that animators which should not have been paused are handled
+     * correctly.
+     */
+    @Test
+    public void testPauseResume() {
+        // Latches used to wait for each of the appropriate lifecycle events
+        final CountDownLatch animatorStartedLatch = new CountDownLatch(1);
+        // There are 2 animators which should be paused and resumed, thus a countdown of 2
+        final CountDownLatch animatorPausedLatch = new CountDownLatch(2);
+        final CountDownLatch animatorResumedLatch = new CountDownLatch(2);
+
+        // The first of these (infinite) should get paused, the second (finite) should not
+        ValueAnimator infiniteAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(1000);
+        infiniteAnimator.setRepeatCount(ValueAnimator.INFINITE);
+        ValueAnimator finiteAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(5000);
+
+        // Now create infinite and finite AnimatorSets
+        // As above, the infinite set should get paused, the finite one should not
+        ValueAnimator infiniteAnimator1 = ValueAnimator.ofFloat(0f, 1f).setDuration(1000);
+        infiniteAnimator1.setRepeatCount(ValueAnimator.INFINITE);
+        AnimatorSet infiniteSet = new AnimatorSet();
+        infiniteSet.play(infiniteAnimator1);
+        ValueAnimator finiteAnimator1 = ValueAnimator.ofFloat(0f, 1f).setDuration(5000);
+        AnimatorSet finiteSet = new AnimatorSet();
+        finiteSet.play(finiteAnimator1);
+
+        // This listener tracks which animators get paused and resumed
+        AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                // Wait until animators start to trigger the lifecycle changes
+                animatorStartedLatch.countDown();
+            }
+
+            @Override
+            public void onAnimationPause(Animator animation) {
+                if (animation == infiniteAnimator) {
+                    mPaused = true;
+                } else if (animation == infiniteSet) {
+                    mPausedSet = true;
+                } else if (animation == finiteAnimator) {
+                    mFinitePaused = true;
+                    // end it to avoid having it interfere with future resume latch
+                    animation.end();
+                    return;
+                } else if (animation == finiteSet) {
+                    mFinitePausedSet = true;
+                    // end it to avoid having it interfere with future resume latch
+                    animation.end();
+                    return;
+                }
+                animatorPausedLatch.countDown();
+            }
+
+            @Override
+            public void onAnimationResume(Animator animation) {
+                mResumed = true;
+                animatorResumedLatch.countDown();
+            }
+        };
+        infiniteAnimator.addListener(listener);
+        infiniteAnimator.addPauseListener(listener);
+        finiteAnimator.addPauseListener(listener);
+        infiniteSet.addPauseListener(listener);
+        finiteSet.addPauseListener(listener);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            public void run() {
+                Animator.setBackgroundPauseDelay(500);
+                try {
+                    infiniteAnimator.start();
+                    finiteAnimator.start();
+                    infiniteSet.start();
+                    finiteSet.start();
+                } catch (Throwable throwable) {
+                }
+            }
+        });
+        try {
+            // Wait until the animators are running to start changing the activity lifecycle
+            animatorStartedLatch.await(5, TimeUnit.SECONDS);
+
+            // First, test that animators are *not* paused when an activity goes to the background
+            // if there is another activity in the same process which is now in the foreground.
+            mActivityRule2.launchActivity(null);
+            animatorPausedLatch.await(1, TimeUnit.SECONDS);
+            Assert.assertFalse("Animator was paused", mPaused);
+            mActivityRule2.finishActivity();
+
+            // Send the activity to the background. This should cause the animators to be paused
+            // after Animator.getBackgroundPauseDelay()
+            UiDevice uiDevice = UiDevice.getInstance(getInstrumentation());
+            uiDevice.pressHome();
+
+            animatorPausedLatch.await(5, TimeUnit.SECONDS);
+
+            // It is not possible (or obvious) how to bring the activity back into the foreground.
+            // However, AnimationHandler pauses/resumes all animators for the process based on
+            // *any* visible activities in that process. So it is sufficient to launch a second
+            // activity, which should resume the animators paused when the first activity went
+            // into the background.
+            mActivityRule2.launchActivity(null);
+            animatorResumedLatch.await(5, TimeUnit.SECONDS);
+        } catch (Exception e) { }
+        Assert.assertTrue("Animator was not paused", mPaused);
+        Assert.assertTrue("AnimatorSet was not paused", mPausedSet);
+        Assert.assertFalse("Non-infinite Animator was paused", mFinitePaused);
+        Assert.assertFalse("Non-infinite AnimatorSet was paused", mFinitePausedSet);
+        Assert.assertTrue("Animator was not resumed", mResumed);
+        Assert.assertTrue("AnimatorSet was not resumed", mResumed);
+    }
+
+    /**
+     * The approach of this test is to start animators in the main activity for the test.
+     * That activity is forced into the background and the test checks whether the animators
+     * are paused appropriately. The activity is then forced back into the foreground again
+     * and the test checks whether the animators previously paused are resumed. There are also
+     * checks to make sure that animators which should not have been paused are handled
+     * correctly.
+     */
+    @Test
+    public void testPauseDisablement() {
+        // Latches used to wait for each of the appropriate lifecycle events
+        final CountDownLatch animatorStartedLatch = new CountDownLatch(1);
+        // There are 2 animators which should be paused and resumed, thus a countdown of 2
+        final CountDownLatch animatorPausedLatch = new CountDownLatch(1);
+        final CountDownLatch animatorResumedLatch = new CountDownLatch(1);
+
+        // The first of these (infinite) should get paused, the second (finite) should not
+        ValueAnimator infiniteAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(1000);
+        infiniteAnimator.setRepeatCount(ValueAnimator.INFINITE);
+
+        // This listener tracks which animators get paused and resumed
+        AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                // Wait until animators start to trigger the lifecycle changes
+                animatorStartedLatch.countDown();
+            }
+
+            @Override
+            public void onAnimationPause(Animator animation) {
+                mPaused = true;
+                animatorPausedLatch.countDown();
+            }
+
+            @Override
+            public void onAnimationResume(Animator animation) {
+                mResumed = true;
+                animatorResumedLatch.countDown();
+            }
+        };
+        infiniteAnimator.addListener(listener);
+        infiniteAnimator.addPauseListener(listener);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            public void run() {
+                Animator.setBackgroundPauseDelay(500);
+                Animator.setAnimatorPausingEnabled(false);
+                try {
+                    infiniteAnimator.start();
+                } catch (Throwable throwable) {
+                }
+            }
+        });
+        try {
+            // Wait until the animators are running to start changing the activity lifecycle
+            animatorStartedLatch.await(5, TimeUnit.SECONDS);
+
+            // Send the activity to the background. This should cause the animators to be paused
+            // after Animator.getBackgroundPauseDelay()
+            UiDevice uiDevice = UiDevice.getInstance(getInstrumentation());
+            uiDevice.pressHome();
+
+            animatorPausedLatch.await(2, TimeUnit.SECONDS);
+
+            // It is not possible (or obvious) how to bring the activity back into the foreground.
+            // However, AnimationHandler pauses/resumes all animators for the process based on
+            // *any* visible activities in that process. So it is sufficient to launch a second
+            // activity, which should resume the animators paused when the first activity went
+            // into the background.
+            mActivityRule2.launchActivity(null);
+            animatorResumedLatch.await(2, TimeUnit.SECONDS);
+        } catch (Exception e) { }
+        Assert.assertFalse("Animator paused when pausing disabled", mPaused);
+        Assert.assertFalse("Animator resumed when pausing disabled", mResumed);
+    }
+
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
index 534f492..9600df2 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
@@ -24,6 +24,7 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 import static org.testng.Assert.assertThrows;
 
 import android.content.res.Resources;
@@ -35,6 +36,7 @@
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.media.MediaFormat;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.platform.test.annotations.LargeTest;
@@ -47,6 +49,7 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
+import com.android.compatibility.common.util.ApiLevelUtil;
 import com.android.compatibility.common.util.BitmapUtils;
 import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.MediaUtils;
@@ -1005,6 +1008,8 @@
     @Test
     @RequiresDevice
     public void testDecode10BitHEIFTo10BitBitmap() {
+        assumeTrue(
+            "Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
         if (!MediaUtils.hasDecoder(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
             return;
         }
@@ -1020,6 +1025,8 @@
     @Test
     @RequiresDevice
     public void testDecode10BitHEIFTo8BitBitmap() {
+        assumeTrue(
+            "Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
         if (!MediaUtils.hasDecoder(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
             return;
         }
diff --git a/tests/tests/graphics/src/android/graphics/cts/EmptyActivity.java b/tests/tests/graphics/src/android/graphics/cts/EmptyActivity.java
new file mode 100644
index 0000000..5ae6cd3
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/EmptyActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+/**
+ * Empty activity
+ */
+public final class EmptyActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Button b = new Button(this);
+        b.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
+        b.setText("My Button 1111");
+        setContentView(b);
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/EmptyActivity2.java b/tests/tests/graphics/src/android/graphics/cts/EmptyActivity2.java
new file mode 100644
index 0000000..da0b8a6
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/EmptyActivity2.java
@@ -0,0 +1,37 @@
+/*
+ * 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.graphics.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+/**
+ * Empty activity - this one exists in addition to EmptyActivity when an app
+ * needs two launch 2 separate activities.
+ */
+public final class EmptyActivity2 extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Button b = new Button(this);
+        b.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
+        b.setText("My Button 22222");
+        setContentView(b);
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 46239d8..5b179d6 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -23,6 +23,7 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -45,6 +46,7 @@
 import android.graphics.drawable.NinePatchDrawable;
 import android.media.MediaFormat;
 import android.net.Uri;
+import android.os.Build;
 import android.util.DisplayMetrics;
 import android.util.Size;
 import android.util.TypedValue;
@@ -54,6 +56,7 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.filters.RequiresDevice;
 
+import com.android.compatibility.common.util.ApiLevelUtil;
 import com.android.compatibility.common.util.BitmapUtils;
 import com.android.compatibility.common.util.MediaUtils;
 
@@ -239,6 +242,8 @@
     @Test
     @RequiresDevice
     public void testDecode10BitHeif() {
+        assumeTrue(
+            "Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
         if (!MediaUtils.hasDecoder(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
             return;
         }
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualDeviceTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualDeviceTestCase.java
index ba192c4..8ad13df 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualDeviceTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualDeviceTestCase.java
@@ -57,8 +57,8 @@
 
     private static final int ARBITRARY_SURFACE_TEX_ID = 1;
 
-    static final int DISPLAY_WIDTH = 100;
-    static final int DISPLAY_HEIGHT = 100;
+    protected static final int DISPLAY_WIDTH = 100;
+    protected static final int DISPLAY_HEIGHT = 100;
 
     // Uses:
     // Manifest.permission.CREATE_VIRTUAL_DEVICE,
@@ -140,10 +140,6 @@
         }
         // Tap to gain window focus on the activity
         tapActivityToFocus();
-        // Wait for everything to settle. Like see in InputHidTestCase, registered input devices
-        // don't always seem to produce events right away. Adding a bit of slack here decreases
-        // the flake rate.
-        SystemClock.sleep(1000L);
     }
 
     abstract void onSetUpVirtualInputDevice();
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualMouseTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualMouseTest.java
index eb54097..6ca80e5 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualMouseTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualMouseTest.java
@@ -40,11 +40,7 @@
 
     private static final String DEVICE_NAME = "CtsVirtualMouseTestDevice";
 
-    // TODO(b/216792538): while the start position is deterministic, it would be nice to test it at
-    // runtime. The virtual display is 100x100px, running from [0,99]. Half of this is 49.5, and
-    // we assume the pointer for a new display begins at the center.
-    private static final PointF START_POSITION = new PointF((DISPLAY_WIDTH - 1) / 2f,
-            (DISPLAY_HEIGHT - 1) / 2f);
+    private static final float EPSILON = 0.001f;
 
     private VirtualMouse mVirtualMouse;
 
@@ -63,6 +59,7 @@
 
     @Test
     public void sendButtonEvent() {
+        final PointF startPosition = mVirtualMouse.getCursorPosition();
         mVirtualMouse.sendButtonEvent(new VirtualMouseButtonEvent.Builder()
                 .setAction(VirtualMouseButtonEvent.ACTION_BUTTON_PRESS)
                 .setButtonCode(VirtualMouseButtonEvent.BUTTON_PRIMARY)
@@ -72,59 +69,78 @@
                 .setButtonCode(VirtualMouseButtonEvent.BUTTON_PRIMARY)
                 .build());
         final MotionEvent buttonPressEvent = createMotionEvent(MotionEvent.ACTION_BUTTON_PRESS,
-                START_POSITION.x, START_POSITION.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
+                startPosition.x, startPosition.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
                 /* vScroll= */ 0f, /* hScroll= */ 0f, MotionEvent.BUTTON_PRIMARY,
                 /* pressure= */ 1.0f);
         buttonPressEvent.setActionButton(MotionEvent.BUTTON_PRIMARY);
         final MotionEvent buttonReleaseEvent = createMotionEvent(MotionEvent.ACTION_BUTTON_RELEASE,
-                START_POSITION.x, START_POSITION.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
+                startPosition.x, startPosition.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
                 /* vScroll= */ 0f, /* hScroll= */ 0f, /* buttonState= */ 0, /* pressure= */ 0.0f);
         buttonReleaseEvent.setActionButton(MotionEvent.BUTTON_PRIMARY);
         verifyEvents(Arrays.asList(
-                createMotionEvent(MotionEvent.ACTION_DOWN, START_POSITION.x, START_POSITION.y,
+                createMotionEvent(MotionEvent.ACTION_DOWN, startPosition.x, startPosition.y,
                         /* relativeX= */ 0f, /* relativeY= */ 0f, /* vScroll= */ 0f,
                         /* hScroll= */ 0f, MotionEvent.BUTTON_PRIMARY, /* pressure= */ 1.0f),
                 buttonPressEvent,
                 buttonReleaseEvent,
-                createMotionEvent(MotionEvent.ACTION_UP, START_POSITION.x, START_POSITION.y,
+                createMotionEvent(MotionEvent.ACTION_UP, startPosition.x, startPosition.y,
                         /* relativeX= */ 0f, /* relativeY= */ 0f, /* vScroll= */ 0f,
                         /* hScroll= */ 0f, /* buttonState= */ 0, /* pressure= */ 0.0f),
-                createMotionEvent(MotionEvent.ACTION_HOVER_ENTER, START_POSITION.x,
-                        START_POSITION.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
+                createMotionEvent(MotionEvent.ACTION_HOVER_ENTER, startPosition.x,
+                        startPosition.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
                         /* vScroll= */ 0f, /* hScroll= */ 0f, /* buttonState= */ 0,
                         /* pressure= */ 0.0f)));
     }
 
     @Test
     public void sendRelativeEvent() {
+        final PointF startPosition = mVirtualMouse.getCursorPosition();
         final float relativeChangeX = 25f;
         final float relativeChangeY = 35f;
         mVirtualMouse.sendRelativeEvent(new VirtualMouseRelativeEvent.Builder()
                 .setRelativeY(relativeChangeY)
                 .setRelativeX(relativeChangeX)
                 .build());
-        mVirtualMouse.sendRelativeEvent(new VirtualMouseRelativeEvent.Builder()
-                .setRelativeY(-relativeChangeY)
-                .setRelativeX(-relativeChangeX)
-                .build());
-        final float firstStopPositionX = START_POSITION.x + relativeChangeX;
-        final float firstStopPositionY = START_POSITION.y + relativeChangeY;
-        final float secondStopPositionX = firstStopPositionX - relativeChangeX;
-        final float secondStopPositionY = firstStopPositionY - relativeChangeY;
+        final float firstStopPositionX = startPosition.x + relativeChangeX;
+        final float firstStopPositionY = startPosition.y + relativeChangeY;
         verifyEvents(Arrays.asList(
                 createMotionEvent(MotionEvent.ACTION_HOVER_ENTER, firstStopPositionX,
                         firstStopPositionY, relativeChangeX, relativeChangeY, /* vScroll= */ 0f,
                         /* hScroll= */ 0f, /* buttonState= */ 0, /* pressure= */ 0.0f),
                 createMotionEvent(MotionEvent.ACTION_HOVER_MOVE, firstStopPositionX,
                         firstStopPositionY, relativeChangeX, relativeChangeY, /* vScroll= */ 0f,
+                        /* hScroll= */ 0f, /* buttonState= */ 0, /* pressure= */ 0.0f)));
+        final PointF cursorPosition1 = mVirtualMouse.getCursorPosition();
+        assertEquals("getCursorPosition() should return the updated x position",
+                firstStopPositionX, cursorPosition1.x, EPSILON);
+        assertEquals("getCursorPosition() should return the updated y position",
+                firstStopPositionY, cursorPosition1.y, EPSILON);
+
+        final float secondStopPositionX = firstStopPositionX - relativeChangeX;
+        final float secondStopPositionY = firstStopPositionY - relativeChangeY;
+        mVirtualMouse.sendRelativeEvent(new VirtualMouseRelativeEvent.Builder()
+                .setRelativeY(-relativeChangeY)
+                .setRelativeX(-relativeChangeX)
+                .build());
+        verifyEvents(Arrays.asList(
+                createMotionEvent(MotionEvent.ACTION_HOVER_ENTER, secondStopPositionX,
+                        secondStopPositionY, -relativeChangeX,
+                        -relativeChangeY, /* vScroll= */ 0f,
                         /* hScroll= */ 0f, /* buttonState= */ 0, /* pressure= */ 0.0f),
                 createMotionEvent(MotionEvent.ACTION_HOVER_MOVE, secondStopPositionX,
-                        secondStopPositionY, -relativeChangeX, -relativeChangeY, /* vScroll= */ 0f,
+                        secondStopPositionY, -relativeChangeX,
+                        -relativeChangeY, /* vScroll= */ 0f,
                         /* hScroll= */ 0f, /* buttonState= */ 0, /* pressure= */ 0.0f)));
+        final PointF cursorPosition2 = mVirtualMouse.getCursorPosition();
+        assertEquals("getCursorPosition() should return the updated x position",
+                secondStopPositionX, cursorPosition2.x, EPSILON);
+        assertEquals("getCursorPosition() should return the updated y position",
+                secondStopPositionY, cursorPosition2.y, EPSILON);
     }
 
     @Test
     public void sendScrollEvent() {
+        final PointF startPosition = mVirtualMouse.getCursorPosition();
         final float moveX = 0f;
         final float moveY = 1f;
         mVirtualMouse.sendScrollEvent(new VirtualMouseScrollEvent.Builder()
@@ -132,42 +148,46 @@
                 .setXAxisMovement(moveX)
                 .build());
         verifyEvents(Arrays.asList(
-                createMotionEvent(MotionEvent.ACTION_HOVER_ENTER, START_POSITION.x,
-                        START_POSITION.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
+                createMotionEvent(MotionEvent.ACTION_HOVER_ENTER, startPosition.x,
+                        startPosition.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
                         /* vScroll= */ 0f, /* hScroll= */ 0f, /* buttonState= */ 0,
                         /* pressure= */ 0f),
-                createMotionEvent(MotionEvent.ACTION_HOVER_MOVE, START_POSITION.x,
-                        START_POSITION.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
+                createMotionEvent(MotionEvent.ACTION_HOVER_MOVE, startPosition.x,
+                        startPosition.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
                         /* vScroll= */ 0f, /* hScroll= */ 0f, /* buttonState= */ 0,
                         /* pressure= */ 0f),
-                createMotionEvent(MotionEvent.ACTION_SCROLL, START_POSITION.x,
-                        START_POSITION.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
+                createMotionEvent(MotionEvent.ACTION_SCROLL, startPosition.x,
+                        startPosition.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
                         /* vScroll= */ 1f, /* hScroll= */ 0f, /* buttonState= */ 0,
                         /* pressure= */ 0f)));
     }
 
     @Test
-    public void getCursorPosition() {
+    public void testStartingCursorPosition() {
+        // The virtual display is 100x100px, running from [0,99]. Half of this is 49.5, and
+        // we assume the pointer for a new display begins at the center.
+        final PointF startPosition = new PointF((DISPLAY_WIDTH - 1) / 2f,
+                (DISPLAY_HEIGHT - 1) / 2f);
         // Trigger a position update without moving the cursor off the starting position.
         mVirtualMouse.sendButtonEvent(new VirtualMouseButtonEvent.Builder()
                 .setAction(VirtualMouseButtonEvent.ACTION_BUTTON_PRESS)
                 .setButtonCode(VirtualMouseButtonEvent.BUTTON_PRIMARY)
                 .build());
         final MotionEvent buttonPressEvent = createMotionEvent(MotionEvent.ACTION_BUTTON_PRESS,
-                START_POSITION.x, START_POSITION.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
+                startPosition.x, startPosition.y, /* relativeX= */ 0f, /* relativeY= */ 0f,
                 /* vScroll= */ 0f, /* hScroll= */ 0f, MotionEvent.BUTTON_PRIMARY,
                 /* pressure= */ 1.0f);
         buttonPressEvent.setActionButton(MotionEvent.BUTTON_PRIMARY);
         verifyEvents(Arrays.asList(
-                createMotionEvent(MotionEvent.ACTION_DOWN, START_POSITION.x, START_POSITION.y,
+                createMotionEvent(MotionEvent.ACTION_DOWN, startPosition.x, startPosition.y,
                         /* relativeX= */ 0f, /* relativeY= */ 0f, /* vScroll= */ 0f,
                         /* hScroll= */ 0f, MotionEvent.BUTTON_PRIMARY, /* pressure= */ 1.0f),
                 buttonPressEvent));
 
         final PointF position = mVirtualMouse.getCursorPosition();
 
-        assertEquals("Cursor position x differs", START_POSITION.x, position.x, 0.0001f);
-        assertEquals("Cursor position y differs", START_POSITION.y, position.y, 0.0001f);
+        assertEquals("Cursor position x differs", startPosition.x, position.x, EPSILON);
+        assertEquals("Cursor position y differs", startPosition.y, position.y, EPSILON);
     }
 
     private MotionEvent createMotionEvent(int action, float x, float y, float relativeX,
diff --git a/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java
index be2ecc5..6057e45 100644
--- a/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java
+++ b/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java
@@ -842,19 +842,19 @@
             int ciphertextIndex = 0;
             for (int plaintextIndex = 0; plaintextIndex < plaintext.length; plaintextIndex++) {
                 byte[] output = update(new byte[] {plaintext[plaintextIndex]});
-                if ((plaintextIndex % blockSize) == blockSize - 1) {
-                    String additionalInformation = "";
-                    boolean compareOutput = true;
-                    if (isStrongbox() && output == null) {
-                        // This is known to be broken on older vendor implementations.
-                        if (Build.VERSION_CODES.TIRAMISU
-                                > SystemProperties.getInt("ro.vendor.api_level", 0)) {
-                            compareOutput = false;
-                        } else {
-                            additionalInformation = " (b/194134359)";
-                        }
+                String additionalInformation = "";
+                boolean compareOutput = true;
+                if (isStrongbox()) {
+                    // This is known to be broken on older vendor implementations.
+                    if (Build.VERSION_CODES.TIRAMISU
+                            > SystemProperties.getInt("ro.vendor.api_level", 0)) {
+                        compareOutput = false;
+                    } else {
+                        additionalInformation = " (b/194134359)";
                     }
-                    if (compareOutput) {
+                }
+                if (compareOutput) {
+                    if ((plaintextIndex % blockSize) == blockSize - 1) {
                         // Cipher.update is expected to have output a new block
                         assertArrayEquals(
                                 "plaintext index: " + plaintextIndex + additionalInformation,
@@ -863,10 +863,12 @@
                                         ciphertextIndex,
                                         ciphertextIndex + blockSize),
                                 output);
+                    } else {
+                        // Cipher.update is expected to have produced no output
+                        assertArrayEquals(
+                                "plaintext index: " + plaintextIndex + additionalInformation,
+                                null, output);
                     }
-                } else {
-                    // Cipher.update is expected to have produced no output
-                    assertArrayEquals("plaintext index: " + plaintextIndex, null, output);
                 }
                 if (output != null) {
                     ciphertextIndex += output.length;
@@ -943,27 +945,28 @@
                                 && (ciphertextIndex > 0) && ((ciphertextIndex % blockSize) == 0))
                         || ((!paddingEnabled) && ((ciphertextIndex % blockSize) == blockSize - 1));
 
-                if (outputExpected) {
-                    String additionalInformation = "";
-                    boolean compareOutput = true;
-                    if (isStrongbox()) {
-                        // This is known to be broken on older vendor implementations.
-                        if (Build.VERSION_CODES.TIRAMISU
-                                > SystemProperties.getInt("ro.vendor.api_level", 0)) {
-                            compareOutput = false;
-                        } else {
-                            additionalInformation = " (b/194134040)";
-                        }
+                String additionalInformation = "";
+                boolean compareOutput = true;
+                if (isStrongbox()) {
+                    // This is known to be broken on older vendor implementations.
+                    if (Build.VERSION_CODES.TIRAMISU
+                            > SystemProperties.getInt("ro.vendor.api_level", 0)) {
+                        compareOutput = false;
+                    } else {
+                        additionalInformation = " (b/194134040)";
                     }
-                    if (compareOutput) {
+                }
+                if (compareOutput) {
+                    if (outputExpected) {
                         assertArrayEquals(
                                 "ciphertext index: " + ciphertextIndex + additionalInformation,
                                 subarray(expectedPlaintext, plaintextIndex,
                                     plaintextIndex + blockSize),
                                 output);
+                    } else {
+                        assertEquals("ciphertext index: " + ciphertextIndex + additionalInformation,
+                                null, output);
                     }
-                } else {
-                    assertEquals("ciphertext index: " + ciphertextIndex, null, output);
                 }
 
                 if (output != null) {
@@ -1322,7 +1325,6 @@
         System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
         createCipher();
         initKat(opmode);
-        String additionalInformation = "";
         int outputLength = update(buffer, inputOffsetInBuffer, input.length,
                 buffer, outputOffsetInBuffer);
         if (isStrongbox()) {
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index d899b04..56b5aaf 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -815,6 +815,10 @@
         if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.S) {
             return;
         }
+        // ID attestation is not implemented on the goldfish emulator.
+        if (Build.BOARD.startsWith("goldfish")) {
+            return;
+        }
         // ID attestation is tested by other tests (outside of this class), including negative
         // tests that ID attestation is failing if the platform does not declare support.
         // Hence, it's safe to only test here that the feature is supported.
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 e0cae51..3e90992 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
@@ -615,6 +615,9 @@
      * Note: This assumes there is exactly one video codec running in the player.
      */
     public long getVideoTimeUs() {
+        if (mVideoCodecStates == null || mVideoCodecStates.get(0) == null) {
+            return CodecState.UNINITIALIZED_TIMESTAMP;
+        }
         return mVideoCodecStates.get(0).getVideoTimeUs();
     }
 
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 ed75129..73ba7c3 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
@@ -16,6 +16,7 @@
 
 package android.media.decoder.cts;
 
+import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_TunneledPlayback;
 import static android.media.MediaCodecInfo.CodecProfileLevel.AVCLevel31;
 import static android.media.MediaCodecInfo.CodecProfileLevel.AVCLevel32;
 import static android.media.MediaCodecInfo.CodecProfileLevel.AVCLevel4;
@@ -40,7 +41,6 @@
 import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.AudioTimestamp;
-import android.media.AudioTrack;
 import android.media.Image;
 import android.media.MediaCodec;
 import android.media.MediaCodec.BufferInfo;
@@ -3872,11 +3872,8 @@
      * TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
      */
     private void tunneledVideoPlayback(String mimeType, String videoName) throws Exception {
-        if (!isVideoFeatureSupported(mimeType,
-                CodecCapabilities.FEATURE_TunneledPlayback)) {
-            MediaUtils.skipTest(
-                    TAG,
-                    "No tunneled video playback codec found for MIME " + mimeType);
+        if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
+                    "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
         }
 
@@ -3892,6 +3889,16 @@
 
         // starts video playback
         mMediaCodecPlayer.startThread();
+        sleepUntil(() ->
+                mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
+                && mMediaCodecPlayer.getTimestamp() != null
+                && mMediaCodecPlayer.getTimestamp().framePosition > 0,
+                Duration.ofSeconds(1));
+        assertNotEquals("onFrameRendered was not called",
+                mMediaCodecPlayer.getVideoTimeUs(), CodecState.UNINITIALIZED_TIMESTAMP);
+        assertNotEquals("Audio timestamp is null", mMediaCodecPlayer.getTimestamp(), null);
+        assertNotEquals("Audio timestamp has a zero frame position",
+                mMediaCodecPlayer.getTimestamp().framePosition, 0);
 
         final long durationMs = mMediaCodecPlayer.getDuration();
         final long timeOutMs = System.currentTimeMillis() + durationMs + 5 * 1000; // add 5 sec
@@ -3947,11 +3954,8 @@
      * TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
      */
     private void testTunneledVideoFlush(String mimeType, String videoName) throws Exception {
-        if (!isVideoFeatureSupported(mimeType,
-                        CodecCapabilities.FEATURE_TunneledPlayback)) {
-            MediaUtils.skipTest(
-                    TAG,
-                    "No tunneled video playback codec found for MIME " + mimeType);
+        if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
+                    "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
         }
 
@@ -3967,7 +3971,17 @@
 
         // starts video playback
         mMediaCodecPlayer.startThread();
-        Thread.sleep(SLEEP_TIME_MS);
+        sleepUntil(() ->
+                mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
+                && mMediaCodecPlayer.getTimestamp() != null
+                && mMediaCodecPlayer.getTimestamp().framePosition > 0,
+                Duration.ofSeconds(1));
+        assertNotEquals("onFrameRendered was not called",
+                mMediaCodecPlayer.getVideoTimeUs(), CodecState.UNINITIALIZED_TIMESTAMP);
+        assertNotEquals("Audio timestamp is null", mMediaCodecPlayer.getTimestamp(), null);
+        assertNotEquals("Audio timestamp has a zero frame position",
+                mMediaCodecPlayer.getTimestamp().framePosition, 0);
+
         mMediaCodecPlayer.pause();
         mMediaCodecPlayer.flush();
         // mMediaCodecPlayer.reset() handled in TearDown();
@@ -4004,18 +4018,17 @@
     }
 
     /**
-     * Test tunneled video peek is on by default if supported
+     * Test tunneled video peek renders the first frame when on
      *
      * TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
      */
-    private void testTunneledVideoPeekDefault(String mimeType, String videoName) throws Exception {
-        if (!MediaUtils.check(mIsAtLeastS, "testTunneledVideoPeekDefault requires Android 12")) {
+    private void testTunneledVideoPeekOn(String mimeType, String videoName) throws Exception {
+        if (!MediaUtils.check(mIsAtLeastS, "testTunneledVideoPeekOn requires Android 12")) {
             return;
         }
 
-        if (!MediaUtils.check(isVideoFeatureSupported(mimeType,
-                                CodecCapabilities.FEATURE_TunneledPlayback),
-                        "No tunneled video playback codec found for MIME " + mimeType)){
+        if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
+                    "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
         }
 
@@ -4030,6 +4043,7 @@
         assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
         mMediaCodecPlayer.start();
+        mMediaCodecPlayer.setVideoPeek(true); // Enable video peek
 
         // Assert that onFirstTunnelFrameReady is called
         mMediaCodecPlayer.queueOneVideoFrame();
@@ -4047,38 +4061,38 @@
     }
 
     /**
-     * Test default tunneled video peek with HEVC if supported
+     * Test tunneled video peek with HEVC renders the first frame when on
      */
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
-    public void testTunneledVideoPeekDefaultHevc() throws Exception {
-        testTunneledVideoPeekDefault(MediaFormat.MIMETYPE_VIDEO_HEVC,
+    public void testTunneledVideoPeekOnHevc() throws Exception {
+        testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_HEVC,
                 "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
     }
 
     /**
-     * Test default tunneled video peek with AVC if supported
+     * Test tunneled video peek with AVC renders the first frame when on
      */
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
-    public void testTunneledVideoPeekDefaultAvc() throws Exception {
-        testTunneledVideoPeekDefault(MediaFormat.MIMETYPE_VIDEO_AVC,
+    public void testTunneledVideoPeekOnAvc() throws Exception {
+        testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
     }
 
     /**
-     * Test default tunneled video peek with VP9 if supported
+     * Test tunneled video peek with VP9 renders the first frame when on
      */
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
-    public void testTunneledVideoPeekDefaultVp9() throws Exception {
-        testTunneledVideoPeekDefault(MediaFormat.MIMETYPE_VIDEO_VP9,
+    public void testTunneledVideoPeekOnVp9() throws Exception {
+        testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_VP9,
                 "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
     }
 
 
     /**
-     * Test tunneled video peek can be turned off then on.
+     * Test tunneled video peek doesn't render the first frame when off and then turned on
      *
      * TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
      */
@@ -4087,9 +4101,8 @@
             return;
         }
 
-        if (!MediaUtils.check(isVideoFeatureSupported(mimeType,
-                                CodecCapabilities.FEATURE_TunneledPlayback),
-                        "No tunneled video playback codec found for MIME " + mimeType)){
+        if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
+                    "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
         }
 
@@ -4129,7 +4142,7 @@
     }
 
     /**
-     * Test tunneled video peek can be turned off then on with HEVC if supported
+     * Test tunneled video peek with HEVC doesn't render the first frame when off and then turned on
      */
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
@@ -4139,7 +4152,7 @@
     }
 
     /**
-     * Test tunneled video peek can be turned off then on with AVC if supported
+     * Test tunneled video peek with AVC doesn't render the first frame when off and then turned on
      */
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
@@ -4149,7 +4162,7 @@
     }
 
     /**
-     * Test tunneled video peek can be turned off then on with VP9 if supported
+     * Test tunneled video peek with VP9 doesn't render the first frame when off and then turned on
      */
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
@@ -4198,9 +4211,8 @@
     }
 
     private void testTunneledAudioPtsGaps(String mimeType, String fileName) throws Exception {
-        if (!MediaUtils.check(isVideoFeatureSupported(mimeType,
-                CodecCapabilities.FEATURE_TunneledPlayback),
-                "No tunneled video playback codec found for MIME " + mimeType)) {
+        if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
+                    "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
         }
 
@@ -4211,52 +4223,71 @@
 
         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());
 
+        // starts video playback
         mMediaCodecPlayer.startThread();
-        sleepUntil(() -> mMediaCodecPlayer.getTimestamp() != null
-                && mMediaCodecPlayer.getTimestamp().framePosition > 0,  Duration.ofSeconds(1));
-        // After 30 ms, Changing the presentation offset for audio track
-        Thread.sleep(30);
+        sleepUntil(() ->
+                mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
+                && mMediaCodecPlayer.getTimestamp() != null
+                && mMediaCodecPlayer.getTimestamp().framePosition > 0,
+                Duration.ofSeconds(1));
+        assertNotEquals("onFrameRendered was not called",
+                mMediaCodecPlayer.getVideoTimeUs(), CodecState.UNINITIALIZED_TIMESTAMP);
+        assertNotEquals("Audio timestamp is null", mMediaCodecPlayer.getTimestamp(), null);
+        assertNotEquals("Audio timestamp has a zero frame position",
+                mMediaCodecPlayer.getTimestamp().framePosition, 0);
 
         // Requirement: If the audio presentation timestamp header sent by the app is greater than
         // the current audio clock by less than 100ms, the framePosition returned by
         // AudioTrack#getTimestamp (per get_presentation_position) must not advance for any silent
         // frames rendered to fill the gap.
         // TODO: add link to documentation when available
-        mMediaCodecPlayer.setAudioTrackOffsetMs(100);
-        // Wait for 20 ms so that whatever was buffered before offset is played
-        Thread.sleep(20);
-        long initialFramePosition = mMediaCodecPlayer.getTimestamp().framePosition;
 
-        // Verify that the framePosition did not advance after 30 ms. This ensures framePosition
-        // returned by AudioTrack#getTimestamp did not advance for any silent frames rendered to
-        // fill PTS gaps.
+        // Simulate a PTS gap of 100ms after 30ms
         Thread.sleep(30);
-        assertEquals(
-                "Initial frame position != Final frame position after introducing PTS gaps",
-                initialFramePosition, mMediaCodecPlayer.getTimestamp().framePosition);
+        mMediaCodecPlayer.setAudioTrackOffsetMs(100);
 
+        // Verify that at some point in time in the future, the framePosition stopped advancing.
+        // This verifies that when silence was rendered to fill the PTS gap, that the silent frames
+        // do not cause framePosition to advance.
+        final long ptsGapTimeoutMs = 1000;
+        long startTimeMs = System.currentTimeMillis();
+        AudioTimestamp currentTimestamp = mMediaCodecPlayer.getTimestamp();
+        AudioTimestamp ptsGapTimestamp;
+        do {
+            assertTrue(String.format("No audio PTS gap after %d milliseconds", ptsGapTimeoutMs),
+                    System.currentTimeMillis() - startTimeMs < ptsGapTimeoutMs);
+            ptsGapTimestamp = currentTimestamp;
+            Thread.sleep(50);
+            currentTimestamp = mMediaCodecPlayer.getTimestamp();
+        } while (currentTimestamp.framePosition != ptsGapTimestamp.framePosition);
+
+        // Allow the playback to advance past the PTS gap and back to normal operation
         Thread.sleep(500);
+        // Simulate the end of playback
         mMediaCodecPlayer.stopWritingToAudioTrack(true);
 
         // Sleep till framePosition stabilizes, i.e. playback is complete or till max 3 seconds.
-        long framePosCurrent = 0;
-        int totalSleepMs = 0;
-        while (totalSleepMs < 3000
-                && framePosCurrent != mMediaCodecPlayer.getTimestamp().framePosition) {
-            framePosCurrent = mMediaCodecPlayer.getTimestamp().framePosition;
-            Thread.sleep(500);
-            totalSleepMs += 500;
-        }
+        final long endOfPlayackTimeoutMs = 3000;
+        startTimeMs = System.currentTimeMillis();
+        AudioTimestamp endOfPlaybackTimestamp;
+        do {
+            assertTrue(String.format("No end of playback after %d milliseconds",
+                            endOfPlayackTimeoutMs),
+                    System.currentTimeMillis() - startTimeMs < endOfPlayackTimeoutMs);
+            endOfPlaybackTimestamp = currentTimestamp;
+            Thread.sleep(50);
+            currentTimestamp = mMediaCodecPlayer.getTimestamp();
+        } while (currentTimestamp.framePosition != endOfPlaybackTimestamp.framePosition);
 
-        // Verify if number of frames written and played are same even if PTS Gaps were present
+        // Verify if number of frames written and played are same even if PTS gaps were present
         // in the playback.
         assertEquals("Number of frames written != Number of frames played",
                 mMediaCodecPlayer.getAudioFramesWritten(),
-                mMediaCodecPlayer.getTimestamp().framePosition);
+                endOfPlaybackTimestamp.framePosition);
     }
 
     /**
@@ -4291,8 +4322,7 @@
 
     private void testTunneledAudioTimestampProgressWithUnderrun(
             String mimeType, String fileName) throws Exception {
-        if (!MediaUtils.check(isVideoFeatureSupported(mimeType,
-                CodecCapabilities.FEATURE_TunneledPlayback),
+        if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                 "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
         }
@@ -4304,11 +4334,22 @@
 
         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());
 
+        // starts video playback
         mMediaCodecPlayer.startThread();
+        sleepUntil(() ->
+                mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
+                && mMediaCodecPlayer.getTimestamp() != null
+                && mMediaCodecPlayer.getTimestamp().framePosition > 0,
+                Duration.ofSeconds(1));
+        assertNotEquals("onFrameRendered was not called",
+                mMediaCodecPlayer.getVideoTimeUs(), CodecState.UNINITIALIZED_TIMESTAMP);
+        assertNotEquals("Audio timestamp is null", mMediaCodecPlayer.getTimestamp(), null);
+        assertNotEquals("Audio timestamp has a zero frame position",
+                mMediaCodecPlayer.getTimestamp().framePosition, 0);
 
         // Stop writing to the AudioTrack after 200 ms.
         Thread.sleep(200);
@@ -4353,9 +4394,8 @@
             return;
         }
 
-        if (!MediaUtils.check(isVideoFeatureSupported(mimeType,
-                                CodecCapabilities.FEATURE_TunneledPlayback),
-                        "No tunneled video playback codec found for MIME " + mimeType)){
+        if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
+                    "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
         }
 
@@ -4381,12 +4421,19 @@
         // does.
         mMediaCodecPlayer.setVideoPeek(false);
 
-        // Start playback
+        // starts video playback
         mMediaCodecPlayer.startThread();
-        Thread.sleep(maxAllowedTimeToFirstFrameMs);
-        assertNotEquals(String.format("No frame displayed after %d ms",
-                        maxAllowedTimeToFirstFrameMs), CodecState.UNINITIALIZED_TIMESTAMP,
-                mMediaCodecPlayer.getCurrentPosition());
+        sleepUntil(() ->
+                mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
+                && mMediaCodecPlayer.getTimestamp() != null
+                && mMediaCodecPlayer.getTimestamp().framePosition > 0,
+                Duration.ofSeconds(1));
+        assertNotEquals("onFrameRendered was not called",
+                mMediaCodecPlayer.getVideoTimeUs(), CodecState.UNINITIALIZED_TIMESTAMP);
+        assertNotEquals("Audio timestamp is null", mMediaCodecPlayer.getTimestamp(), null);
+        assertNotEquals("Audio timestamp has a zero frame position",
+                mMediaCodecPlayer.getTimestamp().framePosition, 0);
+
         // Pause playback
         mMediaCodecPlayer.pause();
         // Ensure audio and video are in sync. We give some time to the codec to finish displaying
@@ -4491,9 +4538,8 @@
     private void
     testTunneledAudioTimestampProgress(String mimeType, String videoName) throws Exception
     {
-        if (!isVideoFeatureSupported(mimeType,
-                CodecCapabilities.FEATURE_TunneledPlayback)) {
-            MediaUtils.skipTest(TAG,"No tunneled video playback codec found for MIME " + mimeType);
+        if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
+                    "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
         }
 
@@ -4509,15 +4555,18 @@
 
         // starts video playback
         mMediaCodecPlayer.startThread();
-
         sleepUntil(() ->
-                mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP,
+                mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
+                && mMediaCodecPlayer.getTimestamp() != null
+                && mMediaCodecPlayer.getTimestamp().framePosition > 0,
                 Duration.ofSeconds(1));
-        final int firstPosition = mMediaCodecPlayer.getCurrentPosition();
-        assertNotEquals("On frame rendered not called after playback start!",
-                CodecState.UNINITIALIZED_TIMESTAMP, firstPosition);
-        AudioTimestamp firstTimestamp = mMediaCodecPlayer.getTimestamp();
-        assertTrue("Timestamp is null!", firstTimestamp != null);
+        long firstVideoPosition = mMediaCodecPlayer.getVideoTimeUs();
+        assertNotEquals("onFrameRendered was not called",
+                firstVideoPosition, CodecState.UNINITIALIZED_TIMESTAMP);
+        AudioTimestamp firstAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+        assertNotEquals("Audio timestamp is null", firstAudioTimestamp, null);
+        assertNotEquals("Audio timestamp has a zero frame position",
+                firstAudioTimestamp.framePosition, 0);
 
         // Expected stabilization wait is 60ms. We triple to 180ms to prevent flakiness
         // and still test basic functionality.
@@ -4526,15 +4575,15 @@
         mMediaCodecPlayer.pause();
         // pause might take some time to ramp volume down.
         Thread.sleep(sleepTimeMs);
-        AudioTimestamp timeStampAfterPause = mMediaCodecPlayer.getTimestamp();
+        AudioTimestamp audioTimestampAfterPause = mMediaCodecPlayer.getTimestamp();
         // Verify the video has advanced beyond the first position.
-        assertTrue(mMediaCodecPlayer.getCurrentPosition() > firstPosition);
+        assertTrue(mMediaCodecPlayer.getVideoTimeUs() > firstVideoPosition);
         // Verify that the timestamp has advanced beyond the first timestamp.
-        assertTrue(timeStampAfterPause.nanoTime > firstTimestamp.nanoTime);
+        assertTrue(audioTimestampAfterPause.nanoTime > firstAudioTimestamp.nanoTime);
 
         Thread.sleep(sleepTimeMs);
         // Verify that the timestamp does not advance after pause.
-        assertEquals(timeStampAfterPause.nanoTime, mMediaCodecPlayer.getTimestamp().nanoTime);
+        assertEquals(audioTimestampAfterPause.nanoTime, mMediaCodecPlayer.getTimestamp().nanoTime);
     }
 
     /**
@@ -4546,11 +4595,8 @@
      */
     private void tunneledAudioUnderrun(String mimeType, String videoName, int frameRate)
             throws Exception {
-        if (!isVideoFeatureSupported(mimeType,
-                        CodecCapabilities.FEATURE_TunneledPlayback)) {
-            MediaUtils.skipTest(
-                    TAG,
-                    "No tunneled video playback codec found for MIME " + mimeType);
+        if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
+                "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
         }
 
@@ -4564,84 +4610,112 @@
         assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
 
-        // Start media playback
+        // Starts video playback
         mMediaCodecPlayer.startThread();
-        final int waitStartMs = 50;
-        Thread.sleep(waitStartMs);
-        assertTrue(String.format("Playback has not started after %d milliseconds", waitStartMs),
-                mMediaCodecPlayer.getVideoTimeUs() != 0);
+        sleepUntil(() ->
+                mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
+                && mMediaCodecPlayer.getTimestamp() != null
+                && mMediaCodecPlayer.getTimestamp().framePosition > 0,
+                Duration.ofSeconds(1));
+        assertNotEquals("onFrameRendered was not called",
+                mMediaCodecPlayer.getVideoTimeUs(), CodecState.UNINITIALIZED_TIMESTAMP);
+        assertNotEquals("Audio timestamp is null", mMediaCodecPlayer.getTimestamp(), null);
+        assertNotEquals("Audio timestamp has a zero frame position",
+                mMediaCodecPlayer.getTimestamp().framePosition, 0);
+
         // Keep buffering video content but stop buffering audio content -> audio underrun
         mMediaCodecPlayer.simulateAudioUnderrun(true);
-        // Loop to wait for audio underrun
-        // TODO(b/200280965): Find a more appropriate delay based on partner feedback
+
+        // Wait for audio underrun
         final int audioUnderrunTimeoutMs = 1000; // Arbitrary upper time limit on loop time duration
         long startTimeMs = System.currentTimeMillis();
-        AudioTimestamp previousTimestamp = mMediaCodecPlayer.getTimestamp();
+        AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
         AudioTimestamp underrunAudioTimestamp;
-        while ((underrunAudioTimestamp = mMediaCodecPlayer.getTimestamp()) != previousTimestamp) {
+        do {
             assertTrue(String.format("No audio underrun after %d milliseconds",
-                            audioUnderrunTimeoutMs),
+                            System.currentTimeMillis() - startTimeMs),
                     System.currentTimeMillis() - startTimeMs < audioUnderrunTimeoutMs);
-            previousTimestamp = underrunAudioTimestamp;
+            underrunAudioTimestamp = currentAudioTimestamp;
             Thread.sleep(50);
-        }
-        // Loop to wait until video playback stalls
-        long previousVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
-        long underrunVideoTimeUs;
-        startTimeMs = System.currentTimeMillis();
-        // TODO(b/200280965): Find a more appropriate delay based on partner feedback
+            currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+        } while (currentAudioTimestamp.framePosition != underrunAudioTimestamp.framePosition);
+
+
+        // Wait until video playback stalls
         final int videoUnderrunTimeoutMs = 1000;
-        while ((underrunVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs()) != previousVideoTimeUs) {
+        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);
-            previousVideoTimeUs = underrunVideoTimeUs;
+            underrunVideoTimeUs = currentVideoTimeUs;
             Thread.sleep(50);
-        }
+            currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+        } while (currentVideoTimeUs != underrunVideoTimeUs);
 
-        final int underrunVideoRenderedTimestampIndex =
+        // Retrieve index for the video rendered frame at the time of underrun
+        int underrunVideoRenderedTimestampIndex =
                 mMediaCodecPlayer.getRenderedVideoFrameTimestampList().size() - 1;
+
         // Resume audio buffering with a negative offset, in order to simulate a desynchronisation.
         // TODO(b/202710709): Use timestamp relative to last played video frame before pause
         mMediaCodecPlayer.setAudioTrackOffsetMs(-100);
         mMediaCodecPlayer.simulateAudioUnderrun(false);
 
-        // Loop to wait until audio playback resumes
+        // Wait until audio playback resumes
+        final int audioResumeTimeoutMs = 1000;
         startTimeMs = System.currentTimeMillis();
-        AudioTimestamp postResumeTimestamp;
-        while ((postResumeTimestamp = mMediaCodecPlayer.getTimestamp()) == underrunAudioTimestamp) {
+        currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+        AudioTimestamp postResumeAudioTimestamp;
+        do {
             assertTrue(String.format("Audio has not resumed after %d milliseconds",
-                            audioUnderrunTimeoutMs),
-                    System.currentTimeMillis() - startTimeMs < audioUnderrunTimeoutMs);
+                            audioResumeTimeoutMs),
+                    System.currentTimeMillis() - startTimeMs < audioResumeTimeoutMs);
+            postResumeAudioTimestamp = currentAudioTimestamp;
             Thread.sleep(50);
-        }
+            currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+        } while(currentAudioTimestamp.framePosition == postResumeAudioTimestamp.framePosition);
 
-        long resumeAudioSystemTime = interpolateSystemTimeAt(
-                underrunAudioTimestamp.framePosition + 1, postResumeTimestamp,
-                mMediaCodecPlayer.getAudioTrack());
-
-        // Now that audio playback has resumed, loop to wait until video playback resumes
+        // 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.
-        long resumeVideoTimeUs = 0;
+        final int videoResumeTimeoutMs = 1000;
         startTimeMs = System.currentTimeMillis();
-        while ((resumeVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs()) == underrunVideoTimeUs) {
+        currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+        long resumeVideoTimeUs = -1;
+        do {
             assertTrue(String.format("Video has not resumed after %d milliseconds",
-                            videoUnderrunTimeoutMs),
-                    System.currentTimeMillis() - startTimeMs < videoUnderrunTimeoutMs);
+                            videoResumeTimeoutMs),
+                    System.currentTimeMillis() - startTimeMs < videoResumeTimeoutMs);
+            resumeVideoTimeUs = currentVideoTimeUs;
             Thread.sleep(50);
-        }
+            currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+        } while (currentVideoTimeUs == resumeVideoTimeUs);
 
-        final ImmutableList<Long> renderedSystemTimeList =
-                mMediaCodecPlayer.getRenderedVideoFrameSystemTimeList();
-        final long resumeVideoFrameSystemTime = mMediaCodecPlayer
-                .getRenderedVideoFrameSystemTimeList().get(underrunVideoRenderedTimestampIndex + 1);
-        final long vsync = (long) (1000 / frameRate);
-        final long avSyncOffset = resumeAudioSystemTime + 100 - resumeVideoFrameSystemTime;
-        assertTrue(String.format("Audio and video tracks are more than %d milliseconds out of sync",
-                        vsync),
-                Math.abs(avSyncOffset) <= vsync);
+        // The system time when rendering the first audio frame after the resume
+        long playbackRateFps = mMediaCodecPlayer.getAudioTrack().getPlaybackRate();
+        long playedFrames = postResumeAudioTimestamp.framePosition
+                - underrunAudioTimestamp.framePosition + 1;
+        double elapsedTimeNs = playedFrames * (1000.0 * 1000.0 * 1000.0 / playbackRateFps);
+        long resumeAudioSystemTimeNs = postResumeAudioTimestamp.nanoTime - (long) elapsedTimeNs;
+        long resumeAudioSystemTimeMs = resumeAudioSystemTimeNs / 1000 / 1000;
+
+        // The system time when rendering the first video frame after the resume
+        long resumeVideoSystemTimeMs = mMediaCodecPlayer.getRenderedVideoFrameSystemTimeList()
+                .get(underrunVideoRenderedTimestampIndex + 1) / 1000 / 1000;
+
+        // Verify that audio and video are in-sync after resume time
+        // Note: Because a -100ms PTS gap is introduced, the video should resume 100ms later
+        resumeAudioSystemTimeMs += 100;
+        long vsyncMs = 1000 / frameRate;
+        long avSyncOffsetMs = resumeAudioSystemTimeMs - resumeVideoSystemTimeMs;
+        assertTrue(String.format(
+                        "Audio is %d milliseconds out of sync of video (audio:%d video:%d)",
+                        avSyncOffsetMs, resumeAudioSystemTimeMs, resumeVideoSystemTimeMs),
+                Math.abs(avSyncOffsetMs) <= vsyncMs);
     }
 
     /**
@@ -4685,18 +4759,6 @@
     }
 
     /**
-     * Returns the system time of the frame {@code framePosition} from {@code timestamp}, for a
-     * specific {@code AudioTrack}.
-     */
-    private static long interpolateSystemTimeAt(long framePosition, AudioTimestamp timestamp,
-            AudioTrack audioTrack) {
-        final long playbackRateFps = audioTrack.getPlaybackRate();  // Frames per second
-        final long playedFrames = timestamp.framePosition - framePosition;
-        final double elapsedTimeNs = playedFrames * (1000000000.0 / playbackRateFps);
-        return timestamp.nanoTime - (long) elapsedTimeNs;
-    }
-
-    /**
      * Returns list of CodecCapabilities advertising support for the given MIME type.
      */
     private static List<CodecCapabilities> getCodecCapabilitiesForMimeType(String mimeType) {
diff --git a/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java b/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java
index a28095f..eab6aeb 100644
--- a/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java
@@ -449,6 +449,8 @@
                         CamcorderProfile.getAll(String.valueOf(cameraId), quality);
                     checkAllProfiles(allProfiles, profile, videoSizesToCheck);
                 }
+            } else {
+                assertNull(CamcorderProfile.getAll(String.valueOf(cameraId), quality));
             }
         }
 
diff --git a/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc b/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc
index 8c17a72f..8533d7e 100644
--- a/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc
+++ b/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc
@@ -16,6 +16,7 @@
 #include "jni.h"
 
 #include <cstring>
+#include <cassert>
 
 #include <errno.h>
 #include <fcntl.h>
@@ -118,9 +119,9 @@
 
   int major, minor;
   struct utsname uts;
-  if (uname(&uts) != 0 ||
-      strcmp(uts.sysname, "Linux") != 0 ||
-      sscanf(uts.release, "%d.%d", &major, &minor) != 2 ||
+  uname(&uts);
+  assert(strcmp(uts.sysname, "Linux") == 0);
+  if (sscanf(uts.release, "%d.%d", &major, &minor) != 2 ||
       (major < kRequiredMajor || (major == kRequiredMajor && minor < kRequiredMinor))) {
     return false;
   }
@@ -131,6 +132,22 @@
 }
 
 extern "C"
+JNIEXPORT bool JNICALL Java_android_os_cts_uffdgc_UserfaultfdTest_confirmKernelArch64bit(JNIEnv*) {
+#if defined(__linux__)
+  struct utsname uts;
+  uname(&uts);
+  assert(strcmp(uts.sysname, "Linux") == 0);
+  if (strstr(uts.machine, "64") != nullptr ||
+      strstr(uts.machine, "armv8") == uts.machine) {
+    return true;
+  }
+  return false;
+#else
+  return false;
+#endif
+}
+
+extern "C"
 JNIEXPORT jint JNICALL Java_android_os_cts_uffdgc_UserfaultfdTest_performKernelSpaceUffd(JNIEnv*) {
   int ret = 0, write_fd = 0;
   void* addr = nullptr;
diff --git a/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java b/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java
index fc4df13..2f092a6 100644
--- a/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java
+++ b/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java
@@ -71,6 +71,8 @@
   // Test if userfaultfd works for minor-faults on shmem.
   @Test
   public void minorUserfaultfd() {
+    // minor fault feature is not enabled on 32-bit kernel archs.
+    Assume.assumeTrue(confirmKernelArch64bit());
     assertEquals(0, performMinorUffd());
   }
 
@@ -82,6 +84,7 @@
     assertEquals(13, checkGetattr());
   }
 
+  private native boolean confirmKernelArch64bit();
   private native boolean confirmKernelVersion();
   private native int performKernelSpaceUffd();
   private native int uffdWithoutUserModeOnly();
diff --git a/tests/tests/packageinstaller/uninstall/src/android/packageinstaller/uninstall/cts/UninstallTest.java b/tests/tests/packageinstaller/uninstall/src/android/packageinstaller/uninstall/cts/UninstallTest.java
index 893f23a..4a5cea9 100644
--- a/tests/tests/packageinstaller/uninstall/src/android/packageinstaller/uninstall/cts/UninstallTest.java
+++ b/tests/tests/packageinstaller/uninstall/src/android/packageinstaller/uninstall/cts/UninstallTest.java
@@ -34,9 +34,11 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AsbSecurityTest;
 import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.SearchCondition;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.Until;
@@ -60,6 +62,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.util.concurrent.TimeUnit;
 
 @RunWith(AndroidJUnit4.class)
 @AppModeFull
@@ -99,12 +102,26 @@
         }
     }
 
-    private void startUninstall() {
+    private void startUninstall() throws RemoteException {
         Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
         intent.setData(Uri.parse("package:" + TEST_APK_PACKAGE_NAME));
         intent.addFlags(FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK);
         Log.d(LOG_TAG, "sending uninstall intent ("  + intent + ") on user " + mContext.getUser());
+
+        mUiDevice.waitForIdle();
+        // wake up the screen
+        mUiDevice.wakeUp();
+        // unlock the keyguard or the expected window is by systemui or other alert window
+        mUiDevice.pressMenu();
+        // dismiss the system alert window for requesting permissions
+        mUiDevice.pressBack();
+        // return to home/launcher to prevent from being obscured by systemui or other alert window
+        mUiDevice.pressHome();
+
         mContext.startActivity(intent);
+
+        // wait for device idle
+        mUiDevice.waitForIdle();
     }
 
     @Test
@@ -147,16 +164,32 @@
         }
     }
 
+    private void waitFor(SearchCondition<UiObject2> condition)
+            throws IOException, InterruptedException {
+        final long OneSecond = TimeUnit.SECONDS.toMillis(1);
+        final long start = System.currentTimeMillis();
+        while (System.currentTimeMillis() - start < TIMEOUT_MS) {
+            try {
+                if (mUiDevice.wait(condition, OneSecond) == null) {
+                    continue;
+                }
+                return;
+            } catch (Throwable e) {
+                Thread.sleep(OneSecond);
+            }
+        }
+        dumpWindowHierarchy();
+        fail("Unable to wait for the uninstaller activity");
+    }
+
     @Test
     public void testUninstall() throws Exception {
         assertTrue("Package is not installed", isInstalled());
 
         startUninstall();
 
-        if (mUiDevice.wait(Until.findObject(By.text("Do you want to uninstall this app?")),
-                TIMEOUT_MS) == null) {
-            dumpWindowHierarchy();
-        }
+        waitFor(Until.findObject(By.text("Do you want to uninstall this app?")));
+
         assertNotNull("Uninstall prompt not shown",
                 mUiDevice.wait(Until.findObject(By.text("Do you want to uninstall this app?")),
                         TIMEOUT_MS));
diff --git a/tests/tests/permission/Android.bp b/tests/tests/permission/Android.bp
index b78b6c0..eae7276 100644
--- a/tests/tests/permission/Android.bp
+++ b/tests/tests/permission/Android.bp
@@ -63,4 +63,54 @@
         "android.test.runner",
         "android.test.base",
     ],
+    data: [
+        ":AppThatDefinesUndefinedPermissionGroupElement",
+        ":AppThatDoesNotHaveBgLocationAccess",
+        ":CtsAdversarialPermissionDefinerApp",
+        ":CtsAdversarialPermissionUserApp",
+        ":CtsAppThatAccessesLocationOnCommand",
+        ":CtsAppThatAlsoDefinesPermissionA",
+        ":CtsAppThatAlsoDefinesPermissionADifferentCert",
+        ":CtsAppThatAlsoDefinesPermissionGroupADifferentCert",
+        ":CtsAppThatAlsoDefinesPermissionGroupADifferentCert30",
+        ":CtsAppThatDefinesPermissionA",
+        ":CtsAppThatDefinesPermissionInPlatformGroup",
+        ":CtsAppThatDefinesPermissionWithInvalidGroup",
+        ":CtsAppThatDefinesPermissionWithInvalidGroup30",
+        ":CtsAppThatRequestsBluetoothPermission30",
+        ":CtsAppThatRequestsCalendarContactsBodySensorCustomPermission",
+        ":CtsAppThatRequestsBluetoothPermission31",
+        ":CtsAppThatRequestsBluetoothPermissionNeverForLocation31",
+        ":CtsAppThatRequestsContactsAndCallLogPermission16",
+        ":CtsAppThatRequestsContactsPermission15",
+        ":CtsAppThatRequestsContactsPermission16",
+        ":CtsAppThatRequestsLocationAndBackgroundPermission28",
+        ":CtsAppThatRequestsLocationAndBackgroundPermission29",
+        ":CtsAppThatRequestsBluetoothPermissionNeverForLocationNoProvider",
+        ":CtsAppThatRequestsLocationPermission22",
+        ":CtsAppThatRequestsLocationPermission28",
+        ":CtsAppThatRequestsLocationPermission29",
+        ":CtsAppThatRequestsLocationPermission29v4",
+        ":CtsAppThatRequestsOneTimePermission",
+        ":CtsAppThatRequestsPermissionAandB",
+        ":CtsAppThatRequestsPermissionAandC",
+        ":CtsAppThatRequestsStoragePermission28",
+        ":CtsAppThatRequestsStoragePermission29",
+        ":CtsAppThatRunsRationaleTests",
+        ":CtsAppToTestRevokeSelfPermission",
+        ":CtsAppWithSharedUidThatRequestsLocationPermission28",
+        ":CtsAppWithSharedUidThatRequestsLocationPermission29",
+        ":CtsAppWithSharedUidThatRequestsNoPermissions",
+        ":CtsAppWithSharedUidThatRequestsPermissions",
+        ":CtsInstallPermissionDefinerApp",
+        ":CtsInstallPermissionEscalatorApp",
+        ":CtsInstallPermissionUserApp",
+        ":CtsRuntimePermissionDefinerApp",
+        ":CtsRuntimePermissionUserApp",
+        ":CtsStorageEscalationApp28",
+        ":CtsStorageEscalationApp29Full",
+        ":CtsStorageEscalationApp29Scoped",
+        ":CtsVictimPermissionDefinerApp",
+    ],
+    per_testcase_directory: true,
 }
diff --git a/tests/tests/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt b/tests/tests/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt
index 95e3e55..f2e0ffa 100644
--- a/tests/tests/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt
+++ b/tests/tests/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt
@@ -104,24 +104,25 @@
      */
     @Test
     fun testCustomPermissionGrantedAlone() {
-        Assert.assertEquals(mPm!!.checkPermission(CAMERA, APP_PKG_NAME),
-                PackageManager.PERMISSION_DENIED)
-        Assert.assertEquals(mPm!!.checkPermission(RECORD_AUDIO, APP_PKG_NAME),
-                PackageManager.PERMISSION_DENIED)
-        Assert.assertEquals(mPm!!.checkPermission(TEST, APP_PKG_NAME),
-                PackageManager.PERMISSION_DENIED)
+        Assert.assertEquals(PackageManager.PERMISSION_DENIED,
+            mPm!!.checkPermission(CAMERA, APP_PKG_NAME))
+        Assert.assertEquals(PackageManager.PERMISSION_DENIED,
+            mPm!!.checkPermission(RECORD_AUDIO, APP_PKG_NAME))
+        Assert.assertEquals(PackageManager.PERMISSION_DENIED,
+            mPm!!.checkPermission(TEST, APP_PKG_NAME))
         eventually {
             startRequestActivity(arrayOf(TEST))
             mUiDevice!!.waitForIdle()
+            Thread.sleep(2000)
             findAllowButton().click()
         }
         eventually {
-            Assert.assertEquals(mPm!!.checkPermission(CAMERA, APP_PKG_NAME),
-                    PackageManager.PERMISSION_DENIED)
-            Assert.assertEquals(mPm!!.checkPermission(RECORD_AUDIO, APP_PKG_NAME),
-                    PackageManager.PERMISSION_DENIED)
-            Assert.assertEquals(mPm!!.checkPermission(TEST, APP_PKG_NAME),
-                    PackageManager.PERMISSION_GRANTED)
+            Assert.assertEquals(PackageManager.PERMISSION_DENIED,
+                mPm!!.checkPermission(CAMERA, APP_PKG_NAME))
+            Assert.assertEquals(PackageManager.PERMISSION_DENIED,
+                mPm!!.checkPermission(RECORD_AUDIO, APP_PKG_NAME))
+            Assert.assertEquals(PackageManager.PERMISSION_GRANTED,
+                mPm!!.checkPermission(TEST, APP_PKG_NAME))
         }
     }
 
@@ -133,11 +134,11 @@
     fun findAllowButton(): UiObject2 {
         return if (mContext?.packageManager
                         ?.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) == true) {
-            waitFindObject(By.text(mAllowButtonText), 100)
+            waitFindObject(By.text(mAllowButtonText), 2000)
         } else {
             waitFindObject(By.res(
                     "com.android.permissioncontroller:id/permission_allow_button"),
-                    100)
+                    2000)
         }
     }
 
@@ -150,8 +151,8 @@
             mPm!!.grantRuntimePermission(
                     APP_PKG_NAME, grantedPerm, Process.myUserHandle())
         }
-        Assert.assertEquals("$grantedPerm not granted.", mPm!!.checkPermission(grantedPerm,
-                APP_PKG_NAME), PackageManager.PERMISSION_GRANTED)
+        Assert.assertEquals("$grantedPerm not granted.", PackageManager.PERMISSION_GRANTED,
+            mPm!!.checkPermission(grantedPerm, APP_PKG_NAME))
 
         // If the dialog shows, success. If not then either the UI is broken or the permission was
         // granted in the background.
@@ -161,18 +162,18 @@
             try {
                 if (mContext?.packageManager
                                 ?.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) == true) {
-                    waitFindObject(By.text(mDenyButtonText), 100)
+                    waitFindObject(By.text(mDenyButtonText), 2000)
                 } else {
-                    waitFindObject(By.res("com.android.permissioncontroller:id/grant_dialog"), 100)
+                    waitFindObject(By.res("com.android.permissioncontroller:id/grant_dialog"), 2000)
                 }
             } catch (e: UiObjectNotFoundException) {
                 Assert.assertEquals("grant dialog never showed.",
-                        mPm!!.checkPermission(targetPermission,
-                                APP_PKG_NAME), PackageManager.PERMISSION_GRANTED)
+                    PackageManager.PERMISSION_GRANTED,
+                    mPm!!.checkPermission(targetPermission, APP_PKG_NAME))
             }
         }
-        Assert.assertEquals(mPm!!.checkPermission(targetPermission, APP_PKG_NAME),
-                PackageManager.PERMISSION_DENIED)
+        Assert.assertEquals(PackageManager.PERMISSION_DENIED,
+            mPm!!.checkPermission(targetPermission, APP_PKG_NAME))
     }
 
     private fun startRequestActivity(permissions: Array<String>) {
diff --git a/tests/tests/permission3/UsePermissionApp30/AndroidManifest.xml b/tests/tests/permission3/UsePermissionApp30/AndroidManifest.xml
index 03654c0..fcfb2d8 100644
--- a/tests/tests/permission3/UsePermissionApp30/AndroidManifest.xml
+++ b/tests/tests/permission3/UsePermissionApp30/AndroidManifest.xml
@@ -32,6 +32,8 @@
 
     <uses-permission android:name="android.permission.CAMERA" />
 
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
     <application>
         <activity android:name=".CheckCalendarAccessActivity" android:exported="true" />
         <activity android:name=".FinishOnCreateActivity" android:exported="true" />
diff --git a/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
index ffbc67d..6693aa3 100644
--- a/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
@@ -16,8 +16,10 @@
 
 package android.permission3.cts
 
+import android.Manifest
 import android.os.Build
 import androidx.test.filters.SdkSuppress
+import com.android.compatibility.common.util.SystemUtil
 import org.junit.Test
 
 /**
@@ -110,4 +112,62 @@
         }
         assertStorageAndMediaPermissionState(false)
     }
+
+    @Test
+    fun testWhenA33AppRequestsAuralThenDialogAndGrant() {
+        installPackage(APP_APK_PATH_LATEST)
+        requestAppPermissions(android.Manifest.permission.READ_MEDIA_AUDIO) {
+            clickPermissionRequestAllowButton()
+        }
+        assertAppHasPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE, false)
+        assertAppHasPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, false)
+        assertAppHasPermission(android.Manifest.permission.READ_MEDIA_AUDIO, true)
+        assertAppHasPermission(android.Manifest.permission.READ_MEDIA_VIDEO, false)
+        assertAppHasPermission(android.Manifest.permission.READ_MEDIA_IMAGES, false)
+    }
+
+    @Test
+    fun testWhenA33AppRequestsVisualThenDialogAndGrant() {
+        installPackage(APP_APK_PATH_LATEST)
+        requestAppPermissions(
+            android.Manifest.permission.READ_MEDIA_VIDEO,
+            android.Manifest.permission.READ_MEDIA_IMAGES
+        ) {
+            clickPermissionRequestAllowButton()
+        }
+        assertAppHasPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE, false)
+        assertAppHasPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, false)
+        assertAppHasPermission(android.Manifest.permission.READ_MEDIA_AUDIO, false)
+        assertAppHasPermission(android.Manifest.permission.READ_MEDIA_VIDEO, true)
+        assertAppHasPermission(android.Manifest.permission.READ_MEDIA_IMAGES, true)
+    }
+
+    @Test
+    fun testWhenA30AppRequestsStorageWhenMediaPermsHaveRWRFlag() {
+        installPackage(APP_APK_PATH_30)
+
+        requestAppPermissionsAndAssertResult(
+            Manifest.permission.READ_EXTERNAL_STORAGE to true
+        ) {
+            clickPermissionRequestAllowButton()
+        }
+
+        fun setRevokeWhenRequested(permission: String) = SystemUtil.runShellCommandOrThrow(
+            "pm set-permission-flags android.permission3.cts.usepermission " +
+                permission + " revoke-when-requested")
+        setRevokeWhenRequested("android.permission.READ_MEDIA_AUDIO")
+        setRevokeWhenRequested("android.permission.READ_MEDIA_VIDEO")
+        setRevokeWhenRequested("android.permission.READ_MEDIA_IMAGES")
+
+        requestAppPermissionsAndAssertResult(
+            Manifest.permission.READ_EXTERNAL_STORAGE to true
+        ) {
+            // No dialog should appear
+        }
+
+        assertAppHasPermission(Manifest.permission.READ_EXTERNAL_STORAGE, true)
+        assertAppHasPermission(Manifest.permission.READ_MEDIA_AUDIO, true)
+        assertAppHasPermission(Manifest.permission.READ_MEDIA_VIDEO, true)
+        assertAppHasPermission(Manifest.permission.READ_MEDIA_IMAGES, true)
+    }
 }
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionAttributionTest.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionAttributionTest.kt
index 57efe74..31e5449 100644
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionAttributionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionAttributionTest.kt
@@ -29,11 +29,9 @@
 import com.android.compatibility.common.util.CtsDownstreamingTest
 import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
 import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import com.android.modules.utils.build.SdkLevel
 import org.junit.After
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertTrue
-import org.junit.Assume.assumeFalse
 import org.junit.Before
 import org.junit.Test
 import java.util.concurrent.TimeUnit
@@ -41,19 +39,16 @@
 /**
  * Tests permission attribution for location providers.
  */
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+// Tests converted to GTS since these are GMS requirements not CDD.
+// These will be moved to GTS in U.
+@CtsDownstreamingTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
 class PermissionAttributionTest : BasePermissionHubTest() {
     private val micLabel = packageManager.getPermissionGroupInfo(
         android.Manifest.permission_group.MICROPHONE, 0).loadLabel(packageManager).toString()
     val locationManager = context.getSystemService(LocationManager::class.java)!!
     private var wasEnabled = false
 
-    // Permission history is not available on Auto devices running S or below.
-    @Before
-    fun assumeNotAutoBelowT() {
-        assumeFalse(isAutomotive && !SdkLevel.isAtLeastT())
-    }
-
     @Before
     fun installAppLocationProviderAndAllowMockLocation() {
         installPackage(APP_APK_PATH, grantRuntimePermissions = true)
@@ -79,7 +74,6 @@
         }
     }
 
-    @CtsDownstreamingTest
     @Test
     fun testLocationProviderAttributionForMicrophone() {
         enableAppAsLocationProvider()
diff --git a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
index f23faae..fe9037a 100644
--- a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
+++ b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
@@ -295,7 +295,7 @@
                 // indicator
                 uiDevice.openQuickSettings()
                 assertPrivacyChipAndIndicatorsPresent(
-                    useMic || useHotword,
+                    useMic,
                     useCamera,
                     chainUsage,
                     safetyCenterEnabled
@@ -390,11 +390,13 @@
         chainUsage: Boolean,
         safetyCenterEnabled: Boolean = false
     ) {
-        // Ensure the privacy chip is present
-        eventually {
-            val privacyChip = uiDevice.findObject(UiSelector().resourceId(PRIVACY_CHIP_ID))
-            assertTrue("view with id $PRIVACY_CHIP_ID not found", privacyChip.exists())
-            privacyChip.click()
+        // Ensure the privacy chip is present (or not)
+        val chipFound = isChipPresent()
+        if (useMic || useCamera) {
+            assertTrue("Did not find chip", chipFound)
+        } else { // hotword
+            assertFalse("Found chip, but did not expect to", chipFound)
+            return
         }
 
         eventually {
@@ -455,6 +457,21 @@
         assertEquals("Expected only one shell view", 1, shellView.size)
     }
 
+    private fun isChipPresent(): Boolean {
+        var chipFound = false
+        try {
+            eventually {
+                val privacyChip = uiDevice.findObject(By.res(PRIVACY_CHIP_ID))
+                assertNotNull("view with id $PRIVACY_CHIP_ID not found", privacyChip)
+                privacyChip.click()
+                chipFound = true
+            }
+        } catch (e: Exception) {
+            // Handle more gracefully after
+        }
+        return chipFound
+    }
+
     private fun pressBack() {
         uiDevice.pressBack()
         waitForIdle()
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 5b53d0e..186c5e2 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -194,6 +194,13 @@
             android:grantUriPermissions="true"
             android:process=":badprovider" />
 
+        <activity android:name="android.security.cts.CVE_2022_20143.PocActivity"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.app.action.AUTOMATIC_ZEN_RULE"/>
+            </intent-filter>
+        </activity>
+
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/security/src/android/security/cts/BasePermissionUiTest.kt b/tests/tests/security/src/android/security/cts/BasePermissionUiTest.kt
index d42f56d..b449451 100644
--- a/tests/tests/security/src/android/security/cts/BasePermissionUiTest.kt
+++ b/tests/tests/security/src/android/security/cts/BasePermissionUiTest.kt
@@ -37,6 +37,7 @@
 import androidx.test.rule.ActivityTestRule
 import com.android.compatibility.common.util.SystemUtil
 import com.android.compatibility.common.util.UiAutomatorUtils
+import com.android.modules.utils.build.SdkLevel
 import com.android.sts.common.util.StsExtraBusinessLogicTestCase
 import org.junit.After
 import org.junit.Assert.assertEquals
@@ -63,7 +64,6 @@
 
         const val APP_PACKAGE_NAME = "android.security.cts.usepermission"
         const val NOTIF_TEXT = "permgrouprequest_notifications"
-        const val NOTIF_CONTINUE_TEXT = "permgrouprequestcontinue_notifications"
         const val ALLOW_BUTTON_TEXT = "grant_dialog_button_allow"
         const val ALLOW_BUTTON =
             "com.android.permissioncontroller:id/permission_allow_button"
@@ -216,7 +216,7 @@
         )
         waitForIdle()
         // Notification permission prompt is shown first, so get it out of the way
-        clickNotificationPermissionRequestAllowButton()
+        clickNotificationPermissionRequestAllowButtonIfAvailable()
         // Perform the post-request action
         block()
         return future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
@@ -225,10 +225,14 @@
     /**
      * Only for use in tests that are not testing the notification permission popup
      */
-    private fun clickNotificationPermissionRequestAllowButton() {
+    private fun clickNotificationPermissionRequestAllowButtonIfAvailable() {
+        if (!SdkLevel.isAtLeastT()) {
+            return
+        }
+
         if (waitFindObjectOrNull(
                 By.text(getPermissionControllerString(
-                    NOTIF_CONTINUE_TEXT,
+                    NOTIF_TEXT,
                     APP_PACKAGE_NAME
                 )), 1000) != null ||
             waitFindObjectOrNull(
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20143/CVE_2022_20143.java b/tests/tests/security/src/android/security/cts/CVE_2022_20143/CVE_2022_20143.java
new file mode 100644
index 0000000..3c08cbb
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20143/CVE_2022_20143.java
@@ -0,0 +1,117 @@
+/*
+ * 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_20143;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.AutomaticZenRule;
+import android.app.Instrumentation;
+import android.app.NotificationManager;
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.Uri;
+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.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20143 extends StsExtraBusinessLogicTestCase {
+
+    @AsbSecurityTest(cveBugId = 220735360)
+    @Test
+    public void testPocCVE_2022_20143() {
+        final int ruleLimitPerPackage = 200;
+        final int timeoutDuration = 5000;
+        final int waitDuration = 100;
+        Instrumentation instrumentation;
+        Context context;
+        NotificationManager notificationManager = null;
+        String packageName = null;
+        UiAutomation uiautomation = null;
+        boolean isVulnerable = true;
+        boolean notificationPolicyAccessGranted = false;
+        int automaticZenRules = 0;
+        ArrayList<String> ruleIds = new ArrayList<>();
+        try {
+            instrumentation = InstrumentationRegistry.getInstrumentation();
+            context = instrumentation.getContext();
+            notificationManager = context.getSystemService(NotificationManager.class);
+            packageName = context.getPackageName();
+            uiautomation = instrumentation.getUiAutomation();
+            uiautomation.executeShellCommand("cmd notification allow_dnd " + packageName);
+            long startTime = System.currentTimeMillis();
+            while (System.currentTimeMillis() - startTime < timeoutDuration) {
+                // busy wait until notification policy access is granted
+                if (notificationManager.isNotificationPolicyAccessGranted()) {
+                    notificationPolicyAccessGranted = true;
+                    break;
+                }
+                Thread.sleep(waitDuration);
+            }
+            // storing the number of automaticZenRules present before test run
+            automaticZenRules = notificationManager.getAutomaticZenRules().size();
+            ComponentName component =
+                    new ComponentName(packageName, PocActivity.class.getCanonicalName());
+            for (int i = 0; i < ruleLimitPerPackage; ++i) {
+                Uri conditionId = Uri.parse("condition://android/" + i);
+                AutomaticZenRule rule = new AutomaticZenRule("ZenRuleName" + i, null, component,
+                        conditionId, null, NotificationManager.INTERRUPTION_FILTER_ALL, true);
+                String id = notificationManager.addAutomaticZenRule(rule);
+                ruleIds.add(id);
+            }
+        } catch (Exception e) {
+            if (e instanceof IllegalArgumentException) {
+                isVulnerable = false; // expected with fix
+            } else {
+                assumeNoException(e);
+            }
+        } finally {
+            try {
+                if (notificationPolicyAccessGranted) {
+                    /* retrieving the total number of automaticZenRules added by test so that the */
+                    /* test fails only if all automaticZenRules were added successfully */
+                    automaticZenRules =
+                            notificationManager.getAutomaticZenRules().size() - automaticZenRules;
+                    for (String id : ruleIds) {
+                        notificationManager.removeAutomaticZenRule(id);
+                    }
+                    uiautomation
+                            .executeShellCommand("cmd notification disallow_dnd " + packageName);
+                }
+                boolean allZenRulesAdded = ruleLimitPerPackage == automaticZenRules;
+                assumeTrue("Notification policy access not granted",
+                        notificationPolicyAccessGranted);
+                assertFalse(
+                        "Vulnerable to b/220735360!! System can be corrupted by adding many"
+                                + " AutomaticZenRules via NotificationManager#addAutomaticZenRule",
+                        isVulnerable && allZenRulesAdded);
+            } catch (Exception e) {
+                assumeNoException(e);
+            }
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20143/PocActivity.java b/tests/tests/security/src/android/security/cts/CVE_2022_20143/PocActivity.java
new file mode 100644
index 0000000..4416990
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20143/PocActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20143;
+
+import android.app.Activity;
+
+public class PocActivity extends Activity {
+}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index af5fb29..a061920 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -95,6 +95,8 @@
 import static org.junit.Assume.*;
 import static org.junit.Assert.*;
 
+import static org.hamcrest.Matchers.is;
+
 /**
  * Verify that the device is not vulnerable to any known Stagefright
  * vulnerabilities.
@@ -2361,6 +2363,16 @@
                 try {
                     MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(mime);
                     if (caps != null) {
+                        /* Add mainline skip to decoders in mainline module */
+                        if (isCodecInMainlineModule(info.getName())) {
+                            Log.i(TAG, "Skipping codec " + info.getName() +
+                                        " as it is part of mainline");
+                            continue;
+                        }
+                        if (info.isAlias()) {
+                            Log.i(TAG, "Skipping codec " + info.getName() + " as it is an alias");
+                            continue;
+                        }
                         matchingCodecs.add(info.getName());
                         Log.i(TAG, "Found matching codec " + info.getName() + " for track " + t);
                     }
@@ -2678,9 +2690,8 @@
         } catch (InterruptedException e) {
             fail("operation was interrupted");
         }
-        if (t.isAlive()) {
-            fail("operation not completed within timeout of " + timeout + "ms");
-        }
+        assumeThat("operation not completed within timeout of " + timeout + "ms", t.isAlive(),
+                   is(false));
     }
 
     private void releaseCodec(final MediaCodec codec) {
@@ -2692,6 +2703,20 @@
         }, 5000);
     }
 
+    private boolean isCodecInMainlineModule(String codecName) {
+        boolean value = false;
+        if (codecName.startsWith("c2.android.")) {
+            try {
+                value = ModuleDetector.moduleIsPlayManaged(
+                        getInstrumentation().getContext().getPackageManager(),
+                        MainlineModule.MEDIA_SOFTWARE_CODEC);
+            } catch (Exception e) {
+                Log.e(TAG, "Exception caught " + e.toString());
+            }
+        }
+        return value;
+    }
+
     private void doStagefrightTestRawBlob(
             int rid, String mime, int initWidth, int initHeight) throws Exception {
         doStagefrightTestRawBlob(rid, mime, initWidth, initHeight, new CrashUtils.Config());
@@ -2755,6 +2780,16 @@
             try {
                 MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(mime);
                 if (caps != null) {
+                    /* Add mainline skip to decoders in mainline module */
+                    if (isCodecInMainlineModule(info.getName())) {
+                        Log.i(TAG, "Skipping codec " + info.getName() +
+                                    " as it is part of mainline");
+                        continue;
+                    }
+                    if (info.isAlias()) {
+                        Log.i(TAG, "Skipping codec " + info.getName() + " as it is an alias");
+                        continue;
+                    }
                     matchingCodecs.add(info.getName());
                 }
             } catch (IllegalArgumentException e) {
@@ -2886,6 +2921,16 @@
             try {
                 MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(mime);
                 if (caps != null) {
+                    /* Add mainline skip to decoders in mainline module */
+                    if (isCodecInMainlineModule(info.getName())) {
+                        Log.i(TAG, "Skipping codec " + info.getName() +
+                                    " as it is part of mainline");
+                        continue;
+                    }
+                    if (info.isAlias()) {
+                        Log.i(TAG, "Skipping codec " + info.getName() + " as it is an alias");
+                        continue;
+                    }
                     matchingCodecs.add(info.getName());
                 }
             } catch (IllegalArgumentException e) {
@@ -3031,6 +3076,16 @@
             try {
                 MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(mime);
                 if (caps != null) {
+                    /* Add mainline skip to decoders in mainline module */
+                    if (isCodecInMainlineModule(info.getName())) {
+                        Log.i(TAG, "Skipping codec " + info.getName() +
+                                    " as it is part of mainline");
+                        continue;
+                    }
+                    if (info.isAlias()) {
+                        Log.i(TAG, "Skipping codec " + info.getName() + " as it is an alias");
+                        continue;
+                    }
                     matchingCodecs.add(info.getName());
                 }
             } catch (IllegalArgumentException e) {
diff --git a/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceTest.java b/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceTest.java
index c2af67a..314f29d 100644
--- a/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceTest.java
+++ b/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceTest.java
@@ -16,7 +16,6 @@
 package android.sharesheet.cts;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -49,6 +48,10 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -57,10 +60,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 /**
  * TODO: Add JavaDoc
  */
@@ -86,6 +85,7 @@
     private Instrumentation mInstrumentation;
     private UiAutomation mAutomation;
     public UiDevice mDevice;
+    private UiObject2 mSharesheet;
 
     private String mPkg, mExcludePkg, mActivityLabelTesterPkg, mIntentFilterLabelTesterPkg;
     private String mSharesheetPkg;
@@ -106,8 +106,8 @@
     private boolean mMeetsResolutionRequirements;
 
     /**
-     * To validate Sharesheet API and API behavior works as intended UI test sare required. It is
-     * impossible to know the how the Sharesheet UI will be modified by end partners so these tests
+     * To validate Sharesheet API and API behavior works as intended, UI tests are required. It is
+     * impossible to know how the Sharesheet UI will be modified by end partners, so these tests
      * attempt to assume use the minimum needed assumptions to make the tests work.
      *
      * We cannot assume a scrolling direction or starting point because of potential UI variations.
@@ -490,6 +490,7 @@
     private void launchSharesheet(Intent shareIntent) {
         mContext.startActivity(shareIntent);
         waitAndAssertPkgVisible(mSharesheetPkg);
+        mSharesheet = mDevice.findObject(By.pkg(mSharesheetPkg).depth(0));
         waitForIdle();
     }
 
@@ -599,11 +600,11 @@
     }
 
     private void waitAndAssertPkgVisible(String pkg) {
-        waitAndAssertFound(By.pkg(pkg).depth(0));
+        waitAndAssertFoundOnDevice(By.pkg(pkg).depth(0));
     }
 
     private void waitAndAssertPkgNotVisible(String pkg) {
-        waitAndAssertNotFound(By.pkg(pkg));
+        waitAndAssertNotFoundOnDevice(By.pkg(pkg));
     }
 
     private void waitAndAssertTextContains(String containsText) {
@@ -615,21 +616,37 @@
     }
 
     /**
-     * waitAndAssertFound will wait until UI defined by the selector is found. If it's never found,
-     * this will wait for the duration of the full timeout. Take care to call this method after
-     * reasonable steps are taken to ensure fast completion.
+     * waitAndAssertFound will wait until UI within sharesheet defined by the selector is found. If
+     * it's never found, this will wait for the duration of the full timeout. Take care to call this
+     * method after reasonable steps are taken to ensure fast completion.
      */
     private void waitAndAssertFound(BySelector selector) {
+        assertNotNull(mSharesheet.wait(Until.findObject(selector),
+                WAIT_AND_ASSERT_FOUND_TIMEOUT_MS));
+    }
+
+    /**
+     * Same as waitAndAssertFound but searching the entire device UI.
+     */
+    private void waitAndAssertFoundOnDevice(BySelector selector) {
         assertNotNull(mDevice.wait(Until.findObject(selector), WAIT_AND_ASSERT_FOUND_TIMEOUT_MS));
     }
 
     /**
-     * waitAndAssertNotFound waits for any visible UI to be hidden, validates that it's indeed gone
-     * without waiting more and returns. This means if the UI wasn't visible to start with the
-     * method will return without no timeout. Take care to call this method only once there's reason
-     * to think the UI is in the right state for testing.
+     * waitAndAssertNotFound waits for any visible UI within sharesheet to be hidden, validates that
+     * it's indeed gone without waiting more and returns. This means if the UI wasn't visible to
+     * start with the method will return without no timeout. Take care to call this method only once
+     * there's reason to think the UI is in the right state for testing.
      */
     private void waitAndAssertNotFound(BySelector selector) {
+        mSharesheet.wait(Until.gone(selector), WAIT_AND_ASSERT_NOT_FOUND_TIMEOUT_MS);
+        assertNull(mSharesheet.findObject(selector));
+    }
+
+    /**
+     * Same as waitAndAssertNotFound() but searching the entire device UI.
+     */
+    private void waitAndAssertNotFoundOnDevice(BySelector selector) {
         mDevice.wait(Until.gone(selector), WAIT_AND_ASSERT_NOT_FOUND_TIMEOUT_MS);
         assertNull(mDevice.findObject(selector));
     }
@@ -641,7 +658,7 @@
      * @return UiObject2 that can be used, for example, to execute a click
      */
     private UiObject2 findTextContains(String containsText) {
-        return mDevice.wait(Until.findObject(By.textContains(containsText)),
+        return mSharesheet.wait(Until.findObject(By.textContains(containsText)),
                 WAIT_AND_ASSERT_FOUND_TIMEOUT_MS);
     }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/DataProfileTest.java b/tests/tests/telephony/current/src/android/telephony/cts/DataProfileTest.java
index da2e01c..d592e0f 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/DataProfileTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/DataProfileTest.java
@@ -20,6 +20,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.os.Parcel;
@@ -319,7 +320,7 @@
         assertEquals(ApnSetting.PROTOCOL_IP, profile.getRoamingProtocolType());
         assertEquals(ApnSetting.TYPE_NONE, profile.getSupportedApnTypesBitmask());
         assertEquals(DataProfile.TYPE_COMMON, profile.getType());
-        assertFalse(profile.isEnabled());
+        assertTrue(profile.isEnabled());
         assertFalse(profile.isPersistent());
         assertFalse(profile.isPreferred());
         assertEquals(td, profile.getTrafficDescriptor());
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index e934b2a..137a43b 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -33,7 +33,6 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.annotation.Nullable;
-import android.app.AppOpsManager;
 import android.app.UiAutomation;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -50,7 +49,6 @@
 import android.os.Looper;
 import android.os.ParcelUuid;
 import android.os.PersistableBundle;
-import android.os.Process;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -680,20 +678,10 @@
                 (sm) -> sm.createSubscriptionGroup(subGroup));
 
         // Getting subscriptions in group.
-        List<SubscriptionInfo> infoList;
-        try {
-            mSm.getSubscriptionsInGroup(uuid);
-            fail("SecurityException should be thrown without USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER");
-        } catch (SecurityException ex) {
-            // Expected
-        }
-
-        // has the READ_PRIVILEGED_PHONE_STATE permission
-        infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
-                (sm) -> sm.getSubscriptionsInGroup(uuid), READ_PRIVILEGED_PHONE_STATE);
+        List<SubscriptionInfo> infoList = mSm.getSubscriptionsInGroup(uuid);
         assertNotNull(infoList);
         assertEquals(1, infoList.size());
-        assertEquals(uuid, infoList.get(0).getGroupUuid());
+        assertNull(infoList.get(0).getGroupUuid());
 
         infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
                 (sm) -> sm.getSubscriptionsInGroup(uuid));
@@ -710,36 +698,30 @@
         }
         availableInfoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
                 (sm) -> sm.getAvailableSubscriptionInfoList());
-        // has the USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER permission
-        try {
-            setIdentifierAccess(true);
-            if (availableInfoList.size() > 1) {
-                List<Integer> availableSubGroup = availableInfoList.stream()
-                        .map(info -> info.getSubscriptionId())
-                        .filter(subId -> subId != mSubId)
-                        .collect(Collectors.toList());
+        if (availableInfoList.size() > 1) {
+            List<Integer> availableSubGroup = availableInfoList.stream()
+                    .map(info -> info.getSubscriptionId())
+                    .filter(subId -> subId != mSubId)
+                    .collect(Collectors.toList());
 
-                ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
-                        (sm) -> sm.addSubscriptionsIntoGroup(availableSubGroup, uuid));
-
-                infoList = mSm.getSubscriptionsInGroup(uuid);
-                assertNotNull(infoList);
-                assertEquals(availableInfoList.size(), infoList.size());
-
-                ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
-                        (sm) -> sm.removeSubscriptionsFromGroup(availableSubGroup, uuid));
-            }
-
-            // Remove from subscription group with current sub Id.
             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
-                    (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
+                    (sm) -> sm.addSubscriptionsIntoGroup(availableSubGroup, uuid));
 
             infoList = mSm.getSubscriptionsInGroup(uuid);
             assertNotNull(infoList);
-            assertTrue(infoList.isEmpty());
-        } finally {
-            setIdentifierAccess(false);
+            assertEquals(availableInfoList.size(), infoList.size());
+
+            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
+                    (sm) -> sm.removeSubscriptionsFromGroup(availableSubGroup, uuid));
         }
+
+        // Remove from subscription group with current sub Id.
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
+                (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
+
+        infoList = mSm.getSubscriptionsInGroup(uuid);
+        assertNotNull(infoList);
+        assertTrue(infoList.isEmpty());
     }
 
     @Test
@@ -751,31 +733,23 @@
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
                 (sm) -> sm.addSubscriptionsIntoGroup(subGroup, uuid));
 
-        List<SubscriptionInfo> infoList;
-        try {
-            mSm.getSubscriptionsInGroup(uuid);
-            fail("SecurityException should be thrown without USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER");
-        } catch (SecurityException ex) {
-            // Expected
-        }
-
         // Getting subscriptions in group.
-        try {
-            setIdentifierAccess(true);
-            infoList = mSm.getSubscriptionsInGroup(uuid);
-            assertNotNull(infoList);
-            assertEquals(1, infoList.size());
-            assertEquals(uuid, infoList.get(0).getGroupUuid());
-        } finally {
-            setIdentifierAccess(false);
-        }
+        List<SubscriptionInfo> infoList = mSm.getSubscriptionsInGroup(uuid);
+        assertNotNull(infoList);
+        assertEquals(1, infoList.size());
+        assertNull(infoList.get(0).getGroupUuid());
+
+        infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
+                (sm) -> sm.getSubscriptionsInGroup(uuid));
+        assertNotNull(infoList);
+        assertEquals(1, infoList.size());
+        assertEquals(uuid, infoList.get(0).getGroupUuid());
 
         // Remove from subscription group with current sub Id.
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
                 (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
 
-        infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
-                (sm) -> sm.getSubscriptionsInGroup(uuid));
+        infoList = mSm.getSubscriptionsInGroup(uuid);
         assertNotNull(infoList);
         assertTrue(infoList.isEmpty());
     }
@@ -1485,13 +1459,4 @@
 
         return validCarrier && validNetworkType && validCapabilities;
     }
-
-    private void setIdentifierAccess(boolean allowed) {
-        String op = AppOpsManager.OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER;
-        AppOpsManager appOpsManager = InstrumentationRegistry.getContext().getSystemService(
-                AppOpsManager.class);
-        int mode = allowed ? AppOpsManager.MODE_ALLOWED : AppOpsManager.opToDefaultMode(op);
-        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
-                appOpsManager, (appOps) -> appOps.setUidMode(op, Process.myUid(), mode));
-    }
 }
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 f3b2229..e073153 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -337,36 +337,47 @@
     }
 
     private int mTestSub;
-    private TelephonyManagerTest.CarrierConfigReceiver mReceiver;
     private int mRadioVersion;
     private boolean mIsAllowedNetworkTypeChanged;
     private Map<Integer, Long> mAllowedNetworkTypesList = new HashMap<>();
 
-    private static class CarrierConfigReceiver extends BroadcastReceiver {
+    private class CarrierPrivilegeChangeMonitor implements AutoCloseable {
+        // CarrierPrivilegesCallback will be triggered upon registration. Filter the first callback
+        // here since we really care of the *change* of carrier privileges instead of the content
+        private boolean mHasSentPrivilegeChangeCallback = false;
         private CountDownLatch mLatch = new CountDownLatch(1);
-        private final int mSubId;
+        private final TelephonyManager.CarrierPrivilegesCallback mCarrierPrivilegesCallback;
 
-        CarrierConfigReceiver(int subId) {
-            mSubId = subId;
+        CarrierPrivilegeChangeMonitor() {
+            mCarrierPrivilegesCallback = (privilegedPackageNames, privilegedUids) -> {
+                // Ignore the first callback which is triggered upon registration
+                if (!mHasSentPrivilegeChangeCallback) {
+                    mHasSentPrivilegeChangeCallback = true;
+                    return;
+                }
+                mLatch.countDown();
+            };
+
+            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+                    (tm) -> tm.registerCarrierPrivilegesCallback(
+                            SubscriptionManager.getSlotIndex(mTestSub),
+                            getContext().getMainExecutor(),
+                            mCarrierPrivilegesCallback));
         }
 
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
-                int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
-                        SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-                if (mSubId == subId) {
-                    mLatch.countDown();
-                }
+        public void waitForCarrierPrivilegeChanged() throws Exception {
+            if (!mLatch.await(5, TimeUnit.SECONDS)) {
+                throw new IllegalStateException("Failed to update carrier privileges");
             }
         }
 
-        void clearQueue() {
-            mLatch = new CountDownLatch(1);
-        }
-
-        void waitForCarrierConfigChanged() throws Exception {
-            mLatch.await(5000, TimeUnit.MILLISECONDS);
+        @Override
+        public void close() throws Exception {
+            if(mTelephonyManager != null) {
+                ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+                        (tm) -> tm.unregisterCarrierPrivilegesCallback(
+                                mCarrierPrivilegesCallback));
+            }
         }
     }
 
@@ -383,12 +394,9 @@
         mTestSub = SubscriptionManager.getDefaultSubscriptionId();
         mTelephonyManager = getContext().getSystemService(TelephonyManager.class)
                 .createForSubscriptionId(mTestSub);
-        mReceiver = new CarrierConfigReceiver(mTestSub);
         Pair<Integer, Integer> radioVersion = mTelephonyManager.getRadioHalVersion();
         mRadioVersion = makeRadioVersion(radioVersion.first, radioVersion.second);
         IntentFilter filter = new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
-        // ACTION_CARRIER_CONFIG_CHANGED is sticky, so we will get a callback right away.
-        getContext().registerReceiver(mReceiver, filter);
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .adoptShellPermissionIdentity("android.permission.READ_PHONE_STATE");
         saveAllowedNetworkTypesForAllReasons();
@@ -400,10 +408,6 @@
             // unregister the listener
             mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);
         }
-        if (mReceiver != null) {
-            getContext().unregisterReceiver(mReceiver);
-            mReceiver = null;
-        }
         if (mIsAllowedNetworkTypeChanged) {
             recoverAllowedNetworkType();
         }
@@ -494,7 +498,7 @@
             // purge the certs in carrierConfigs first
             carrierConfig.putStringArray(
                     CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY, new String[]{});
-            overrideCarrierConfig(carrierConfig);
+            changeCarrierPrivileges(false, carrierConfig);
             // verify we don't have privilege through carrierConfigs or Uicc
             assertFalse(mTelephonyManager.hasCarrierPrivileges());
 
@@ -503,25 +507,34 @@
                     new String[]{mSelfCertHash});
 
             // verify we now have privilege after adding certificate to carrierConfigs
-            overrideCarrierConfig(carrierConfig);
+            changeCarrierPrivileges(true, carrierConfig);
             assertTrue(mTelephonyManager.hasCarrierPrivileges());
         } finally {
             // purge the newly added certificate
             carrierConfig.putStringArray(
                     CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY, new String[]{});
-            // carrierConfig.remove(CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY);
-            overrideCarrierConfig(carrierConfig);
-
+            changeCarrierPrivileges(false, carrierConfig);
             // verify we no longer have privilege after removing certificate
             assertFalse(mTelephonyManager.hasCarrierPrivileges());
         }
     }
 
+    private void changeCarrierPrivileges(boolean gain, PersistableBundle carrierConfig)
+            throws Exception {
+        if (mTelephonyManager.hasCarrierPrivileges() == gain) {
+            Log.w(TAG, "Carrier privileges already " + (gain ? "granted" : "revoked"));
+            return;
+        }
+
+        try(CarrierPrivilegeChangeMonitor monitor = new CarrierPrivilegeChangeMonitor()) {
+            overrideCarrierConfig(carrierConfig);
+            monitor.waitForCarrierPrivilegeChanged();
+        }
+    }
+
     private void overrideCarrierConfig(PersistableBundle bundle) throws Exception {
-        mReceiver.clearQueue();
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mCarrierConfigManager,
                 (cm) -> cm.overrideConfig(mTestSub, bundle));
-        mReceiver.waitForCarrierConfigChanged();
     }
 
     public static void grantLocationPermissions() {
@@ -1259,16 +1272,14 @@
     public void testSetSystemSelectionChannels() {
         assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
 
-        List<RadioAccessSpecifier> channels = Collections.emptyList();
-        if (mRadioVersion >= RADIO_HAL_VERSION_1_6) {
-            try {
-                channels = ShellIdentityUtils.invokeMethodWithShellPermissions(
-                        mTelephonyManager, TelephonyManager::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;
-            }
+        List<RadioAccessSpecifier> channels;
+        try {
+            channels = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                    mTelephonyManager, TelephonyManager::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;
         }
 
         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1);
@@ -5032,25 +5043,47 @@
     @Test
     public void testSimSlotMapping() {
         assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION));
-
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity("android.permission.READ_PRIVILEGED_PHONE_STATE");
+        Collection<UiccSlotMapping> simSlotMapping = mTelephonyManager.getSimSlotMapping();
+        // passing slotMapping combination
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .adoptShellPermissionIdentity("android.permission.MODIFY_PHONE_STATE");
-        // passing slotMapping combination
-        UiccSlotMapping slotMapping1 = new UiccSlotMapping(0, 1, 1);
-        UiccSlotMapping slotMapping2 = new UiccSlotMapping(1, 0, 0);
+        try {
+            mTelephonyManager.setSimSlotMapping(simSlotMapping);
+        } catch (IllegalArgumentException e) {
+            fail("Not Expected Fail, Error in setSimSlotMapping :" + e);
+        }
+
         List<UiccSlotMapping> slotMappingList = new ArrayList<>();
+        // invalid logicalSlotIndex - Fail
+        UiccSlotMapping slotMapping1 = new UiccSlotMapping(
+                TelephonyManager.DEFAULT_PORT_INDEX, /*portIndex*/
+                1, /*physicalSlotIndex*/
+                SubscriptionManager.INVALID_PHONE_INDEX /*logicalSlotIndex*/);
+        UiccSlotMapping slotMapping2 = new UiccSlotMapping(
+                TelephonyManager.DEFAULT_PORT_INDEX, /*portIndex*/
+                0, /*physicalSlotIndex*/
+                0 /*logicalSlotIndex*/);
         slotMappingList.add(slotMapping1);
         slotMappingList.add(slotMapping2);
         try {
             mTelephonyManager.setSimSlotMapping(slotMappingList);
-        } catch (Exception e) {
-            fail("Not Expected Fail, Error in setSimSlotMapping :" + e);
+            fail("Expected IllegalStateException, invalid UiccSlotMapping data found");
+        } catch (IllegalStateException e) {
+            //expected
         }
         slotMappingList.clear();
 
         // Duplicate logicalSlotIndex - Fail
-        UiccSlotMapping slotMapping3 = new UiccSlotMapping(0, 1, 0);
-        UiccSlotMapping slotMapping4 = new UiccSlotMapping(1, 0, 0);
+        UiccSlotMapping slotMapping3 = new UiccSlotMapping(
+                TelephonyManager.DEFAULT_PORT_INDEX, /*portIndex*/
+                1, /*physicalSlotIndex*/
+                0 /*logicalSlotIndex*/);
+        UiccSlotMapping slotMapping4 = new UiccSlotMapping(
+                TelephonyManager.DEFAULT_PORT_INDEX, /*portIndex*/
+                0, /*physicalSlotIndex*/
+                0 /*logicalSlotIndex*/);
         slotMappingList.add(slotMapping3);
         slotMappingList.add(slotMapping4);
         try {
@@ -5062,8 +5095,14 @@
         slotMappingList.clear();
 
         // Duplicate {portIndex+physicalSlotIndex} - Fail
-        UiccSlotMapping slotMapping5 = new UiccSlotMapping(0, 1, 0);
-        UiccSlotMapping slotMapping6 = new UiccSlotMapping(0, 1, 1);
+        UiccSlotMapping slotMapping5 = new UiccSlotMapping(
+                TelephonyManager.DEFAULT_PORT_INDEX, /*portIndex*/
+                1, /*physicalSlotIndex*/
+                0 /*logicalSlotIndex*/);
+        UiccSlotMapping slotMapping6 = new UiccSlotMapping(
+                TelephonyManager.DEFAULT_PORT_INDEX, /*portIndex*/
+                1, /*physicalSlotIndex*/
+                1 /*logicalSlotIndex*/);
         slotMappingList.add(slotMapping5);
         slotMappingList.add(slotMapping6);
         try {
@@ -5075,8 +5114,14 @@
         slotMappingList.clear();
 
         // Duplicate {portIndex+physicalSlotIndex+logicalSlotIndex} - Fail
-        UiccSlotMapping slotMapping7 = new UiccSlotMapping(0, 1, 0);
-        UiccSlotMapping slotMapping8 = new UiccSlotMapping(0, 1, 0);
+        UiccSlotMapping slotMapping7 = new UiccSlotMapping(
+                TelephonyManager.DEFAULT_PORT_INDEX, /*portIndex*/
+                1, /*physicalSlotIndex*/
+                0 /*logicalSlotIndex*/);
+        UiccSlotMapping slotMapping8 = new UiccSlotMapping(
+                TelephonyManager.DEFAULT_PORT_INDEX, /*portIndex*/
+                1, /*physicalSlotIndex*/
+                0 /*logicalSlotIndex*/);
         slotMappingList.add(slotMapping7);
         slotMappingList.add(slotMapping8);
         try {
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java
index 76d615d..1c20e9a 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java
@@ -754,6 +754,77 @@
     }
 
     @Test
+    public void testOutGoingIncomingMultiCallAcceptTerminate() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        bindImsService();
+        mServiceCallBack = new ServiceCallBack();
+        InCallServiceStateValidator.setCallbacks(mServiceCallBack);
+
+        TelecomManager telecomManager = (TelecomManager) InstrumentationRegistry
+                .getInstrumentation().getContext().getSystemService(Context.TELECOM_SERVICE);
+
+        final Uri imsUri = Uri.fromParts(PhoneAccount.SCHEME_TEL, String.valueOf(++sCounter), null);
+        Bundle extras = new Bundle();
+
+        // Place outgoing call
+        telecomManager.placeCall(imsUri, extras);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_ADDED, WAIT_FOR_CALL_STATE));
+
+        Call moCall = getCall(mCurrentCallId);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_DIALING, WAIT_FOR_CALL_STATE));
+
+        TestImsCallSessionImpl moCallSession = sServiceConnector.getCarrierService()
+                .getMmTelFeature().getImsCallsession();
+        isCallActive(moCall, moCallSession);
+        assertTrue("Call is not in Active State", (moCall.getDetails().getState()
+                == Call.STATE_ACTIVE));
+
+        extras.putBoolean("android.telephony.ims.feature.extra.IS_USSD", false);
+        extras.putBoolean("android.telephony.ims.feature.extra.IS_UNKNOWN_CALL", false);
+        extras.putString("android:imsCallID",  String.valueOf(++sCounter));
+        extras.putLong("android:phone_id", 123456);
+        sServiceConnector.getCarrierService().getMmTelFeature().onIncomingCallReceived(extras);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_ADDED, WAIT_FOR_CALL_STATE));
+        TestImsCallSessionImpl mtCallSession = sServiceConnector.getCarrierService()
+                .getMmTelFeature().getImsCallsession();
+        // do not generate an auto hold response here, need to simulate a timing issue.
+        moCallSession.addTestType(TestImsCallSessionImpl.TEST_TYPE_HOLD_NO_RESPONSE);
+
+        Call mtCall = null;
+        if (mCurrentCallId != null) {
+            mtCall = getCall(mCurrentCallId);
+            if (mtCall.getDetails().getState() == Call.STATE_RINGING) {
+                callingTestLatchCountdown(LATCH_WAIT, WAIT_FOR_CALL_CONNECT);
+                mtCall.answer(0);
+            }
+        }
+
+        callingTestLatchCountdown(LATCH_WAIT, WAIT_FOR_CALL_CONNECT);
+        // simulate user hanging up the MT call at the same time as accept.
+        mtCallSession.terminateIncomingCall();
+        isCallDisconnected(mtCall, mtCallSession);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_REMOVED, WAIT_FOR_CALL_STATE));
+
+        // then send hold response, which should be reversed, since MT call was disconnected.
+        moCallSession.sendHoldResponse();
+
+        // MO call should move back to active.
+        isCallActive(moCall, moCallSession);
+        assertTrue("Call is not in Active State", (moCall.getDetails().getState()
+                == Call.STATE_ACTIVE));
+
+        moCall.disconnect();
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_DISCONNECTING, WAIT_FOR_CALL_STATE));
+        isCallDisconnected(moCall, moCallSession);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_REMOVED, WAIT_FOR_CALL_STATE));
+
+        waitForUnboundService();
+    }
+
+    @Test
     public void testOutGoingCallSwap() throws Exception {
         if (!ImsUtils.shouldTestImsService()) {
             return;
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsCallSessionImpl.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsCallSessionImpl.java
index d41f98a..0486cf8 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsCallSessionImpl.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsCallSessionImpl.java
@@ -61,12 +61,13 @@
         }
     }
 
-    public static final int TEST_TYPE_NONE = 0x00000000;
-    public static final int TEST_TYPE_MO_ANSWER = 0x00000001;
-    public static final int TEST_TYPE_MO_FAILED = 0x00000002;
-    public static final int TEST_TYPE_HOLD_FAILED = 0x00000004;
-    public static final int TEST_TYPE_RESUME_FAILED = 0x00000008;
-    public static final int TEST_TYPE_CONFERENCE_FAILED = 0x00000010;
+    public static final int TEST_TYPE_NONE = 0;
+    public static final int TEST_TYPE_MO_ANSWER = 1 << 0;
+    public static final int TEST_TYPE_MO_FAILED = 1 << 1;
+    public static final int TEST_TYPE_HOLD_FAILED = 1 << 2;
+    public static final int TEST_TYPE_RESUME_FAILED = 1 << 3;
+    public static final int TEST_TYPE_CONFERENCE_FAILED = 1 << 4;
+    public static final int TEST_TYPE_HOLD_NO_RESPONSE = 1 << 5;
 
     private int mTestType = TEST_TYPE_NONE;
     private boolean mIsOnHold = false;
@@ -317,29 +318,26 @@
         setState(ImsCallSessionImplBase.State.TERMINATED);
     }
 
-    // End the Incoming Call from local side after accept.
+    // End the Incoming Call
     public void terminateIncomingCall() {
-        int state = getState();
-        if (state == ImsCallSessionImplBase.State.ESTABLISHED) {
-            postAndRunTask(() -> {
-                try {
-                    if (mListener == null) {
-                        return;
-                    }
-                    Log.d(LOG_TAG, "invokeTerminated mCallId = " + mCallId);
-                    mListener.callSessionTerminated(getReasonInfo(
-                            ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE,
-                            ImsReasonInfo.CODE_UNSPECIFIED));
-                } catch (Throwable t) {
-                    Throwable cause = t.getCause();
-                    if (t instanceof DeadObjectException
-                            || (cause != null && cause instanceof DeadObjectException)) {
-                        fail("starting cause Throwable to be thrown: " + t);
-                    }
+        postAndRunTask(() -> {
+            try {
+                if (mListener == null) {
+                    return;
                 }
-            });
-            setState(ImsCallSessionImplBase.State.TERMINATED);
-        }
+                Log.d(LOG_TAG, "invokeTerminated mCallId = " + mCallId);
+                mListener.callSessionTerminated(getReasonInfo(
+                        ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE,
+                        ImsReasonInfo.CODE_UNSPECIFIED));
+            } catch (Throwable t) {
+                Throwable cause = t.getCause();
+                if (t instanceof DeadObjectException
+                        || (cause != null && cause instanceof DeadObjectException)) {
+                    fail("starting cause Throwable to be thrown: " + t);
+                }
+            }
+        });
+        setState(ImsCallSessionImplBase.State.TERMINATED);
     }
 
     @Override
@@ -361,24 +359,7 @@
             }
             setState(ImsCallSessionImplBase.State.RENEGOTIATING);
 
-            postAndRunTask(() -> {
-                imsCallSessionLatchCountdown(LATCH_WAIT, WAIT_FOR_ESTABLISHING);
-                try {
-                    if (mListener == null) {
-                        return;
-                    }
-                    Log.d(LOG_TAG, "invokeHeld mCallId = " + mCallId);
-                    mListener.callSessionHeld(mCallProfile);
-                    mIsOnHold = true;
-                } catch (Throwable t) {
-                    Throwable cause = t.getCause();
-                    if (t instanceof DeadObjectException
-                            || (cause != null && cause instanceof DeadObjectException)) {
-                        fail("starting cause Throwable to be thrown: " + t);
-                    }
-                }
-            });
-            setState(ImsCallSessionImplBase.State.ESTABLISHED);
+            if (!isTestType(TEST_TYPE_HOLD_NO_RESPONSE)) sendHoldResponse();
         }
     }
 
@@ -583,6 +564,30 @@
         mListener.callSessionConferenceStateUpdated(confState);
     }
 
+    /**
+     * Send a hold response for this listener.
+     */
+    public void sendHoldResponse() {
+        postAndRunTask(() -> {
+            imsCallSessionLatchCountdown(LATCH_WAIT, WAIT_FOR_ESTABLISHING);
+            try {
+                if (mListener == null) {
+                    return;
+                }
+                Log.d(LOG_TAG, "invokeHeld mCallId = " + mCallId);
+                mListener.callSessionHeld(mCallProfile);
+                mIsOnHold = true;
+            } catch (Throwable t) {
+                Throwable cause = t.getCause();
+                if (t instanceof DeadObjectException
+                        || (cause != null && cause instanceof DeadObjectException)) {
+                    fail("starting cause Throwable to be thrown: " + t);
+                }
+            }
+        });
+        setState(ImsCallSessionImplBase.State.ESTABLISHED);
+    }
+
     public Bundle createConferenceParticipant(String user, String endpoint,
             String displayText, String status, int sipStatusCode) {
         Bundle participant = new Bundle();
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
index 52b0921..ba634bc 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
@@ -449,8 +449,10 @@
         mInstrumentation.waitForIdleSync();
         assertTrue(mTvView.isFocused());
 
-        verifyKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_GUIDE), unhandledEvent);
-        verifyKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_GUIDE), unhandledEvent);
+        verifyKeyEvent(
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BUTTON_16), unhandledEvent);
+        verifyKeyEvent(
+                new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BUTTON_16), unhandledEvent);
     }
 
     public void testConnectionFailed() throws Throwable {
diff --git a/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java b/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
index a7a3a6a..107820f 100644
--- a/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
+++ b/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
@@ -212,7 +212,7 @@
         assertTrue(swapBuffers > 0);
         assertTrue(intended_vsync > 0);
         assertTrue(vsync > 0);
-        assertTrue(gpuDuration > 0);
+        assertTrue(gpuDuration >= 0);
         assertTrue(totalDuration > 0);
         assertTrue(deadline > 0);
 
diff --git a/tests/tests/virtualdevice/src/android/virtualdevice/cts/CreateVirtualDisplayTest.java b/tests/tests/virtualdevice/src/android/virtualdevice/cts/CreateVirtualDisplayTest.java
index b5eb22b..6027c9e 100644
--- a/tests/tests/virtualdevice/src/android/virtualdevice/cts/CreateVirtualDisplayTest.java
+++ b/tests/tests/virtualdevice/src/android/virtualdevice/cts/CreateVirtualDisplayTest.java
@@ -199,9 +199,6 @@
                     /* flags= */ 0,
                     Runnable::run,
                     mVirtualDisplayCallback));
-            // TODO(b/230544802) - for now, use sleep to avoid deadlock when creating multiple
-            //  displays in quick succession
-            Thread.sleep(50);
         }
 
         // Releasing several displays in quick succession should not cause deadlock
diff --git a/tests/tests/wifi/AndroidTest.xml b/tests/tests/wifi/AndroidTest.xml
index 5da40ea..efbfd45 100644
--- a/tests/tests/wifi/AndroidTest.xml
+++ b/tests/tests/wifi/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
     <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.wifi.apex" />
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tools/cts-tradefed/res/config/cts-automated.xml b/tools/cts-tradefed/res/config/cts-automated.xml
index 80bcea7..cde00b23 100644
--- a/tools/cts-tradefed/res/config/cts-automated.xml
+++ b/tools/cts-tradefed/res/config/cts-automated.xml
@@ -32,4 +32,6 @@
     <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
     <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
 
+    <!-- Main CTS remains single device until decided otherwise for default automation -->
+    <option name="multi-devices-modules" value="EXCLUDE_ALL" />
 </configuration>
diff --git a/tools/cts-tradefed/res/config/cts-common.xml b/tools/cts-tradefed/res/config/cts-common.xml
index 47f3637..e1152c7 100644
--- a/tools/cts-tradefed/res/config/cts-common.xml
+++ b/tools/cts-tradefed/res/config/cts-common.xml
@@ -19,8 +19,8 @@
     <option name="compatibility:run-suite-tag" value="cts" />
     <!-- Enable module parameterization to run instant_app modules in main CTS -->
     <option name="compatibility:enable-parameterized-modules" value="true" />
-    <!-- Main CTS remains single device until decided otherwise -->
-    <option name="multi-devices-modules" value="EXCLUDE_ALL" />
+    <!-- Main CTS executes both single and multi-devices in the same plan during sharding -->
+    <option name="multi-devices-modules" value="RUN" />
 
     <include name="cts-preconditions" />
     <include name="cts-system-checkers" />
diff --git a/tools/cts-tradefed/res/config/cts-exclude.xml b/tools/cts-tradefed/res/config/cts-exclude.xml
index 77d6038..3d66c33 100644
--- a/tools/cts-tradefed/res/config/cts-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-exclude.xml
@@ -28,9 +28,6 @@
          tests into CTS, but until then, they should be excluded. -->
     <option name="compatibility:exclude-filter" value="CtsTestHarnessModeTestCases" />
 
-    <!-- Exclude multi device test cases - work in progress -->
-    <option name="compatibility:exclude-filter" value="CtsWifiAwareTestCases" />
-
     <!-- Exclude downstreaming tests from CTS, i.e. tests added after the
          first major release for this API level (They are pulled into GTS
          instead). -->
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index 1da1953..22ec7d0 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -258,4 +258,13 @@
     <!-- b/182630972, b/214019488 -->
     <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.PinnedStackTests#testEnterPipWithMinimalSize" />
 
+    <!-- b/198021503 -->
+    <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.StorageHostTest#testFullDisk" />
+
+    <!-- b/216546060 -->
+    <option name="compatibility:exclude-filter" value="CtsFragmentTestCases android.fragment.cts.FragmentAnimatorTest#saveWhileAnimatingAway" />
+
+    <!-- b/216553645 -->
+    <option name="compatibility:exclude-filter" value="CtsKeystoreTestCases android.keystore.cts.ECDSASignatureTest#testNONEwithECDSATruncatesInputToFieldSize" />
+  
 </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 cbd7611..a6e59ac 100644
--- a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
@@ -112,4 +112,6 @@
     <option name="compatibility:exclude-filter" value="CtsHdmiCecHostTestCases android.hdmicec.cts.tv.HdmiCecRoutingControlTest" />
     <option name="compatibility:exclude-filter" value="CtsHdmiCecHostTestCases android.hdmicec.cts.tv.HdmiCecTvOneTouchPlayTest" />
 
+    <!-- b/234409652 Stable API does not exist to enforce this requirement on variable geometry devices -->
+    <option name="compatibility:exclude-filter" value="CtsCameraTestCases android.hardware.camera2.cts.ExtendedCameraCharacteristicsTest#testCameraOrientationAlignedWithDevice"/>
 </configuration>
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
index a4998e9..ed45728 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
@@ -141,6 +141,7 @@
             "com.drawelements.deqp.runner.DeqpTestRunner",
             // Tradefed runners
             "com.android.tradefed.testtype.AndroidJUnitTest",
+            "com.android.tradefed.testtype.ArtRunTest",
             "com.android.tradefed.testtype.HostTest",
             "com.android.tradefed.testtype.GTest",
             "com.android.tradefed.testtype.mobly.MoblyBinaryHostTest"