Merge "[cts] test uid in PackageInstallerV2 metrics" into sc-dev
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__arm_CtsShimPrivUpgradeWrongSHA_apk.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__arm_CtsShimPrivUpgradeWrongSHA_apk.asciipb
index ae658b4..57bf63b 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__arm_CtsShimPrivUpgradeWrongSHA_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__arm_CtsShimPrivUpgradeWrongSHA_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/CtsShimPrivUpgradeWrongSHA.apk"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__arm_CtsShimPrivUpgrade_apk.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__arm_CtsShimPrivUpgrade_apk.asciipb
index 0ec2b3f..9e44013 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__arm_CtsShimPrivUpgrade_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__arm_CtsShimPrivUpgrade_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/CtsShimPrivUpgrade.apk"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__x86_CtsShimPrivUpgradeWrongSHA_apk.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__x86_CtsShimPrivUpgradeWrongSHA_apk.asciipb
index 141ae82..556f08d 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__x86_CtsShimPrivUpgradeWrongSHA_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__x86_CtsShimPrivUpgradeWrongSHA_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/CtsShimPrivUpgradeWrongSHA.apk"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__x86_CtsShimPrivUpgrade_apk.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__x86_CtsShimPrivUpgrade_apk.asciipb
index 0b2017c..5015040 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__x86_CtsShimPrivUpgrade_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_appsecurity_test-apps_PrivilegedUpdateApp_apk__x86_CtsShimPrivUpgrade_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/CtsShimPrivUpgrade.apk"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v1_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v1_apex.asciipb
index 779dddb..d3d9a95 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v1_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v1_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v1.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_additional_file_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_additional_file_apex.asciipb
index 65ba29a..e328379 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_additional_file_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_additional_file_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_additional_file.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_additional_folder_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_additional_folder_apex.asciipb
index 872b470..8483625 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_additional_folder_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_additional_folder_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_additional_folder.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_apex.asciipb
index c372928..f478e11 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_apk_in_apex_sdk_target_p_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_apk_in_apex_sdk_target_p_apex.asciipb
index f4fd435..c92a9a9 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_apk_in_apex_sdk_target_p_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_apk_in_apex_sdk_target_p_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_different_certificate_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_different_certificate_apex.asciipb
index 06f779e..96db91b 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_different_certificate_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_different_certificate_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_different_certificate.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_different_package_name_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_different_package_name_apex.asciipb
index 88879d4..71f21c3 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_different_package_name_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_different_package_name_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_different_package_name.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_no_hashtree_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_no_hashtree_apex.asciipb
index 0009342..49618a0 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_no_hashtree_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_no_hashtree_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_no_hashtree.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_sdk_target_p_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_sdk_target_p_apex.asciipb
index 6151ae3..2502dc6 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_sdk_target_p_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_sdk_target_p_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_sdk_target_p.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_sign_payload_with_different_key_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_sign_payload_with_different_key_apex.asciipb
new file mode 100644
index 0000000..ab51f93
--- /dev/null
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_sign_payload_with_different_key_apex.asciipb
@@ -0,0 +1,12 @@
+drops {
+  android_build_drop {
+    build_id: "7351002"
+    target: "CtsShim"
+    source_file: "aosp_arm64/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex"
+  }
+  dest_file: "hostsidetests/stagedinstall/testdata/apex//arm/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex"
+  version: ""
+  version_group: ""
+  git_project: "platform/cts"
+  git_branch: "sc-dev"
+}
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_signed_bob_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_signed_bob_apex.asciipb
index 378cbdb..9aaa75f 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_signed_bob_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_signed_bob_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_signed_bob.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_signed_bob_rot_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_signed_bob_rot_apex.asciipb
index 48e5ed6..2f884a1 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_signed_bob_rot_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_signed_bob_rot_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_signed_bob_rot.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_signed_bob_rot_rollback_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_signed_bob_rot_rollback_apex.asciipb
index 52ebaf0..9c7f872 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_signed_bob_rot_rollback_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_signed_bob_rot_rollback_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_unsigned_payload_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_unsigned_payload_apex.asciipb
index 97f78b3..c8b6903 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_unsigned_payload_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_unsigned_payload_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_unsigned_payload.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_with_post_install_hook_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_with_post_install_hook_apex.asciipb
index 437ff2b..ce54bd4 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_with_post_install_hook_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_with_post_install_hook_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_with_post_install_hook.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_with_pre_install_hook_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_with_pre_install_hook_apex.asciipb
index cc573a4..8bbe71d 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_with_pre_install_hook_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_with_pre_install_hook_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_with_pre_install_hook.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_without_apk_in_apex_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_without_apk_in_apex_apex.asciipb
index ae0243f..6ae0fc0 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_without_apk_in_apex_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_without_apk_in_apex_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_without_apk_in_apex.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_wrong_sha_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_wrong_sha_apex.asciipb
index d043084..a21a5ec 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_wrong_sha_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_wrong_sha_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v2_wrong_sha.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_apex.asciipb
index 3c67ecb..aead21f 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v3.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_signed_bob_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_signed_bob_apex.asciipb
index 3d78040..6eb4002 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_signed_bob_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_signed_bob_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v3_signed_bob.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_signed_bob_rot_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_signed_bob_rot_apex.asciipb
index e3181b2..3c24063 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_signed_bob_rot_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_signed_bob_rot_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/com.android.apex.cts.shim.v3_signed_bob_rot.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v1_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v1_apex.asciipb
index 0d7a7ad..ce15d76 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v1_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v1_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v1.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_additional_file_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_additional_file_apex.asciipb
index 98537ce..be46c3d 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_additional_file_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_additional_file_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_additional_file.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_additional_folder_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_additional_folder_apex.asciipb
index 7a3bb1f..b529bf8 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_additional_folder_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_additional_folder_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_additional_folder.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_apex.asciipb
index d2a0443..fd12f2a 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_apk_in_apex_sdk_target_p_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_apk_in_apex_sdk_target_p_apex.asciipb
index 922786e..65deb79 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_apk_in_apex_sdk_target_p_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_apk_in_apex_sdk_target_p_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_different_certificate_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_different_certificate_apex.asciipb
index bb924c9..6a70aa4 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_different_certificate_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_different_certificate_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_different_certificate.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_different_package_name_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_different_package_name_apex.asciipb
index 0d881f4..f31c25a 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_different_package_name_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_different_package_name_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_different_package_name.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_no_hashtree_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_no_hashtree_apex.asciipb
index 18032c2..7216913 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_no_hashtree_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_no_hashtree_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_no_hashtree.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_sdk_target_p_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_sdk_target_p_apex.asciipb
index f9d23f7..bf59f43 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_sdk_target_p_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_sdk_target_p_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_sdk_target_p.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_sign_payload_with_different_key_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_sign_payload_with_different_key_apex.asciipb
new file mode 100644
index 0000000..10bc505
--- /dev/null
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_sign_payload_with_different_key_apex.asciipb
@@ -0,0 +1,12 @@
+drops {
+  android_build_drop {
+    build_id: "7351002"
+    target: "CtsShim"
+    source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex"
+  }
+  dest_file: "hostsidetests/stagedinstall/testdata/apex//x86/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex"
+  version: ""
+  version_group: ""
+  git_project: "platform/cts"
+  git_branch: "sc-dev"
+}
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_signed_bob_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_signed_bob_apex.asciipb
index f3638c65..5b04c31 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_signed_bob_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_signed_bob_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_signed_bob.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_signed_bob_rot_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_signed_bob_rot_apex.asciipb
index b9a1e22..e32d6c8 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_signed_bob_rot_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_signed_bob_rot_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_signed_bob_rot.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_signed_bob_rot_rollback_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_signed_bob_rot_rollback_apex.asciipb
index 9d69dff..9dde059 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_signed_bob_rot_rollback_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_signed_bob_rot_rollback_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_unsigned_payload_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_unsigned_payload_apex.asciipb
index a056b2f..a393cdb 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_unsigned_payload_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_unsigned_payload_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_unsigned_payload.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_with_post_install_hook_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_with_post_install_hook_apex.asciipb
index 2d181f0..a7811ac 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_with_post_install_hook_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_with_post_install_hook_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_with_post_install_hook.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_with_pre_install_hook_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_with_pre_install_hook_apex.asciipb
index b0bc1f9..71c1b15 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_with_pre_install_hook_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_with_pre_install_hook_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_with_pre_install_hook.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_without_apk_in_apex_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_without_apk_in_apex_apex.asciipb
index 48fac6c..aaad0cf 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_without_apk_in_apex_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_without_apk_in_apex_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_without_apk_in_apex.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_wrong_sha_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_wrong_sha_apex.asciipb
index 457f945..4408eee 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_wrong_sha_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_wrong_sha_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_wrong_sha.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_apex.asciipb
index 58c8864..a650f82 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v3.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_signed_bob_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_signed_bob_apex.asciipb
index c73132c..fecd548 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_signed_bob_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_signed_bob_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v3_signed_bob.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_signed_bob_rot_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_signed_bob_rot_apex.asciipb
index e295e80..d3a2473e 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_signed_bob_rot_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_signed_bob_rot_apex.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/com.android.apex.cts.shim.v3_signed_bob_rot.apex"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apk_CtsShimTargetPSdk__arm_CtsShimTargetPSdk_apk.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apk_CtsShimTargetPSdk__arm_CtsShimTargetPSdk_apk.asciipb
index f5f8566..d69ae9e 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apk_CtsShimTargetPSdk__arm_CtsShimTargetPSdk_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apk_CtsShimTargetPSdk__arm_CtsShimTargetPSdk_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/CtsShimTargetPSdk.apk"
   }
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apk_CtsShimTargetPSdk__x86_CtsShimTargetPSdk_apk.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apk_CtsShimTargetPSdk__x86_CtsShimTargetPSdk_apk.asciipb
index f22f680..ad924e3 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apk_CtsShimTargetPSdk__x86_CtsShimTargetPSdk_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apk_CtsShimTargetPSdk__x86_CtsShimTargetPSdk_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/CtsShimTargetPSdk.apk"
   }
diff --git a/apps/CameraITS/tests/scene1_1/test_exposure.py b/apps/CameraITS/tests/scene1_1/test_exposure.py
index 4fd34ca..17cb5d7 100644
--- a/apps/CameraITS/tests/scene1_1/test_exposure.py
+++ b/apps/CameraITS/tests/scene1_1/test_exposure.py
@@ -90,7 +90,7 @@
   pylab.figure(title)
   pylab.semilogx(x, r, 'ro-', label='R')
   pylab.semilogx(x, gr, 'go-', label='Gr')
-  pylab.semilogx(x, gb, 'bo-', label='Gb')
+  pylab.semilogx(x, gb, 'ko-', label='Gb')
   pylab.semilogx(x, b, 'bo-', label='B')
   pylab.title(NAME + title)
   pylab.xlabel('Gain Multiplier')
@@ -123,18 +123,20 @@
   max_diff = max_val - min_val
   logging.debug('Channel %d line fit (y = mx+b): m = %f, b = %f', chan, m, b)
   logging.debug('Channel min %f max %f diff %f', min_val, max_val, max_diff)
-  e_msg = 'max_diff: %.4f, THRESH: %.3f' % (max_diff, thresh_max_level_diff)
-  assert max_diff < thresh_max_level_diff, e_msg
-  e_msg = 'b: %.2f, THRESH_MIN: %.1f, THRESH_MAX: %.1f' % (
-      b, THRESH_MIN_LEVEL, THRESH_MAX_LEVEL)
-  assert THRESH_MAX_LEVEL > b > THRESH_MIN_LEVEL, e_msg
+  if max_diff >= thresh_max_level_diff:
+    raise AssertionError(f'max_diff: {max_diff:.4f}, '
+                         f'THRESH: {thresh_max_level_diff:.3f}')
+  if not THRESH_MAX_LEVEL > b > THRESH_MIN_LEVEL:
+    raise AssertionError(f'b: {b:.2f}, THRESH_MIN: {THRESH_MIN_LEVEL}, '
+                         f'THRESH_MAX: {THRESH_MAX_LEVEL}')
   for v in values:
-    e_msg = 'v: %.2f, THRESH_MIN: %.1f, THRESH_MAX: %.1f' % (
-        v, THRESH_MIN_LEVEL, THRESH_MAX_LEVEL)
-    assert THRESH_MAX_LEVEL > v > THRESH_MIN_LEVEL, e_msg
-    e_msg = 'v: %.2f, b: %.2f, THRESH_MAX_OUTLIER_DIFF: %.1f' % (
-        v, b, THRESH_MAX_OUTLIER_DIFF)
-    assert abs(v - b) < THRESH_MAX_OUTLIER_DIFF, e_msg
+    if not THRESH_MAX_LEVEL > v > THRESH_MIN_LEVEL:
+      raise AssertionError(f'v: {v:.2f}, THRESH_MIN: {THRESH_MIN_LEVEL}, '
+                           f'THRESH_MAX: {THRESH_MAX_LEVEL}')
+
+    if abs(v - b) >= THRESH_MAX_OUTLIER_DIFF:
+      raise AssertionError(f'v: {v:.2f}, b: {b:.2f}, '
+                           f'THRESH_DIFF: {THRESH_MAX_OUTLIER_DIFF}')
 
 
 def get_raw_active_array_size(props):
@@ -216,12 +218,13 @@
               THRESH_ROUND_DOWN_EXP +
               (THRESH_ROUND_DOWN_EXP0 - THRESH_ROUND_DOWN_EXP) *
               (THRESH_EXP_KNEE - e_test) / THRESH_EXP_KNEE)
-        s_msg = 's_write: %d, s_read: %d, TOL=%.f%%' % (
-            s_test, s_res, THRESH_ROUND_DOWN_GAIN*100)
-        assert 0 <= s_test - s_res < s_test * THRESH_ROUND_DOWN_GAIN, s_msg
-        e_msg = 'e_write: %.3fms, e_read: %.3fms, TOL=%.f%%' % (
-            e_test/1.0E6, e_res/1.0E6, thresh_round_down_exp*100)
-        assert 0 <= e_test - e_res < e_test * thresh_round_down_exp, e_msg
+        if not 0 <= s_test - s_res < s_test * THRESH_ROUND_DOWN_GAIN:
+          raise AssertionError(f's_write: {s_test}, s_read: {s_res}, '
+                               f'TOL={THRESH_ROUND_DOWN_GAIN*100:.f%%}')
+        if not 0 <= e_test - e_res < e_test * thresh_round_down_exp:
+          raise AssertionError(f'e_write: {e_test/1.0E6:.3f}ms, '
+                               f'e_read: {e_res/1.0E6:.3f}ms, '
+                               f'TOL={thresh_round_down_exp*100:.f%%}')
         s_e_product_res = s_res * e_res
         req_res_ratio = s_e_product / s_e_product_res
         logging.debug('Capture result s: %d, e: %dns', s_res, e_res)
@@ -259,11 +262,6 @@
         thresh_max_level_diff = THRESH_MAX_LEVEL_DIFF_WIDE_RANGE
 
     # Draw plots and check data
-    plot_rgb_means('RGB data', mults, r_means, g_means, b_means, self.log_path)
-    for ch, _ in enumerate(['r', 'g', 'b']):
-      values = [r_means, g_means, b_means][ch]
-      check_line_fit(ch, mults, values, thresh_max_level_diff)
-
     if raw_avlb and debug:
       plot_raw_means('RAW data', mults, raw_r_means, raw_gr_means, raw_gb_means,
                      raw_b_means, self.log_path)
@@ -271,5 +269,10 @@
         values = [raw_r_means, raw_gr_means, raw_gb_means, raw_b_means][ch]
         check_line_fit(ch, mults, values, thresh_max_level_diff)
 
+    plot_rgb_means('RGB data', mults, r_means, g_means, b_means, self.log_path)
+    for ch, _ in enumerate(['r', 'g', 'b']):
+      values = [r_means, g_means, b_means][ch]
+      check_line_fit(ch, mults, values, thresh_max_level_diff)
+
 if __name__ == '__main__':
   test_runner.main()
diff --git a/apps/CameraITS/tests/scene6/test_zoom.py b/apps/CameraITS/tests/scene6/test_zoom.py
index 54fcc4a..777bec6 100644
--- a/apps/CameraITS/tests/scene6/test_zoom.py
+++ b/apps/CameraITS/tests/scene6/test_zoom.py
@@ -111,6 +111,10 @@
       if colour == color and (1 - CIRCLE_TOL <= circlish <= 1 + CIRCLE_TOL):
         circles.append([shape['ctx'], shape['cty'], radius, circlish, area])
 
+  if not circles:
+    raise AssertionError('No circle was detected. Please take pictures '
+                         'according to instructions carefully!')
+
   if debug:
     logging.debug('circles [x, y, r, pi*r**2/area, area]: %s', str(circles))
 
@@ -131,10 +135,6 @@
   cv2.circle(img, center_i, radius_i, LINE_COLOR, LINE_THICKNESS)
   image_processing_utils.write_image(img / 255.0, img_name)
 
-  if not circles:
-    raise AssertionError('No circle was detected. Please take pictures '
-                         'according to instructions carefully!')
-
   return [circle[0], circle[1], circle[2]]
 
 
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index ff14f3f..4374b03 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -127,6 +127,7 @@
 SUB_CAMERA_TESTS = {
     'scene0': [
         'test_burst_capture',
+        'test_jitter',
         'test_metadata',
         'test_read_write',
         'test_sensor_events',
@@ -134,13 +135,15 @@
         'test_unified_timestamps',
     ],
     'scene1_1': [
-        'test_exposure',
+        'test_burst_sameness_manual',
         'test_dng_noise_model',
+        'test_exposure',
         'test_linearity',
     ],
     'scene1_2': [
         'test_raw_exposure',
         'test_raw_sensitivity',
+        'test_yuv_plus_raw',
     ],
     'scene2_a': [
         'test_faces',
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 614241f..c0a67f1 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -46,6 +46,7 @@
     <uses-permission android:name="android.permission.NFC" />
     <uses-permission android:name="android.permission.NFC_TRANSACTION_EVENT" />
     <uses-permission android:name="android.permission.VIBRATE" />
+    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
     <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
     <uses-permission android:name="android.permission.REQUEST_PASSWORD_COMPLEXITY" />
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
@@ -183,6 +184,20 @@
                        android:value="multi_display_mode" />
         </activity>
 
+        <activity
+            android:name=".battery.IgnoreBatteryOptimizationsTestActivity"
+            android:label="@string/ibo_test"
+            android:exported="true"
+            android:configChanges="keyboardHidden|orientation|screenSize">
+            <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_other" />
+            <meta-data android:name="test_excluded_features" android:value="android.hardware.type.automotive" />
+            <meta-data android:name="display_mode" android:value="multi_display_mode" />
+        </activity>
+
         <activity android:name=".forcestop.RecentTaskRemovalTestActivity"
                   android:label="@string/remove_from_recents_test"
                   android:exported="true"
diff --git a/apps/CtsVerifier/res/layout-watch/display_cutout.xml b/apps/CtsVerifier/res/layout-watch/display_cutout.xml
index da8314c..b1cfa01 100644
--- a/apps/CtsVerifier/res/layout-watch/display_cutout.xml
+++ b/apps/CtsVerifier/res/layout-watch/display_cutout.xml
@@ -18,17 +18,18 @@
 
     <RelativeLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
+        android:layout_height="match_parent"
+        android:padding="20dp">
 
         <TextView
             android:id="@+id/enable_buttons_desc"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_centerInParent="true"
+            android:layout_below="@id/top_buttons"
             android:layout_marginLeft="30dp"
             android:layout_marginRight="30dp"
             android:text="@string/display_cutout_test_instruction"
-            android:textSize="20dp" />
+            android:textSize="12dp" />
 
         <include
             android:id="@+id/pass_fail_buttons"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index acfce50..2de8172 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -872,6 +872,27 @@
     <string name="hifi_ultrasound_speaker_test_reference_side">
         Please report on the testing device.\n</string>
 
+    <!-- Strings for IgnoreBatteryOptimizationsTestActivity -->
+    <string name="ibo_test">Ignore Battery Optimizations Test</string>
+    <string name="ibo_test_info">
+        This test verifies that the device provides a user affordance to ask the user if the system
+        should disable battery optimizations for an app.
+    </string>
+    <string name="ibo_test_start_unexempt_app">
+        Remove the test app from the ignore battery optimizations list to begin the test. (Try going
+        to the App Info page and make sure the system is optimizing battery for the app.)
+    </string>
+    <string name="ibo_exempt_app">
+        Click Next to have the test request the exemption. Grant the exemption when prompted.
+    </string>
+    <string name="ibo_next_to_confirm">Press next to confirm.</string>
+    <string name="ibo_app_not_exempted">The app is not exempted from battery optimizations.</string>
+    <string name="ibo_unexempt_app">
+        Remove the test app from the ignore battery optimizations list. (Try going
+        to the App Info page and make sure the system is optimizing battery for the app.)
+    </string>
+    <string name="ibo_app_is_exempted">The app is exempted from battery optimizations.</string>
+
     <!-- Strings for Location tests -->
     <string name="location_gps_test">GPS Test</string>
     <string name="location_gps_test_info">This test verifies basic GPS behavior
@@ -5804,11 +5825,9 @@
 
     <string name="display_cutout_test">DisplayCutout Test</string>
     <string name="display_cutout_test_instruction">\n
-    This test is to make sure that the area inside the safe insets from the DisplayCutout should be
-    fully visible and touchable. \n\n
-    Please check the below items: \n
-    1. All buttons are fully visible \n
-    2. All buttons are clickable. \n
+    This test is to make sure that the area inside the safe insets from the DisplayCutout should be:\n
+    1. Visible\n
+    2. Clickable.\n
     </string>
 
     <!-- TTS Test Resources -->
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java
index d3fa699..3d2639b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java
@@ -1101,7 +1101,7 @@
                     if (stream == AudioManager.STREAM_VOICE_CALL) {
                         // Voice call requires MODIFY_PHONE_STATE, so we should not be able to mute
                         mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
-                        assertTrue("Voice call stream (" + stream + ") should require MODIFY_PHONE_STATE "
+                        assertFalse("Voice call stream (" + stream + ") should require MODIFY_PHONE_STATE "
                                 + "to mute.", mAudioManager.isStreamMute(stream));
                     } else {
                         mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/battery/IgnoreBatteryOptimizationsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/battery/IgnoreBatteryOptimizationsTestActivity.java
new file mode 100644
index 0000000..5f41fa7
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/battery/IgnoreBatteryOptimizationsTestActivity.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.battery;
+
+import android.app.usage.UsageStatsManager;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.view.View;
+
+import com.android.cts.verifier.OrderedTestActivity;
+import com.android.cts.verifier.R;
+
+/** Test activity to check fulfillment of the ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS intent. */
+public class IgnoreBatteryOptimizationsTestActivity extends OrderedTestActivity {
+    private PowerManager mPowerManager;
+    private UsageStatsManager mUsageStatsManager;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setInfoResources(R.string.ibo_test, R.string.ibo_test_info, -1);
+
+        mPowerManager = getSystemService(PowerManager.class);
+        mUsageStatsManager = getSystemService(UsageStatsManager.class);
+    }
+
+    @Override
+    protected Test[] getTests() {
+        return new Test[]{
+                mConfirmNotExemptedAtStart,
+                mRequestExemption,
+                mIntermediate,
+                mConfirmIsExempted,
+                mRemoveExemption,
+                mIntermediate,
+                mConfirmIsNotExempted
+        };
+    }
+
+    private boolean isExempted() {
+        return mUsageStatsManager.getAppStandbyBucket() == UsageStatsManager.STANDBY_BUCKET_EXEMPTED
+                && mPowerManager.isIgnoringBatteryOptimizations(getPackageName());
+    }
+
+    private final Test mConfirmNotExemptedAtStart = new Test(R.string.ibo_test_start_unexempt_app) {
+        @Override
+        protected void run() {
+            super.run();
+
+            if (!isExempted()) {
+                succeed();
+            }
+        }
+
+        @Override
+        protected void onNextClick() {
+            if (isExempted()) {
+                Intent appInfoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+                appInfoIntent.setData(Uri.parse("package:" + getPackageName()));
+                startActivity(appInfoIntent);
+            } else {
+                succeed();
+            }
+        }
+    };
+
+    private final Test mRequestExemption = new Test(R.string.ibo_exempt_app) {
+        @Override
+        protected void onNextClick() {
+            Intent request = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
+            request.setData(Uri.parse("package:" + getPackageName()));
+            startActivity(request);
+            succeed();
+        }
+    };
+
+    private final Test mIntermediate = new Test(R.string.ibo_next_to_confirm) {
+        @Override
+        protected void onNextClick() {
+            succeed();
+        }
+    };
+
+    private final Test mConfirmIsExempted = new Test(R.string.ibo_app_not_exempted) {
+        @Override
+        protected void run() {
+            super.run();
+
+            if (isExempted()) {
+                succeed();
+            }
+        }
+    };
+
+    private final Test mRemoveExemption = new Test(R.string.ibo_unexempt_app) {
+        @Override
+        protected void run() {
+            super.run();
+
+            if (!isExempted()) {
+                succeed();
+            }
+        }
+
+        @Override
+        protected void onNextClick() {
+            if (isExempted()) {
+                Intent appInfoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+                appInfoIntent.setData(Uri.parse("package:" + getPackageName()));
+                startActivity(appInfoIntent);
+            } else {
+                succeed();
+            }
+        }
+    };
+
+    private final Test mConfirmIsNotExempted = new Test(R.string.ibo_app_is_exempted) {
+        @Override
+        protected void run() {
+            super.run();
+
+            if (!isExempted()) {
+                succeed();
+            } else {
+                findViewById(R.id.btn_next).setVisibility(View.GONE);
+            }
+        }
+    };
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
index 23e1de5..08cd8b2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
@@ -100,7 +100,7 @@
             add("scene_change");
             add("sensor_fusion");
         }};
-    // This must match scenes of HIDDEN_PHYSICAL_CAMERA_TESTS in run_all_tests.py
+    // This must match scenes of SUB_CAMERA_TESTS in tools/run_all_tests.py
     private static final ArrayList<String> mHiddenPhysicalCameraSceneIds =
             new ArrayList<String> () {{
                     add("scene0");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/orientation/CameraOrientationActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/orientation/CameraOrientationActivity.java
index d753d6a..4a09df8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/orientation/CameraOrientationActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/orientation/CameraOrientationActivity.java
@@ -55,6 +55,8 @@
     private static final int STATE_CAPTURE = 2;
     private static final int NUM_ORIENTATIONS = 4;
     private static final String STAGE_INDEX_EXTRA = "stageIndex";
+    private static final int VGA_WIDTH = 640;
+    private static final int VGA_HEIGHT = 480;
 
     private ImageButton mPassButton;
     private ImageButton mFailButton;
@@ -65,7 +67,9 @@
     private SurfaceHolder mSurfaceHolder;
     private Camera mCamera;
     private List<Camera.Size> mPreviewSizes;
-    private Camera.Size mOptimalSize;
+    private List<Camera.Size> mPictureSizes;
+    private Camera.Size mOptimalPreviewSize;
+    private Camera.Size mOptimalPictureSize;
     private List<Integer> mPreviewOrientations;
     private int mNextPreviewOrientation;
     private int mNumCameras;
@@ -187,8 +191,6 @@
 
         Camera.Parameters p = mCamera.getParameters();
 
-        // Get preview resolutions
-        List<Camera.Size> unsortedSizes = p.getSupportedPreviewSizes();
         class SizeCompare implements Comparator<Camera.Size> {
             @Override
             public int compare(Camera.Size lhs, Camera.Size rhs) {
@@ -201,9 +203,18 @@
         }
         SizeCompare s = new SizeCompare();
         TreeSet<Camera.Size> sortedResolutions = new TreeSet<Camera.Size>(s);
+
+        // Get preview resolutions
+        List<Camera.Size> unsortedSizes = p.getSupportedPreviewSizes();
         sortedResolutions.addAll(unsortedSizes);
         mPreviewSizes = new ArrayList<Camera.Size>(sortedResolutions);
 
+        // Get picture resolutions
+        unsortedSizes = p.getSupportedPictureSizes();
+        sortedResolutions.clear();
+        sortedResolutions.addAll(unsortedSizes);
+        mPictureSizes = new ArrayList<Camera.Size>(sortedResolutions);
+
         startPreview();
     }
 
@@ -245,13 +256,14 @@
         Camera.Parameters p = mCamera.getParameters();
         Log.v(TAG, "Initializing picture format");
         p.setPictureFormat(ImageFormat.JPEG);
-        mOptimalSize = getOptimalPreviewSize(mPreviewSizes, 640, 480);
+        mOptimalPictureSize = getOptimalSize(mPictureSizes, VGA_WIDTH, VGA_HEIGHT);
         Log.v(TAG, "Initializing picture size to "
-                + mOptimalSize.width + "x" + mOptimalSize.height);
-        p.setPictureSize(mOptimalSize.width, mOptimalSize.height);
+                + mOptimalPictureSize.width + "x" + mOptimalPictureSize.height);
+        p.setPictureSize(mOptimalPictureSize.width, mOptimalPictureSize.height);
+        mOptimalPreviewSize = getOptimalSize(mPreviewSizes, VGA_WIDTH, VGA_HEIGHT);
         Log.v(TAG, "Initializing preview size to "
-                + mOptimalSize.width + "x" + mOptimalSize.height);
-        p.setPreviewSize(mOptimalSize.width, mOptimalSize.height);
+                + mOptimalPreviewSize.width + "x" + mOptimalPreviewSize.height);
+        p.setPreviewSize(mOptimalPreviewSize.width, mOptimalPreviewSize.height);
 
         Log.v(TAG, "Setting camera parameters");
         mCamera.setParameters(p);
@@ -375,10 +387,10 @@
     // find a supported size with ratio less than tolerance threshold, and
     // which is closest to height and width of given dimensions without
     // being larger than either of given dimensions
-    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w,
+    private Camera.Size getOptimalSize(List<Camera.Size> sizes, int w,
             int h) {
         final double ASPECT_TOLERANCE = 0.1;
-        double targetRatio = (double) 640 / (double) 480;
+        double targetRatio = (double) w / (double) h;
         if (sizes == null) return null;
 
         Camera.Size optimalSize = null;
@@ -474,13 +486,13 @@
                     // make preview width same as output image width,
                     // then calculate height using output image's height/width ratio
                     newWidth = viewWidth;
-                    newHeight = (int) (viewWidth * ((double) mOptimalSize.height /
-                            (double) mOptimalSize.width));
+                    newHeight = (int) (viewWidth * ((double) mOptimalPreviewSize.height /
+                            (double) mOptimalPreviewSize.width));
                 }
                 else {
                     newHeight = viewHeight;
-                    newWidth = (int) (viewHeight * ((double) mOptimalSize.height /
-                            (double) mOptimalSize.width));
+                    newWidth = (int) (viewHeight * ((double) mOptimalPreviewSize.height /
+                            (double) mOptimalPreviewSize.width));
                 }
 
                 LayoutParams layoutParams = new LayoutParams(newWidth, newHeight);
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 d201b58..61500b7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -185,7 +185,7 @@
     @Override
     public void finish() {
         String action = getIntent().getAction();
-        switch(action) {
+        switch(action != null ? action : "") {
             case ACTION_CHECK_DEVICE_OWNER:
             case ACTION_CHECK_PROFILE_OWNER:
             case ACTION_CHECK_CURRENT_USER_AFFILIATED:
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 07d5314..5e48a8f 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
@@ -22,7 +22,9 @@
 import com.android.bedstead.harrier.annotations.enterprise.NegativePolicyTest;
 import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
 import com.android.bedstead.harrier.annotations.meta.ParameterizedAnnotation;
+import com.android.bedstead.harrier.annotations.meta.RepeatingAnnotation;
 import com.android.bedstead.harrier.annotations.parameterized.IncludeNone;
+import com.android.bedstead.nene.exceptions.NeneException;
 
 import com.google.common.base.Objects;
 
@@ -34,6 +36,7 @@
 import org.junit.runners.model.TestClass;
 
 import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -151,6 +154,19 @@
             @Nullable Class<? extends Annotation> parameterizedAnnotation) {
         List<Annotation> replacementAnnotations = new ArrayList<>();
 
+        if (annotation.annotationType().getAnnotation(RepeatingAnnotation.class) != null) {
+            try {
+                Annotation[] annotations =
+                        (Annotation[]) annotation.annotationType()
+                                .getMethod("value").invoke(annotation);
+                Collections.addAll(replacementAnnotations, annotations);
+                return replacementAnnotations;
+            } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+                throw new NeneException("Error expanding repeated annotations", e);
+            }
+
+        }
+
         if (annotation.annotationType().getAnnotation(ParameterizedAnnotation.class) != null
                 && !annotation.annotationType().equals(parameterizedAnnotation)) {
             return replacementAnnotations;
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 e1790f8..8f9c208 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
@@ -18,6 +18,7 @@
 
 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.utils.Versions.meetsSdkVersionRequirements;
 import static com.android.bedstead.remotedpc.Configuration.REMOTE_DPC_COMPONENT_NAME;
 
 import static com.google.common.truth.Truth.assertWithMessage;
@@ -36,9 +37,13 @@
 
 import com.android.bedstead.harrier.annotations.EnsureDoesNotHavePermission;
 import com.android.bedstead.harrier.annotations.EnsureHasPermission;
+import com.android.bedstead.harrier.annotations.EnsurePackageNotInstalled;
 import com.android.bedstead.harrier.annotations.FailureMode;
-import com.android.bedstead.harrier.annotations.RequireDoesNotHaveFeatures;
-import com.android.bedstead.harrier.annotations.RequireFeatures;
+import com.android.bedstead.harrier.annotations.RequireDoesNotHaveFeature;
+import com.android.bedstead.harrier.annotations.RequireFeature;
+import com.android.bedstead.harrier.annotations.RequirePackageInstalled;
+import com.android.bedstead.harrier.annotations.RequirePackageNotInstalled;
+import com.android.bedstead.harrier.annotations.RequireSdkVersion;
 import com.android.bedstead.harrier.annotations.RequireUserSupported;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
@@ -58,6 +63,7 @@
 import com.android.bedstead.nene.devicepolicy.ProfileOwner;
 import com.android.bedstead.nene.exceptions.AdbException;
 import com.android.bedstead.nene.exceptions.NeneException;
+import com.android.bedstead.nene.packages.Package;
 import com.android.bedstead.nene.permissions.PermissionContextImpl;
 import com.android.bedstead.nene.users.User;
 import com.android.bedstead.nene.users.UserBuilder;
@@ -157,6 +163,7 @@
                         UserType userType = (UserType) annotation.annotationType()
                                 .getMethod("forUser").invoke(annotation);
                         ensureHasNoProfile(ensureHasNoProfileAnnotation.value(), userType);
+                        continue;
                     }
 
                     EnsureHasProfileAnnotation ensureHasProfileAnnotation =
@@ -170,12 +177,14 @@
                             ensureHasProfile(
                                     ensureHasProfileAnnotation.value(), installInstrumentedApp,
                                     forUser);
+                            continue;
                     }
 
                     EnsureHasNoUserAnnotation ensureHasNoUserAnnotation =
                             annotationType.getAnnotation(EnsureHasNoUserAnnotation.class);
                     if (ensureHasNoUserAnnotation != null) {
                         ensureHasNoUser(ensureHasNoUserAnnotation.value());
+                        continue;
                     }
 
                     EnsureHasUserAnnotation ensureHasUserAnnotation =
@@ -185,12 +194,14 @@
                                 annotation.getClass()
                                 .getMethod("installInstrumentedApp").invoke(annotation);
                         ensureHasUser(ensureHasUserAnnotation.value(), installInstrumentedApp);
+                        continue;
                     }
 
                     RequireRunOnUserAnnotation requireRunOnUserAnnotation =
                             annotationType.getAnnotation(RequireRunOnUserAnnotation.class);
                     if (requireRunOnUserAnnotation != null) {
                         requireRunOnUser(requireRunOnUserAnnotation.value());
+                        continue;
                     }
 
                     RequireRunOnProfileAnnotation requireRunOnProfileAnnotation =
@@ -214,20 +225,21 @@
                         ensureHasNoDeviceOwner();
                     }
 
-                    if (annotation instanceof RequireFeatures) {
-                        RequireFeatures requireFeaturesAnnotation = (RequireFeatures) annotation;
-                        for (String feature: requireFeaturesAnnotation.value()) {
-                            requireFeature(feature, requireFeaturesAnnotation.failureMode());
-                        }
+                    if (annotation instanceof RequireFeature) {
+                        RequireFeature requireFeatureAnnotation = (RequireFeature) annotation;
+                        requireFeature(
+                                requireFeatureAnnotation.value(),
+                                requireFeatureAnnotation.failureMode());
+                        continue;
                     }
 
-                    if (annotation instanceof RequireDoesNotHaveFeatures) {
-                        RequireDoesNotHaveFeatures requireDoesNotHaveFeaturesAnnotation =
-                                (RequireDoesNotHaveFeatures) annotation;
-                        for (String feature : requireDoesNotHaveFeaturesAnnotation.value()) {
-                            requireDoesNotHaveFeature(feature,
-                                    requireDoesNotHaveFeaturesAnnotation.failureMode());
-                        }
+                    if (annotation instanceof RequireDoesNotHaveFeature) {
+                        RequireDoesNotHaveFeature requireDoesNotHaveFeatureAnnotation =
+                                (RequireDoesNotHaveFeature) annotation;
+                        requireDoesNotHaveFeature(
+                                requireDoesNotHaveFeatureAnnotation.value(),
+                                requireDoesNotHaveFeatureAnnotation.failureMode());
+                        continue;
                     }
 
                     if (annotationType.equals(EnsureHasProfileOwner.class)) {
@@ -245,10 +257,52 @@
                     if (annotation instanceof RequireUserSupported) {
                         RequireUserSupported requireUserSupportedAnnotation =
                                 (RequireUserSupported) annotation;
-                        for (String userType: requireUserSupportedAnnotation.value()) {
-                            requireUserSupported(
-                                    userType, requireUserSupportedAnnotation.failureMode());
-                        }
+                        requireUserSupported(
+                                requireUserSupportedAnnotation.value(),
+                                requireUserSupportedAnnotation.failureMode());
+                        continue;
+                    }
+
+                    if (annotation instanceof RequireSdkVersion) {
+                        RequireSdkVersion requireSdkVersionAnnotation =
+                                (RequireSdkVersion) annotation;
+
+                        requireSdkVersion(
+                                requireSdkVersionAnnotation.min(),
+                                requireSdkVersionAnnotation.max(),
+                                requireSdkVersionAnnotation.failureMode());
+                        continue;
+                    }
+
+                    if (annotation instanceof RequirePackageInstalled) {
+                        RequirePackageInstalled requirePackageInstalledAnnotation =
+                                (RequirePackageInstalled) annotation;
+                        requirePackageInstalled(
+                                requirePackageInstalledAnnotation.value(),
+                                requirePackageInstalledAnnotation.onUser(),
+                                requirePackageInstalledAnnotation.failureMode());
+                        continue;
+                    }
+
+                    if (annotation instanceof RequirePackageNotInstalled) {
+                        RequirePackageNotInstalled requirePackageNotInstalledAnnotation =
+                                (RequirePackageNotInstalled) annotation;
+                        requirePackageNotInstalled(
+                                requirePackageNotInstalledAnnotation.value(),
+                                requirePackageNotInstalledAnnotation.onUser(),
+                                requirePackageNotInstalledAnnotation.failureMode()
+                        );
+                        continue;
+                    }
+
+                    if (annotation instanceof EnsurePackageNotInstalled) {
+                        EnsurePackageNotInstalled ensurePackageNotInstalledAnnotation =
+                                (EnsurePackageNotInstalled) annotation;
+                        ensurePackageNotInstalled(
+                                ensurePackageNotInstalledAnnotation.value(),
+                                ensurePackageNotInstalledAnnotation.onUser()
+                        );
+                        continue;
                     }
 
                     if (annotation instanceof EnsureHasPermission) {
@@ -379,6 +433,14 @@
                 !sTestApis.packages().features().contains(feature), failureMode);
     }
 
+    private void requireSdkVersion(int min, int max, FailureMode failureMode) {
+        checkFailOrSkip(
+                "Sdk version must be between " + min +  " and " + max + " (inclusive)",
+                meetsSdkVersionRequirements(min, max),
+                failureMode
+        );
+    }
+
     private com.android.bedstead.nene.users.UserType requireUserSupported(
             String userType, FailureMode failureMode) {
         com.android.bedstead.nene.users.UserType resolvedUserType =
@@ -413,6 +475,8 @@
     }
 
     public enum UserType {
+        /** Only to be used with annotations. */
+        ANY,
         SYSTEM_USER,
         CURRENT_USER,
         PRIMARY_USER,
@@ -743,6 +807,8 @@
                 return workProfile();
             case TV_PROFILE:
                 return tvProfile();
+            case ANY:
+                throw new IllegalStateException("ANY UserType can not be used here");
             default:
                 throw new IllegalArgumentException("Unknown user type " + userType);
         }
@@ -1005,4 +1071,68 @@
 
         return RemoteDpc.forDevicePolicyController(profileOwner);
     }
+
+    private void requirePackageInstalled(
+            String packageName, UserType forUser, FailureMode failureMode) {
+
+        Package pkg = sTestApis.packages().find(packageName).resolve();
+        checkFailOrSkip(
+                packageName + " is required to be installed for " + forUser,
+                pkg != null,
+                failureMode);
+
+        if (forUser.equals(UserType.ANY)) {
+            checkFailOrSkip(
+                    packageName + " is required to be installed",
+                    !pkg.installedOnUsers().isEmpty(),
+                    failureMode);
+        } else {
+            checkFailOrSkip(
+                    packageName + " is required to be installed for " + forUser,
+                    pkg.installedOnUsers().contains(resolveUserTypeToUser(forUser)),
+                    failureMode);
+        }
+    }
+
+    private void requirePackageNotInstalled(
+            String packageName, UserType forUser, FailureMode failureMode) {
+        Package pkg = sTestApis.packages().find(packageName).resolve();
+        if (pkg == null) {
+            // Definitely not installed
+            return;
+        }
+
+        if (forUser.equals(UserType.ANY)) {
+            checkFailOrSkip(
+                    packageName + " is required to be not installed",
+                    pkg.installedOnUsers().isEmpty(),
+                    failureMode);
+        } else {
+            checkFailOrSkip(
+                    packageName + " is required to be not installed for " + forUser,
+                    !pkg.installedOnUsers().contains(resolveUserTypeToUser(forUser)),
+                    failureMode);
+        }
+    }
+
+    private void ensurePackageNotInstalled(
+            String packageName, UserType forUser) {
+
+        Package pkg = sTestApis.packages().find(packageName).resolve();
+        if (pkg == null) {
+            // Definitely not installed
+            return;
+        }
+
+        if (forUser.equals(UserType.ANY)) {
+            if (!pkg.installedOnUsers().isEmpty()) {
+                pkg.uninstallFromAllUsers();
+            }
+        } else {
+            UserReference user = resolveUserTypeToUser(forUser);
+            if (pkg.installedOnUsers().contains(user)) {
+                pkg.uninstall(user);
+            }
+        }
+    }
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/EnsureHasWorkProfile.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/EnsureHasWorkProfile.java
index 7802733..0c36637 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/EnsureHasWorkProfile.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/EnsureHasWorkProfile.java
@@ -33,7 +33,7 @@
  * Mark that a test method should run on a user which has a work profile.
  *
  * <p>Use of this annotation implies
- * {@code RequireFeatures("android.software.managed_users", SKIP)}.
+ * {@code RequireFeature("android.software.managed_users", SKIP)}.
  *
  * <p>Your test configuration may be configured so that this test is only run on a user which has
  * a work profile. Otherwise, you can use {@link DeviceState} to ensure that the device enters
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/EnsurePackageNotInstalled.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/EnsurePackageNotInstalled.java
new file mode 100644
index 0000000..73c00c9
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/EnsurePackageNotInstalled.java
@@ -0,0 +1,43 @@
+/*
+ * 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 com.android.bedstead.harrier.DeviceState;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark that a test method should run only when a given package is not installed.
+ *
+ * <p>You can guarantee that these methods do not run on devices with the package by
+ * using {@code DeviceState}.
+ *
+ * <p>Tests annotated with this will attempt to remove the package if it exists, or otherwise fail.
+ * If you'd rather skip or fail tests immediately without attempting to remove see
+ * {@link RequirePackageNotInstalled}.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Repeatable(EnsurePackagesNotInstalled.class)
+public @interface EnsurePackageNotInstalled {
+    String value();
+    DeviceState.UserType onUser() default DeviceState.UserType.CURRENT_USER;
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/EnsurePackagesNotInstalled.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/EnsurePackagesNotInstalled.java
new file mode 100644
index 0000000..c8372a3
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/EnsurePackagesNotInstalled.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 com.android.bedstead.harrier.annotations.meta.RepeatingAnnotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@RepeatingAnnotation
+public @interface EnsurePackagesNotInstalled {
+    EnsurePackageNotInstalled[] value();
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireAospBuild.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireAospBuild.java
new file mode 100644
index 0000000..899b252
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireAospBuild.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.annotations;
+
+import static com.android.bedstead.harrier.annotations.RequireAospBuild.GMS_CORE_PACKAGE;
+import static com.android.bedstead.harrier.annotations.RequireAospBuild.GSF_PACKAGE;
+import static com.android.bedstead.harrier.annotations.RequireAospBuild.PLAY_STORE_PACKAGE;
+
+import com.android.bedstead.harrier.DeviceState;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@RequirePackageNotInstalled(value = GMS_CORE_PACKAGE, onUser = DeviceState.UserType.ANY)
+@RequirePackageNotInstalled(value = PLAY_STORE_PACKAGE, onUser = DeviceState.UserType.ANY)
+@RequirePackageNotInstalled(value = GSF_PACKAGE, onUser = DeviceState.UserType.ANY)
+public @interface RequireAospBuild {
+    String GMS_CORE_PACKAGE = "com.google.android.gms";
+    String PLAY_STORE_PACKAGE = "com.android.vending";
+    String GSF_PACKAGE = "com.google.android.gsf";
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireCnGmsBuild.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireCnGmsBuild.java
new file mode 100644
index 0000000..81df0d8
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireCnGmsBuild.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 static com.android.bedstead.harrier.annotations.RequireCnGmsBuild.CHINA_GOOGLE_SERVICES_FEATURE;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@RequireFeature(CHINA_GOOGLE_SERVICES_FEATURE)
+public @interface RequireCnGmsBuild {
+    String CHINA_GOOGLE_SERVICES_FEATURE = "cn.google.services";
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireDoesNotHaveFeature.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireDoesNotHaveFeature.java
new file mode 100644
index 0000000..d1138ad
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireDoesNotHaveFeature.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.bedstead.harrier.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark that a test method should run only when the device does not have a given feature.
+ *
+ * <p>You can guarantee that these methods do not run on devices with the feature by
+ * using {@code DeviceState}.
+ *
+ * <p>By default the test will be skipped if the feature is available. If you'd rather the test
+ * fail then use {@code failureMode = FailureMode.FAIL}.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RequireDoesNotHaveFeature {
+    String value();
+    FailureMode failureMode() default FailureMode.SKIP;
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireDoesNotHaveFeatures.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireDoesNotHaveFeatures.java
index 61a3854..e4ed4f0 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireDoesNotHaveFeatures.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireDoesNotHaveFeatures.java
@@ -16,23 +16,16 @@
 
 package com.android.bedstead.harrier.annotations;
 
+import com.android.bedstead.harrier.annotations.meta.RepeatingAnnotation;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-/**
- * Mark that a test method should run only when the device does not have a given feature.
- *
- * <p>You can guarantee that these methods do not run on devices with the feature by
- * using {@code DeviceState}.
- *
- * <p>By default the test will be skipped if the feature is available. If you'd rather the test
- * fail then use {@code failureMode = FailureMode.FAIL}.
- */
-@Target(ElementType.METHOD)
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
 @Retention(RetentionPolicy.RUNTIME)
+@RepeatingAnnotation
 public @interface RequireDoesNotHaveFeatures {
-    String[] value();
-    FailureMode failureMode() default FailureMode.SKIP;
-}
+    RequireDoesNotHaveFeature[] value();
+}
\ No newline at end of file
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireFeature.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireFeature.java
new file mode 100644
index 0000000..ec3eab0
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireFeature.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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark that a test method should run only when the device has a given feature.
+ *
+ * <p>You can guarantee that these methods do not run on devices lacking the feature by
+ * using {@code DeviceState}.
+ *
+ * <p>By default the test will be skipped if the feature is not available. If you'd rather the test
+ * fail then use {@code failureMode = FailureMode.FAIL}.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Repeatable(RequireFeatures.class)
+public @interface RequireFeature {
+    String value();
+    FailureMode failureMode() default FailureMode.SKIP;
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireFeatures.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireFeatures.java
index c44292e..b5edcdb 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireFeatures.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireFeatures.java
@@ -16,23 +16,16 @@
 
 package com.android.bedstead.harrier.annotations;
 
+import com.android.bedstead.harrier.annotations.meta.RepeatingAnnotation;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-/**
- * Mark that a test method should run only when the device has a given feature.
- *
- * <p>You can guarantee that these methods do not run on devices lacking the feature by
- * using {@code DeviceState}.
- *
- * <p>By default the test will be skipped if the feature is not available. If you'd rather the test
- * fail then use {@code failureMode = FailureMode.FAIL}.
- */
-@Target(ElementType.METHOD)
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
 @Retention(RetentionPolicy.RUNTIME)
+@RepeatingAnnotation
 public @interface RequireFeatures {
-    String[] value();
-    FailureMode failureMode() default FailureMode.SKIP;
+    RequireFeature[] value();
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireGmsBuild.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireGmsBuild.java
new file mode 100644
index 0000000..f57b218
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireGmsBuild.java
@@ -0,0 +1,36 @@
+/*
+ * 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 static com.android.bedstead.harrier.annotations.RequireAospBuild.GMS_CORE_PACKAGE;
+import static com.android.bedstead.harrier.annotations.RequireAospBuild.GSF_PACKAGE;
+import static com.android.bedstead.harrier.annotations.RequireAospBuild.PLAY_STORE_PACKAGE;
+
+import com.android.bedstead.harrier.DeviceState;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@RequirePackageInstalled(value = GMS_CORE_PACKAGE, onUser = DeviceState.UserType.ANY)
+@RequirePackageInstalled(value = PLAY_STORE_PACKAGE, onUser = DeviceState.UserType.ANY)
+@RequirePackageInstalled(value = GSF_PACKAGE, onUser = DeviceState.UserType.ANY)
+public @interface RequireGmsBuild {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireNotCnGmsBuild.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireNotCnGmsBuild.java
new file mode 100644
index 0000000..976565e
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireNotCnGmsBuild.java
@@ -0,0 +1,30 @@
+/*
+ * 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 static com.android.bedstead.harrier.annotations.RequireCnGmsBuild.CHINA_GOOGLE_SERVICES_FEATURE;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@RequireDoesNotHaveFeature(CHINA_GOOGLE_SERVICES_FEATURE)
+public @interface RequireNotCnGmsBuild {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequirePackageInstalled.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequirePackageInstalled.java
new file mode 100644
index 0000000..b346a6a
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequirePackageInstalled.java
@@ -0,0 +1,43 @@
+/*
+ * 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 com.android.bedstead.harrier.DeviceState;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark that a test method should run only when a given package is installed.
+ *
+ * <p>You can guarantee that these methods do not run on devices lacking the package by
+ * using {@code DeviceState}.
+ *
+ * <p>By default the test will be skipped if the package is not available. If you'd rather the test
+ * fail then use {@code failureMode = FailureMode.FAIL}.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Repeatable(RequirePackagesInstalled.class)
+public @interface RequirePackageInstalled {
+    String value();
+    DeviceState.UserType onUser() default DeviceState.UserType.CURRENT_USER;
+    FailureMode failureMode() default FailureMode.SKIP;
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequirePackageNotInstalled.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequirePackageNotInstalled.java
new file mode 100644
index 0000000..528d18d
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequirePackageNotInstalled.java
@@ -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 com.android.bedstead.harrier.annotations;
+
+import com.android.bedstead.harrier.DeviceState;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark that a test method should run only when a given package is not installed.
+ *
+ * <p>You can guarantee that these methods do not run on devices with the package by
+ * using {@code DeviceState}.
+ *
+ * <p>By default the test will be skipped if the package is available. If you'd rather the test
+ * fail then use {@code failureMode = FailureMode.FAIL}. If you'd like to uninstall the package if
+ * it is installed, see {@link EnsurePackageNotInstalled}.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Repeatable(RequirePackagesNotInstalled.class)
+public @interface RequirePackageNotInstalled {
+    String value();
+    DeviceState.UserType onUser() default DeviceState.UserType.CURRENT_USER;
+    FailureMode failureMode() default FailureMode.SKIP;
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequirePackagesInstalled.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequirePackagesInstalled.java
new file mode 100644
index 0000000..ebfa266
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequirePackagesInstalled.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 com.android.bedstead.harrier.annotations.meta.RepeatingAnnotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@RepeatingAnnotation
+public @interface RequirePackagesInstalled {
+    RequirePackageInstalled[] value();
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequirePackagesNotInstalled.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequirePackagesNotInstalled.java
new file mode 100644
index 0000000..0c1f9d4
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequirePackagesNotInstalled.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 com.android.bedstead.harrier.annotations.meta.RepeatingAnnotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@RepeatingAnnotation
+public @interface RequirePackagesNotInstalled {
+    RequirePackageNotInstalled[] value();
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireSdkVersion.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireSdkVersion.java
new file mode 100644
index 0000000..54f66c2
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireSdkVersion.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.annotations;
+
+import com.android.bedstead.harrier.DeviceState;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark that a test method should only run on specified sdk versions.
+ *
+ * <p>Your test configuration may be configured so that this test is only run on a device with the
+ * given user. Otherwise, you can use {@link DeviceState} to ensure that the test is
+ * not run when the sdk version is not correct.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RequireSdkVersion {
+    int min() default 1;
+    int max() default Integer.MAX_VALUE;
+    FailureMode failureMode() default FailureMode.SKIP;
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireUserSupported.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireUserSupported.java
index deb06f1..383f4e8 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireUserSupported.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireUserSupported.java
@@ -19,6 +19,7 @@
 import com.android.bedstead.harrier.DeviceState;
 
 import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
@@ -30,9 +31,10 @@
  * supports the user types. Otherwise, you can use {@link DeviceState} to ensure that the test is
  * not run when the user type is not supported.
  */
-@Target(ElementType.METHOD)
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
 @Retention(RetentionPolicy.RUNTIME)
+@Repeatable(RequireUsersSupported.class)
 public @interface RequireUserSupported {
-    String[] value();
+    String value();
     FailureMode failureMode() default FailureMode.SKIP;
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireUsersSupported.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireUsersSupported.java
new file mode 100644
index 0000000..e424db8
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireUsersSupported.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 com.android.bedstead.harrier.annotations.meta.RepeatingAnnotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@RepeatingAnnotation
+public @interface RequireUsersSupported {
+    RequireUserSupported[] value();
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/meta/RepeatingAnnotation.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/meta/RepeatingAnnotation.java
new file mode 100644
index 0000000..5556120
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/meta/RepeatingAnnotation.java
@@ -0,0 +1,30 @@
+/*
+ * 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.meta;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that an annotation is a collection of repeated annotations.
+ */
+@Target(ElementType.ANNOTATION_TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RepeatingAnnotation {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/meta/RequiresBedsteadJUnit4.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/meta/RequiresBedsteadJUnit4.java
index 9033b90..4bbd2d6 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/meta/RequiresBedsteadJUnit4.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/meta/RequiresBedsteadJUnit4.java
@@ -24,7 +24,7 @@
 import java.lang.annotation.Target;
 
 /**
- * Indicates that an annotation requires using the {@link BedsteadJUnit4} test runner
+ * Indicates that an annotation requires using the {@link BedsteadJUnit4} test runner.
  */
 @Target(ElementType.ANNOTATION_TYPE)
 @Retention(RetentionPolicy.RUNTIME)
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 9c0d2aa..bc75ff1 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
@@ -21,13 +21,19 @@
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
+import static com.android.bedstead.harrier.DeviceState.UserType.ANY;
+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.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.google.common.truth.Truth.assertThat;
 
 import static org.testng.Assert.assertThrows;
 
+import android.os.Build;
+
 import com.android.bedstead.harrier.annotations.EnsureDoesNotHavePermission;
 import com.android.bedstead.harrier.annotations.EnsureHasNoSecondaryUser;
 import com.android.bedstead.harrier.annotations.EnsureHasNoTvProfile;
@@ -36,8 +42,20 @@
 import com.android.bedstead.harrier.annotations.EnsureHasSecondaryUser;
 import com.android.bedstead.harrier.annotations.EnsureHasTvProfile;
 import com.android.bedstead.harrier.annotations.EnsureHasWorkProfile;
+import com.android.bedstead.harrier.annotations.EnsurePackageNotInstalled;
+import com.android.bedstead.harrier.annotations.RequireAospBuild;
+import com.android.bedstead.harrier.annotations.RequireCnGmsBuild;
+import com.android.bedstead.harrier.annotations.RequireDoesNotHaveFeature;
+import com.android.bedstead.harrier.annotations.RequireFeature;
+import com.android.bedstead.harrier.annotations.RequireGmsBuild;
+import com.android.bedstead.harrier.annotations.RequireNotCnGmsBuild;
+import com.android.bedstead.harrier.annotations.RequirePackageInstalled;
+import com.android.bedstead.harrier.annotations.RequirePackageNotInstalled;
+import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
 import com.android.bedstead.harrier.annotations.RequireRunOnSecondaryUser;
+import com.android.bedstead.harrier.annotations.RequireRunOnTvProfile;
 import com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile;
+import com.android.bedstead.harrier.annotations.RequireSdkVersion;
 import com.android.bedstead.harrier.annotations.RequireUserSupported;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
@@ -48,10 +66,11 @@
 import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnProfileOwner;
 import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnSecondaryUserInDifferentProfileGroupToProfileOwner;
 import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.packages.Package;
 import com.android.bedstead.nene.users.UserReference;
-import com.android.bedstead.nene.users.UserType;
 
 import org.junit.ClassRule;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -176,7 +195,7 @@
     @EnsureHasNoSecondaryUser
     public void secondaryUser_createdSecondaryUser_throwsException() {
         try (UserReference secondaryUser = sTestApis.users().createUser()
-                .type(sTestApis.users().supportedType(UserType.SECONDARY_USER_TYPE_NAME))
+                .type(sTestApis.users().supportedType(SECONDARY_USER_TYPE_NAME))
                 .create()) {
             assertThrows(IllegalStateException.class, sDeviceState::secondaryUser);
         }
@@ -186,7 +205,7 @@
     @EnsureHasSecondaryUser
     public void ensureHasSecondaryUserAnnotation_secondaryUserExists() {
         assertThat(sTestApis.users().findUserOfType(
-                sTestApis.users().supportedType(UserType.SECONDARY_USER_TYPE_NAME))
+                sTestApis.users().supportedType(SECONDARY_USER_TYPE_NAME))
         ).isNotNull();
     }
 
@@ -197,7 +216,7 @@
     @EnsureHasNoSecondaryUser
     public void ensureHasNoSecondaryUserAnnotation_secondaryUserDoesNotExist() {
         assertThat(sTestApis.users().findUserOfType(
-                sTestApis.users().supportedType(UserType.SECONDARY_USER_TYPE_NAME))
+                sTestApis.users().supportedType(SECONDARY_USER_TYPE_NAME))
         ).isNull();
     }
 
@@ -389,4 +408,123 @@
 
         // TODO(scottjonathan): Assert profile groups are different
     }
+
+    @RequirePackageInstalled(value = GMS_CORE_PACKAGE, onUser = ANY)
+    public void requirePackageInstalledAnnotation_anyUser_packageIsInstalled() {
+        assertThat(sTestApis.packages().find(GMS_CORE_PACKAGE).resolve()).isNotNull();
+    }
+
+    @Test
+    @RequirePackageInstalled(GMS_CORE_PACKAGE)
+    public void requirePackageInstalledAnnotation_currentUser_packageIsInstalled() {
+        assertThat(sTestApis.packages().find(GMS_CORE_PACKAGE).resolve().installedOnUsers())
+                .contains(sTestApis.users().instrumented());
+    }
+
+    @Test
+    @RequirePackageNotInstalled(value = GMS_CORE_PACKAGE, onUser = ANY)
+    public void requirePackageNotInstalledAnnotation_anyUser_packageIsNotInstalled() {
+        assertThat(sTestApis.packages().find(GMS_CORE_PACKAGE).resolve()).isNull();
+
+    }
+
+    @Test
+    @RequirePackageNotInstalled(GMS_CORE_PACKAGE)
+    public void requirePackageNotInstalledAnnotation_currentUser_packageIsNotInstalled() {
+        Package resolvedPackage = sTestApis.packages().find(GMS_CORE_PACKAGE).resolve();
+
+        if (resolvedPackage != null) {
+            assertThat(resolvedPackage.installedOnUsers())
+                    .doesNotContain(sTestApis.users().instrumented());
+        }
+    }
+
+    @Test
+    @EnsurePackageNotInstalled(value = GMS_CORE_PACKAGE, onUser = ANY)
+    @Ignore // TODO(scottjonathan): Restore this with a package which can be uninstalled
+    public void ensurePackageNotInstalledAnnotation_anyUser_packageIsNotInstalled() {
+        assertThat(sTestApis.packages().find(GMS_CORE_PACKAGE).resolve()).isNull();
+    }
+
+    @Test
+    @EnsurePackageNotInstalled(GMS_CORE_PACKAGE)
+    @Ignore // TODO(scottjonathan): Restore this with a package which can be uninstalled
+    public void ensurePackageNotInstalledAnnotation_currentUser_packageIsNotInstalled() {
+        Package resolvedPackage = sTestApis.packages().find(GMS_CORE_PACKAGE).resolve();
+
+        if (resolvedPackage != null) {
+            assertThat(resolvedPackage.installedOnUsers())
+                    .doesNotContain(sTestApis.users().instrumented());
+        }
+    }
+
+    @Test
+    @RequireAospBuild
+    public void requireAospBuildAnnotation_isRunningOnAospBuild() {
+        assertThat(sTestApis.packages().find(GMS_CORE_PACKAGE).resolve()).isNull();
+    }
+
+    @Test
+    @RequireGmsBuild
+    public void requireGmsBuildAnnotation_isRunningOnGmsbuild() {
+        assertThat(sTestApis.packages().find(GMS_CORE_PACKAGE).resolve()).isNotNull();
+    }
+
+    @Test
+    @RequireCnGmsBuild
+    public void requireCnGmsBuildAnnotation_isRunningOnCnGmsBuild() {
+        assertThat(sTestApis.packages().features()).contains(CHINA_GOOGLE_SERVICES_FEATURE);
+    }
+
+    @Test
+    @RequireNotCnGmsBuild
+    public void requireNotCnGmsBuildAnnotation_isNotRunningOnCnGmsBuild() {
+        assertThat(sTestApis.packages().features()).doesNotContain(CHINA_GOOGLE_SERVICES_FEATURE);
+
+    }
+
+    @Test
+    @RequireFeature(CHINA_GOOGLE_SERVICES_FEATURE)
+    public void requireHasFeatureAnnotation_doesNotHaveFeature() {
+        assertThat(sTestApis.packages().features()).contains(CHINA_GOOGLE_SERVICES_FEATURE);
+    }
+
+    @Test
+    @RequireDoesNotHaveFeature(CHINA_GOOGLE_SERVICES_FEATURE)
+    public void requireDoesNotHaveFeatureAnnotation_doesNotHaveFeature() {
+        assertThat(sTestApis.packages().features()).doesNotContain(CHINA_GOOGLE_SERVICES_FEATURE);
+    }
+
+    @Test
+    @RequireSdkVersion(min = 27)
+    public void requireSdkVersionAnnotation_min_minIsMet() {
+        assertThat(Build.VERSION.SDK_INT).isGreaterThan(26);
+    }
+
+    @Test
+    @RequireSdkVersion(max = 30)
+    public void requireSdkVersionAnnotation_max_maxIsMet() {
+        assertThat(Build.VERSION.SDK_INT).isLessThan(31);
+    }
+
+    @Test
+    @RequireSdkVersion(min = 27, max = 30)
+    public void requireSdkVersionAnnotation_minAndMax_bothAreMet() {
+        assertThat(Build.VERSION.SDK_INT).isGreaterThan(26);
+        assertThat(Build.VERSION.SDK_INT).isLessThan(31);
+    }
+
+    @Test
+    @RequireRunOnPrimaryUser
+    public void requireRunOnPrimaryUserAnnotation_isRunningOnPrimaryUser() {
+        assertThat(sTestApis.users().instrumented().resolve().type().name())
+                .isEqualTo(SYSTEM_USER_TYPE_NAME);
+    }
+
+    @Test
+    @RequireRunOnTvProfile
+    public void requireRunOnTvProfileAnnotation_isRunningOnTvProfile() {
+        assertThat(sTestApis.users().instrumented().resolve().type().name())
+                .isEqualTo(TV_PROFILE_TYPE_NAME);
+    }
 }
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 298db9d..3b6ec83 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
@@ -46,6 +46,11 @@
 
     static final class MutableUserPackage {
         Set<String> mGrantedPermissions;
+
+        @Override
+        public String toString() {
+            return "UserPackage{grantedPermissions=" + mGrantedPermissions + "}";
+        }
     }
 
     private final MutablePackage mMutablePackage;
@@ -102,7 +107,7 @@
     public String toString() {
         StringBuilder stringBuilder = new StringBuilder("Package{");
         stringBuilder.append("packageName=" + mMutablePackage.mPackageName);
-        stringBuilder.append("installedOnUsers=" + mMutablePackage.mInstalledOnUsers);
+        stringBuilder.append(", installedOnUsers=" + mMutablePackage.mInstalledOnUsers);
         stringBuilder.append("}");
         return stringBuilder.toString();
     }
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/PackageReference.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/PackageReference.java
index f15d9ad..82b36a5 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/PackageReference.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/PackageReference.java
@@ -95,6 +95,24 @@
     }
 
     /**
+     * Uninstall the package for all users.
+     *
+     * <p>The package will no longer {@link #resolve()}.
+     */
+    public PackageReference uninstallFromAllUsers() {
+        Package pkg = resolve();
+        if (pkg == null) {
+            return this;
+        }
+
+        for (UserReference user : pkg.installedOnUsers()) {
+            pkg.uninstall(user);
+        }
+
+        return this;
+    }
+
+    /**
      * Uninstall the package for the given user.
      *
      * <p>If this is the last user which has this package installed, then the package will no
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 3d01d3c..b4f5d62 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
@@ -126,10 +126,17 @@
             throw new NullPointerException();
         }
 
-        if (Versions.isRunningOn(Versions.S, "S")) {
+        if (Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
             return install(user, loadBytes(apkFile));
         }
 
+        User resolvedUser = user.resolve();
+
+        if (resolvedUser == null || resolvedUser.state() != RUNNING_UNLOCKED) {
+            throw new NeneException("Packages can not be installed in non-started users "
+                    + "(Trying to install into user " + resolvedUser + ")");
+        }
+
         BlockingBroadcastReceiver broadcastReceiver = BlockingBroadcastReceiver.create(
                 mTestApis.context().instrumentedContext(), mPackageAddedIntentFilter);
         broadcastReceiver.register();
@@ -144,12 +151,6 @@
 
             return waitForPackageAddedBroadcast(broadcastReceiver);
         } catch (AdbException e) {
-            User resolvedUser = user.resolve();
-
-            if (resolvedUser == null || resolvedUser.state() != RUNNING_UNLOCKED) {
-                throw new NeneException("Packages can not be installed in non-started users "
-                        + "(Trying to install into user " + resolvedUser + ")");
-            }
             throw new NeneException("Could not install " + apkFile + " for user " + user, e);
         } finally {
             broadcastReceiver.unregisterQuietly();
@@ -192,7 +193,7 @@
             throw new NullPointerException();
         }
 
-        //        if (!Versions.isRunningOn(Versions.S, "S")) {
+        //        if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
         return installPreS(user, apkFile);
 //        }
 
@@ -303,7 +304,7 @@
     @RequiresApi(Build.VERSION_CODES.S)
     @CheckResult
     public KeepUninstalledPackagesBuilder keepUninstalledPackages() {
-        Versions.requireS();
+        Versions.requireMinimumVersion(Build.VERSION_CODES.S);
 
         return new KeepUninstalledPackagesBuilder(mTestApis);
     }
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 c0b8031..441d06f 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
@@ -229,7 +229,7 @@
     }
 
     private void recordExistingPermissions() {
-        if (!Versions.isRunningOn(Versions.S, "S")) {
+        if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
             return;
         }
 
@@ -237,7 +237,7 @@
     }
 
     private void restoreExistingPermissions() {
-        if (!Versions.isRunningOn(Versions.S, "S")) {
+        if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
             return;
         }
 
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/ShellCommandUtils.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/ShellCommandUtils.java
index 9995e3d..894667d 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/ShellCommandUtils.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/ShellCommandUtils.java
@@ -64,7 +64,7 @@
             throws AdbException {
         logCommand(command, allowEmptyOutput, stdInBytes);
 
-        if (!Versions.isRunningOn(S, "S")) {
+        if (!Versions.meetsMinimumSdkVersionRequirement(S)) {
             return executeCommandPreS(command, allowEmptyOutput, stdInBytes);
         }
 
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Versions.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Versions.java
index bc33792..e9b7922 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Versions.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Versions.java
@@ -16,30 +16,85 @@
 
 package com.android.bedstead.nene.utils;
 
-import static android.os.Build.VERSION.SDK_INT;
-
 import android.os.Build;
 
-/** Version constants used when VERSION_CODES is not final. */
+import java.lang.reflect.Field;
+
+/** SDK Version checks. */
 public final class Versions {
-    // TODO(scottjonathan): Replace once S version is final
-    public static final int S = 31;
+
+    /** Any version. */
+    public static final int ANY = -1;
+
+    private static final String DEVELOPMENT_CODENAME = "S";
 
     private Versions() {
 
     }
 
-    /** Require that this is running on Android S or above. */
-    public static void requireS() {
-        if (!isRunningOn(S, "S")) {
+    /**
+     * Throw a {@link UnsupportedOperationException} if the minimum version requirement is not met.
+     */
+    public static void requireMinimumVersion(int min) {
+        if (!meetsSdkVersionRequirements(min, ANY)) {
             throw new UnsupportedOperationException(
-                    "keepUninstalledPackages is only available on S+ (currently "
-                            + Build.VERSION.CODENAME + ")");
+                    "Thie feature is only available on "
+                            + versionToLetter(min)
+                            + "+ (currently " + Build.VERSION.CODENAME + ")");
         }
     }
 
-    /** True if the app is running on the given Android version or above. */
-    public static boolean isRunningOn(int version, String codename) {
-        return (SDK_INT >= version || Build.VERSION.CODENAME.equals(codename));
+    private static String versionToLetter(int version) {
+        for (Field field : Build.VERSION_CODES.class.getFields()) {
+            if (!java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
+                continue;
+            }
+            if (!field.getType().equals(int.class)) {
+                continue;
+            }
+            try {
+                int fieldValue = (int) field.get(null);
+
+                if (fieldValue == version) {
+                    return field.getName();
+                }
+            } catch (IllegalAccessException e) {
+                // Couldn't access this variable - ignore
+            }
+        }
+
+        throw new IllegalStateException("Could not find version with code " + version);
+    }
+
+    /**
+     * {@code true} if the minimum version requirement is met.
+     */
+    public static boolean meetsMinimumSdkVersionRequirement(int min) {
+        return meetsSdkVersionRequirements(min, ANY);
+    }
+
+    /**
+     * {@code true} if the minimum and maximum version requirements are met.
+     *
+     * <p>Use {@link #ANY} to accept any version.
+     */
+    public static boolean meetsSdkVersionRequirements(int min, int max) {
+        if (min != ANY) {
+            if (min == Build.VERSION_CODES.CUR_DEVELOPMENT) {
+                if (!Build.VERSION.CODENAME.equals(DEVELOPMENT_CODENAME)) {
+                    return false;
+                }
+            } else if (min > Build.VERSION.SDK_INT) {
+                return false;
+            }
+        }
+
+        if (max != ANY
+                && max != Build.VERSION_CODES.CUR_DEVELOPMENT
+                && max < Build.VERSION.SDK_INT) {
+            return false;
+        }
+
+        return true;
     }
 }
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageReferenceTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageReferenceTest.java
index 60f1cab..bceea8f 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageReferenceTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageReferenceTest.java
@@ -100,6 +100,25 @@
     }
 
     @Test
+    public void uninstallForAllUsers_isUninstalledForAllUsers() {
+        PackageReference pkg = sTestApis.packages().install(sUser, TEST_APP_APK_FILE);
+        try {
+            sTestApis.packages().install(sOtherUser, TEST_APP_APK_FILE);
+
+            mTestAppReference.uninstallFromAllUsers();
+
+            Package resolvedPackage = mTestAppReference.resolve();
+            // Might be null or might still resolve depending on device timing
+            if (resolvedPackage != null) {
+                assertThat(resolvedPackage.installedOnUsers()).isEmpty();
+            }
+        } finally {
+            pkg.uninstall(sUser);
+            pkg.uninstall(sOtherUser);
+        }
+    }
+
+    @Test
     public void uninstall_packageIsInstalledForDifferentUser_isUninstalledForUser() {
         PackageReference pkg = sTestApis.packages().install(sUser, TEST_APP_APK_FILE);
         try {
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 b9535ef..c02f84a 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
@@ -21,6 +21,8 @@
 import static org.junit.Assume.assumeTrue;
 import static org.testng.Assert.assertThrows;
 
+import android.os.Build;
+
 import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.exceptions.NeneException;
 import com.android.bedstead.nene.users.UserReference;
@@ -215,13 +217,9 @@
 
     @Test
     public void install_userNotStarted_throwsException() {
-        UserReference user = mTestApis.users().createUser().create().stop();
-
-        try {
+        try (UserReference user = mTestApis.users().createUser().create().stop()) {
             assertThrows(NeneException.class, () -> mTestApis.packages().install(user,
                     TEST_APP_APK_FILE));
-        } finally {
-            user.remove();
         }
     }
 
@@ -311,7 +309,7 @@
     @Test
     public void keepUninstalledPackages_packageIsUninstalled_packageStillResolves() {
         assumeTrue("keepUninstalledPackages is only supported on S+",
-                Versions.isRunningOn(Versions.S, "S"));
+                Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S));
 
         mTestApis.packages().install(mUser, TEST_APP_APK_FILE);
         mTestApis.packages().keepUninstalledPackages()
@@ -331,7 +329,7 @@
     @Ignore("While using adb calls this is not reliable, enable once we use framework calls for uninstall")
     public void keepUninstalledPackages_packageRemovedFromList_packageIsUninstalled_packageDoesNotResolve() {
         assumeTrue("keepUninstalledPackages is only supported on S+",
-                Versions.isRunningOn(Versions.S, "S"));
+                Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S));
 
         mTestApis.packages().install(mUser, TEST_APP_APK_FILE);
         mTestApis.packages().keepUninstalledPackages()
@@ -354,7 +352,7 @@
     @Ignore("While using adb calls this is not reliable, enable once we use framework calls for uninstall")
     public void keepUninstalledPackages_cleared_packageIsUninstalled_packageDoesNotResolve() {
         assumeTrue("keepUninstalledPackages is only supported on S+",
-                Versions.isRunningOn(Versions.S, "S"));
+                Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S));
 
         mTestApis.packages().install(mUser, TEST_APP_APK_FILE);
 
@@ -376,7 +374,7 @@
     @Ignore("While using adb calls this is not reliable, enable once we use framework calls for uninstall")
     public void keepUninstalledPackages_packageRemovedFromList_packageAlreadyUninstalled_packageDoesNotResolve() {
         assumeTrue("keepUninstalledPackages is only supported on S+",
-                Versions.isRunningOn(Versions.S, "S"));
+                Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S));
 
         mTestApis.packages().install(mUser, TEST_APP_APK_FILE);
         mTestApis.packages().keepUninstalledPackages().add(mTestAppReference).commit();
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/permissions/PermissionsTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/permissions/PermissionsTest.java
index 18eeed7..fad6bd6 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/permissions/PermissionsTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/permissions/PermissionsTest.java
@@ -127,7 +127,7 @@
         assumeTrue("assume shell identity is only available on Q+",
                 Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q);
         assumeFalse("After S, all available permissions are held by shell",
-                Versions.isRunningOn(Versions.S, "S"));
+                Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S));
 
         try (PermissionContext p =
                     sTestApis.permissions().withoutPermission(
@@ -213,32 +213,9 @@
     }
 
     @Test
-    public void withPermissions_androidSAndAbove_restoresPreviousPermissionContext() {
-        assumeTrue("restoring permissions is only available on S+",
-                Versions.isRunningOn(Versions.S, "S"));
-        assumeFalse("After S, all available permissions are held by shell",
-                Versions.isRunningOn(Versions.S, "S"));
-
-        ShellCommandUtils.uiAutomation()
-                .adoptShellPermissionIdentity(DECLARED_PERMISSION_NOT_HELD_BY_SHELL_PRE_S);
-
-        try {
-            PermissionContext p =
-                    sTestApis.permissions()
-                            .withPermission(DECLARED_PERMISSION_NOT_HELD_BY_SHELL_PRE_S);
-            p.close();
-
-            assertThat(sContext.checkSelfPermission(DECLARED_PERMISSION_NOT_HELD_BY_SHELL_PRE_S))
-                    .isEqualTo(PERMISSION_DENIED);
-        } finally {
-            ShellCommandUtils.uiAutomation().dropShellPermissionIdentity();
-        }
-    }
-
-    @Test
     public void withoutPermission_androidSAndAbove_restoresPreviousPermissionContext() {
         assumeTrue("restoring permissions is only available on S+",
-                Versions.isRunningOn(Versions.S, "S"));
+                Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S));
 
         ShellCommandUtils.uiAutomation().adoptShellPermissionIdentity(PERMISSION_HELD_BY_SHELL);
 
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java
index d13e998..f74214b 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java
@@ -61,7 +61,7 @@
 public class BlockingBroadcastReceiver extends BroadcastReceiver implements AutoCloseable {
     private static final String TAG = "BlockingBroadcast";
 
-    private static final int DEFAULT_TIMEOUT_SECONDS = 60;
+    private static final int DEFAULT_TIMEOUT_SECONDS = 240;
 
     private Intent mReceivedIntent = null;
     private final BlockingQueue<Intent> mBlockingQueue;
@@ -215,7 +215,7 @@
     @Override
     public void close() {
         try {
-            awaitForBroadcast();
+            awaitForBroadcastOrFail();
         } finally {
             unregisterQuietly();
         }
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
index 185e714..70c9362 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
@@ -82,19 +82,10 @@
      * Return the first API level for this product. If the read-only property is unset,
      * this means the first API level is the current API level, and the current API level
      * is returned.
-     * If vendor partition has older API level than the first API level, this is a GRF
-     * device and returns the vendor API level, instead.
      */
     public static int getFirstApiLevel() {
         int firstApiLevel = getPropertyInt(FIRST_API_LEVEL);
-        if (firstApiLevel == INT_VALUE_IF_UNSET) {
-            return Build.VERSION.SDK_INT;
-        }
-        int vendorApiLevel = getVendorApiLevel();
-        if (firstApiLevel > vendorApiLevel) {
-            return vendorApiLevel;
-        }
-        return firstApiLevel;
+        return (firstApiLevel == INT_VALUE_IF_UNSET) ? Build.VERSION.SDK_INT : firstApiLevel;
     }
 
     /**
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/WifiConfigCreator.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/WifiConfigCreator.java
index 6e35fe8..f6637e2 100755
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/WifiConfigCreator.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/WifiConfigCreator.java
@@ -34,6 +34,7 @@
 import java.util.Optional;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 /**
  * A simple activity to create and manage wifi configurations.
@@ -108,6 +109,7 @@
             WifiConfiguration conf = getWifiConfigurationBySsid(ssid);
             retrievedPacProxyUrl = getPacProxyUrl(conf);
 
+            Log.d(TAG, "calling removeNetwork(" + netId + ")");
             if (!mWifiManager.removeNetwork(netId)) {
                 throw new IllegalStateException("Failed to remove WifiConfiguration: " + ssid);
             }
@@ -132,7 +134,9 @@
             conf.setHttpProxy(ProxyInfo.buildPacProxy(Uri.parse(pacProxyUrl)));
         }
 
+        Log.d(TAG, "addNetworkWithProxy(ssid=" + ssid + ", pacProxyUrl=" + pacProxyUrl);
         int netId = mWifiManager.addNetwork(conf);
+        Log.d(TAG, "added: netId=" + netId);
         if (netId == -1) {
             throw new IllegalStateException("Failed to addNetwork: " + ssid);
         }
@@ -142,12 +146,13 @@
     private WifiConfiguration getWifiConfigurationBySsid(String ssid) {
         WifiConfiguration wifiConfiguration = null;
         String expectedSsid = wrapInQuotes(ssid);
-
-        for (final WifiConfiguration w : mWifiManager.getConfiguredNetworks()) {
+        List<WifiConfiguration> configuredNetworks = getConfiguredNetworks();
+        for (WifiConfiguration w : configuredNetworks) {
             if (w.SSID.equals(expectedSsid)) {
                 wifiConfiguration = w;
                 break;
             }
+            Log.v(TAG, "skipping " + w.SSID);
         }
         if (wifiConfiguration == null) {
             throw new IllegalStateException("Failed to get WifiConfiguration for: " + ssid);
@@ -172,8 +177,11 @@
         int newNetId = mWifiManager.updateNetwork(conf);
 
         if (newNetId != -1) {
+            Log.v(TAG, "calling saveConfiguration()");
             mWifiManager.saveConfiguration();
+            Log.v(TAG, "calling enableNetwork(" + newNetId + ")");
             mWifiManager.enableNetwork(newNetId, true);
+            Log.v(TAG, "enabled");
         } else {
             Log.w(TAG, "Unable to update SSID '" + ssid + "': netId = " + newNetId);
         }
@@ -186,21 +194,26 @@
      */
     public int updateNetwork(int netId, String ssid, boolean hidden,
             int securityType, String password) throws InterruptedException, SecurityException {
+        Log.d(TAG, "updateNetwork(): netId= " + netId + ", ssid=" + ssid + ", hidden=" + hidden);
         checkAndEnableWifi();
 
         WifiConfiguration wifiConf = null;
-        List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+        List<WifiConfiguration> configs = getConfiguredNetworks();
         for (WifiConfiguration config : configs) {
             if (config.networkId == netId) {
                 wifiConf = config;
                 break;
             }
+            Log.v(TAG, "skipping " + config.networkId);
         }
         return updateNetwork(wifiConf, ssid, hidden, securityType, password);
     }
 
     public boolean removeNetwork(int netId) {
-        return mWifiManager.removeNetwork(netId);
+        Log.v(TAG, "calling removeNetwork(" + netId + ")");
+        boolean removed = mWifiManager.removeNetwork(netId);
+        Log.v(TAG, "removed: " + removed);
+        return removed;
     }
 
     /**
@@ -264,6 +277,7 @@
         final BroadcastReceiver watcher = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
+                Log.d(TAG, "Received intent " + intent.getAction());
                 if (intent.getIntExtra(EXTRA_WIFI_STATE, -1) == WIFI_STATE_ENABLED) {
                     enabledLatch.countDown();
                 }
@@ -274,7 +288,9 @@
         try {
             // In case wifi is not already enabled, wait for it to come up
             if (!mWifiManager.isWifiEnabled()) {
+                Log.v(TAG, "Calling setWifiEnabled(true)");
                 mWifiManager.setWifiEnabled(true);
+                Log.v(TAG, "enabled");
                 enabledLatch.await(ENABLE_WIFI_WAIT_SEC, TimeUnit.SECONDS);
             }
         } finally {
@@ -285,5 +301,13 @@
     private String wrapInQuotes(String ssid) {
         return '"' + ssid + '"';
     }
+
+    private List<WifiConfiguration> getConfiguredNetworks() {
+        Log.d(TAG, "calling getConfiguredNetworks() on " + mWifiManager);
+        List<WifiConfiguration> configuredNetworks = mWifiManager.getConfiguredNetworks();
+        Log.d(TAG, "Got " + configuredNetworks.size() + " networks: "
+                + configuredNetworks.stream().map((c) -> c.SSID).collect(Collectors.toList()));
+        return configuredNetworks;
+    }
 }
 
diff --git a/hostsidetests/appsearch/src/android/appsearch/cts/AppSearchHostTestBase.java b/hostsidetests/appsearch/src/android/appsearch/cts/AppSearchHostTestBase.java
index 468997f..c4c76de 100644
--- a/hostsidetests/appsearch/src/android/appsearch/cts/AppSearchHostTestBase.java
+++ b/hostsidetests/appsearch/src/android/appsearch/cts/AppSearchHostTestBase.java
@@ -16,7 +16,14 @@
 
 package android.appsearch.cts;
 
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
+
+import java.util.Map;
+
+import javax.annotation.Nonnull;
 
 public abstract class AppSearchHostTestBase extends BaseHostJUnit4Test {
     protected static final String TARGET_APK_A = "CtsAppSearchHostTestHelperA.apk";
@@ -26,15 +33,35 @@
     protected static final String TARGET_PKG_B = "android.appsearch.app.b";
     protected static final String TEST_CLASS_B = TARGET_PKG_B + ".AppSearchDeviceTest";
 
+    protected static final String USER_ID_KEY = "userId";
+
     protected static final long DEFAULT_INSTRUMENTATION_TIMEOUT_MS = 600_000; // 10min
 
-    protected void runDeviceTestAsUserInPkgA(String testMethod, int userId) throws Exception {
-        runDeviceTests(getDevice(), TARGET_PKG_A, TEST_CLASS_A, testMethod, userId,
-                DEFAULT_INSTRUMENTATION_TIMEOUT_MS);
+    protected void runDeviceTestAsUserInPkgA(@Nonnull String testMethod, int userId)
+            throws Exception {
+        assertWithMessage(testMethod + " failed").that(
+                runDeviceTests(getDevice(), TARGET_PKG_A, TEST_CLASS_A, testMethod, userId,
+                        DEFAULT_INSTRUMENTATION_TIMEOUT_MS)).isTrue();
     }
 
-    protected void runDeviceTestAsUserInPkgB(String testMethod, int userId) throws Exception {
-        runDeviceTests(getDevice(), TARGET_PKG_B, TEST_CLASS_B, testMethod, userId,
-                DEFAULT_INSTRUMENTATION_TIMEOUT_MS);
+    protected void runDeviceTestAsUserInPkgA(@Nonnull String testMethod, int userId,
+            @Nonnull Map<String, String> args) throws Exception {
+        DeviceTestRunOptions deviceTestRunOptions = new DeviceTestRunOptions(TARGET_PKG_A)
+                .setTestClassName(TEST_CLASS_A)
+                .setTestMethodName(testMethod)
+                .setMaxInstrumentationTimeoutMs(DEFAULT_INSTRUMENTATION_TIMEOUT_MS)
+                .setUserId(userId);
+        for (Map.Entry<String, String> entry : args.entrySet()) {
+            deviceTestRunOptions.addInstrumentationArg(entry.getKey(), entry.getValue());
+        }
+        assertWithMessage(testMethod + " failed").that(
+                runDeviceTests(deviceTestRunOptions)).isTrue();
+    }
+
+    protected void runDeviceTestAsUserInPkgB(@Nonnull String testMethod, int userId)
+            throws Exception {
+        assertWithMessage(testMethod + " failed").that(
+                runDeviceTests(getDevice(), TARGET_PKG_B, TEST_CLASS_B, testMethod, userId,
+                        DEFAULT_INSTRUMENTATION_TIMEOUT_MS)).isTrue();
     }
 }
diff --git a/hostsidetests/appsearch/src/android/appsearch/cts/AppSearchMultiUserTestBase.java b/hostsidetests/appsearch/src/android/appsearch/cts/AppSearchMultiUserTest.java
similarity index 68%
rename from hostsidetests/appsearch/src/android/appsearch/cts/AppSearchMultiUserTestBase.java
rename to hostsidetests/appsearch/src/android/appsearch/cts/AppSearchMultiUserTest.java
index 8696b69..6990ace 100644
--- a/hostsidetests/appsearch/src/android/appsearch/cts/AppSearchMultiUserTestBase.java
+++ b/hostsidetests/appsearch/src/android/appsearch/cts/AppSearchMultiUserTest.java
@@ -17,7 +17,6 @@
 package android.appsearch.cts;
 
 import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assume.assumeTrue;
 
@@ -28,18 +27,23 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Collections;
+import java.util.Map;
+
 /**
- * Test to mock multi-user interacting with AppSearch.
+ * Test to cover multi-user interacting with AppSearch.
  *
  * <p>This test is split into two distinct parts: The first part is the test-apps that runs on the
- * device and interactive with AppSearch.This class is the second part that runs on the host and
+ * device and interactive with AppSearch. This class is the second part that runs on the host and
  * triggers tests in the first part for different users.
  *
  * <p>To trigger a device test, call runDeviceTestAsUser with a specific the test name and specific
  * user.
+ *
+ * <p>Unlock your device when test locally.
  */
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class AppSearchMultiUserTestBase extends AppSearchHostTestBase {
+public class AppSearchMultiUserTest extends AppSearchHostTestBase {
 
     private int mInitialUserId;
     private int mSecondaryUserId;
@@ -75,4 +79,21 @@
         // Cannot get the document from another user.
         runDeviceTestAsUserInPkgA("testGetDocuments_nonexist", mInitialUserId);
     }
+
+    @Test
+    public void testCreateSessionInStoppedUser() throws Exception {
+        Map<String, String> args =
+                Collections.singletonMap(USER_ID_KEY, String.valueOf(mSecondaryUserId));
+        getDevice().stopUser(mSecondaryUserId, /*waitFlag=*/true, /*forceFlag=*/true);
+        runDeviceTestAsUserInPkgA("createSessionInStoppedUser", mInitialUserId, args);
+    }
+
+    @Test
+    public void testStopUser_persistData() throws Exception {
+        runDeviceTestAsUserInPkgA("testPutDocuments", mSecondaryUserId);
+        runDeviceTestAsUserInPkgA("testGetDocuments_exist", mSecondaryUserId);
+        getDevice().stopUser(mSecondaryUserId, /*waitFlag=*/true, /*forceFlag=*/true);
+        getDevice().startUser(mSecondaryUserId, /*waitFlag=*/true);
+        runDeviceTestAsUserInPkgA("testGetDocuments_exist", mSecondaryUserId);
+    }
 }
diff --git a/hostsidetests/appsearch/src/android/appsearch/cts/AppSearchPackageTestBase.java b/hostsidetests/appsearch/src/android/appsearch/cts/AppSearchPackageTest.java
similarity index 76%
rename from hostsidetests/appsearch/src/android/appsearch/cts/AppSearchPackageTestBase.java
rename to hostsidetests/appsearch/src/android/appsearch/cts/AppSearchPackageTest.java
index ef1d089..45f4f70 100644
--- a/hostsidetests/appsearch/src/android/appsearch/cts/AppSearchPackageTestBase.java
+++ b/hostsidetests/appsearch/src/android/appsearch/cts/AppSearchPackageTest.java
@@ -16,18 +16,26 @@
 
 package android.appsearch.cts;
 
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assume.assumeTrue;
-
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+/**
+ * Test to cover install and uninstall packages with AppSearch.
+ *
+ * <p>This test is split into two distinct parts: The first part is the test-apps that runs on the
+ * device and interactive with AppSearch. This class is the second part that runs on the host and
+ * triggers tests in the first part for different users.
+ *
+ * <p>To trigger a device test, call runDeviceTestAsUser with a specific the test name and specific
+ * user.
+ *
+ * <p>Unlock your device when test locally.
+ */
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class AppSearchPackageTestBase extends AppSearchHostTestBase {
+public class AppSearchPackageTest extends AppSearchHostTestBase {
 
     private int mPrimaryUserId;
 
diff --git a/hostsidetests/appsearch/test-apps/AppSearchHostTestHelperA/src/android/appsearch/app/a/AppSearchDeviceTest.java b/hostsidetests/appsearch/test-apps/AppSearchHostTestHelperA/src/android/appsearch/app/a/AppSearchDeviceTest.java
index 479a613..212f0a3 100644
--- a/hostsidetests/appsearch/test-apps/AppSearchHostTestHelperA/src/android/appsearch/app/a/AppSearchDeviceTest.java
+++ b/hostsidetests/appsearch/test-apps/AppSearchHostTestHelperA/src/android/appsearch/app/a/AppSearchDeviceTest.java
@@ -21,6 +21,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.testng.Assert.expectThrows;
+
+import android.app.UiAutomation;
 import android.app.appsearch.AppSearchBatchResult;
 import android.app.appsearch.AppSearchManager;
 import android.app.appsearch.AppSearchResult;
@@ -31,8 +34,10 @@
 import android.app.appsearch.PackageIdentifier;
 import android.app.appsearch.PutDocumentsRequest;
 import android.app.appsearch.SetSchemaRequest;
+import android.os.Bundle;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.server.appsearch.testing.AppSearchSessionShimImpl;
 
@@ -43,12 +48,15 @@
 import org.junit.runner.RunWith;
 
 import java.util.List;
+import java.util.concurrent.ExecutionException;
+
 @RunWith(AndroidJUnit4.class)
 public class AppSearchDeviceTest {
 
     private static final String DB_NAME = "";
     private static final String NAMESPACE = "namespace";
     private static final String ID = "id";
+    private static final String USER_ID_KEY = "userId";
     private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder("testSchema")
             .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("subject")
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
@@ -77,11 +85,13 @@
             "3D7A1AAE7AE8B9949BE93E071F3702AA38695B0F99B5FC4B2E8B364AC78FFDB2");
 
     private AppSearchSessionShim mDb;
+    private UiAutomation mUiAutomation;
 
     @Before
     public void setUp() throws Exception {
         mDb = AppSearchSessionShimImpl.createSearchSession(
                 new AppSearchManager.SearchContext.Builder(DB_NAME).build()).get();
+        mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
     }
 
     @Test
@@ -122,4 +132,21 @@
     public void clearTestData() throws Exception {
         mDb.setSchema(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
     }
+
+    @Test
+    public void createSessionInStoppedUser() {
+        mUiAutomation.adoptShellPermissionIdentity(
+                "android.permission.INTERACT_ACROSS_USERS_FULL");
+        try {
+            Bundle args = InstrumentationRegistry.getArguments();
+            int userId = Integer.parseInt(args.getString(USER_ID_KEY));
+            ExecutionException exception = expectThrows(ExecutionException.class, () ->
+                    AppSearchSessionShimImpl.createSearchSession(
+                            new AppSearchManager.SearchContext.Builder(DB_NAME).build(),
+                            userId).get());
+            assertThat(exception.getMessage()).contains("is locked or not running.");
+        } finally {
+            mUiAutomation.dropShellPermissionIdentity();
+        }
+    }
 }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ReadableSettingsFieldsTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ReadableSettingsFieldsTest.java
index e38eb0a..67fba8ace 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ReadableSettingsFieldsTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ReadableSettingsFieldsTest.java
@@ -91,6 +91,13 @@
     }
 
     @Test
+    public void testGlobalHiddenSettingsKeyNotReadableWithoutPermissions() throws
+            DeviceNotAvailableException {
+        runDeviceTests(TEST_PACKAGE, TEST_CLASS,
+                "testGlobalHiddenSettingsKeyNotReadableWithoutPermissions");
+    }
+
+    @Test
     public void testSecureHiddenSettingsKeysNotReadableWithoutAnnotation()
             throws DeviceNotAvailableException {
         runDeviceTests(TEST_PACKAGE, TEST_CLASS,
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk
index 9b7eae3..bbb312f 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgradeWrongSHA.apk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgradeWrongSHA.apk
index b6baab3..d2bf4e4 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgradeWrongSHA.apk
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgradeWrongSHA.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgrade.apk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgrade.apk
index b34d7a0..9f4ea15 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgrade.apk
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgrade.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgradeWrongSHA.apk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgradeWrongSHA.apk
index 7e8d3a7..4ce0f37 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgradeWrongSHA.apk
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgradeWrongSHA.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/test-apps/ReadSettingsFieldsApp/src/com/android/cts/readsettingsfieldsapp/ReadSettingsFieldsTest.java b/hostsidetests/appsecurity/test-apps/ReadSettingsFieldsApp/src/com/android/cts/readsettingsfieldsapp/ReadSettingsFieldsTest.java
index e7c6638..c28032f 100644
--- a/hostsidetests/appsecurity/test-apps/ReadSettingsFieldsApp/src/com/android/cts/readsettingsfieldsapp/ReadSettingsFieldsTest.java
+++ b/hostsidetests/appsecurity/test-apps/ReadSettingsFieldsApp/src/com/android/cts/readsettingsfieldsapp/ReadSettingsFieldsTest.java
@@ -49,6 +49,10 @@
                 if (isSettingsDeprecated(ex)) {
                     continue;
                 }
+                /** b/174151290 skip it due to it's @hide but also @TestApi */
+                if (key.equals(Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT)) {
+                    continue;
+                }
                 fail("Reading public " + settingsClass.getSimpleName() + " settings key <" + key
                         + "> should not raise exception! "
                         + "Did you forget to add @Readable annotation?\n" + ex.getMessage());
@@ -156,6 +160,23 @@
                 publicSettingsKeys, hiddenSettingsKeys);
     }
 
+    // test the cases that hidden keys are marked with readable annotation but access should be
+    // protected by additional permission check.
+    public void testGlobalHiddenSettingsKeyNotReadableWithoutPermissions() {
+        final String[] hiddenSettingsKeysRequiresPermissions = {"multi_sim_data_call"};
+        for (String key : hiddenSettingsKeysRequiresPermissions) {
+            try {
+                // Verify that the hidden keys can't be accessed due to lack of permissions.
+                callGetStringMethod(Settings.Global.class, key);
+            } catch (SecurityException ex) {
+                assertTrue(ex.getMessage().contains("permission"));
+                continue;
+            }
+            fail("Reading hidden " + Settings.Global.class.getSimpleName() + " settings key <" + key
+                    + "> should be protected with permission!");
+        }
+    }
+
     private <T extends Settings.NameValueTable>
     void testHiddenSettingsKeysNotReadableWithoutAnnotation(
             Class<T> settingsClass, ArraySet<String> publicKeys, String[] targetKeys) {
diff --git a/hostsidetests/car/src/android/car/cts/PowerPolicyHostTest.java b/hostsidetests/car/src/android/car/cts/PowerPolicyHostTest.java
index 6a7f414..c199b5b 100644
--- a/hostsidetests/car/src/android/car/cts/PowerPolicyHostTest.java
+++ b/hostsidetests/car/src/android/car/cts/PowerPolicyHostTest.java
@@ -56,6 +56,7 @@
         testHelper.checkCurrentPolicy(PowerPolicyDef.IdSet.NO_USER_INTERACTION);
         testHelper.checkSilentModeStatus(true);
         testHelper.checkSilentModeFull(SilentModeInfo.FORCED_SILENT);
+        testHelper.checkCurrentPowerComponents(PowerPolicyDef.PolicySet.NO_USER_INTERACT);
 
         teststep = "restore to normal mode";
         restoreFromForcedSilentMode();
@@ -64,8 +65,15 @@
         testHelper.checkCurrentPolicy(PowerPolicyDef.IdSet.DEFAULT_ALL_ON);
         testHelper.checkSilentModeStatus(false);
         testHelper.checkSilentModeFull(SilentModeInfo.NO_SILENT);
+        testHelper.checkCurrentPowerComponents(PowerPolicyDef.PolicySet.DEFAULT_ALL_ON);
     }
 
+    /**
+     * Tests the error conditions for CPMS at the ON state.
+     *
+     * <p>All other VHAL events but {@code SHUTDOWN_PREPARE} shall not have any impact
+     * to CPMS power state.
+     */
     @Test
     public void testDefaultStateMachineAtONState() throws Exception {
         String testcase = "testDefaultStateMachineAtONState:";
@@ -80,8 +88,6 @@
             PowerPolicyConstants.VhalPowerStateReq.FINISHED
         };
 
-        // CPMS is at the ON state. All other VHAL events but SHUTDOWN_PREPARE
-        // will not have any impact to CPMS
         for (int i = 0; i < stepNames.length; i++) {
             triggerVhalPowerStateReq(vhalReqs[i], PowerPolicyConstants.ShutdownParam.NOT_USED);
             PowerPolicyTestHelper testHelper = getTestHelper(testcase, i + 1, stepNames[i]);
diff --git a/hostsidetests/car/src/android/car/cts/powerpolicy/CpmsFrameworkLayerStateInfo.java b/hostsidetests/car/src/android/car/cts/powerpolicy/CpmsFrameworkLayerStateInfo.java
index 3d3f176..33ac06a 100644
--- a/hostsidetests/car/src/android/car/cts/powerpolicy/CpmsFrameworkLayerStateInfo.java
+++ b/hostsidetests/car/src/android/car/cts/powerpolicy/CpmsFrameworkLayerStateInfo.java
@@ -34,7 +34,8 @@
     public static final String PENDING_POLICY_ID_HDR = "mPendingPowerPolicyId:";
     public static final String CURRENT_POLICY_GROUP_ID_HDR = "mCurrentPowerPolicyGroupId:";
     public static final String COMPONENT_STATE_HDR = "Power components state:";
-    public static final String COMPONENT_CONTROLLED_HDR = "Components controlled by user:";
+    public static final String COMPONENT_CONTROLLED_HDR =
+            "Components powered off by power policy:";
     public static final String COMPONENT_CHANGED_HDR = "Components changed by the last policy:";
     public static final String MONITORING_HW_HDR = "Monitoring HW state signal:";
     public static final String SILENT_MODE_BY_HW_HDR = "Silent mode by HW state signal:";
@@ -94,6 +95,14 @@
         return mForcedSilentMode;
     }
 
+    public PowerPolicyDef.PowerComponent[] getCurrentEnabledComponents() {
+        return PowerPolicyDef.PowerComponent.asComponentArray(mEnables);
+    }
+
+    public PowerPolicyDef.PowerComponent[] getCurrentDisabledComponents() {
+        return PowerPolicyDef.PowerComponent.asComponentArray(mDisables);
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder(STRING_BUILDER_BUF_SIZE);
@@ -170,14 +179,16 @@
                     currentPolicyGroupId = parser.getStringData(CURRENT_POLICY_GROUP_ID_HDR);
                     break;
                 case COMPONENT_STATE_HDR:
-                    parser.parseComponentStates(COMPONENT_STATE_HDR, COMPONENT_CONTROLLED_HDR);
+                    parser.parseComponentStates(COMPONENT_STATE_HDR,
+                            COMPONENT_CONTROLLED_HDR, true);
                     enables = parser.getEnables();
                     disables = parser.getDisables();
                     Collections.sort(enables);
                     Collections.sort(disables);
                     break;
                 case COMPONENT_CONTROLLED_HDR:
-                    parser.parseComponentStates(COMPONENT_CONTROLLED_HDR, COMPONENT_CHANGED_HDR);
+                    parser.parseComponentStates(COMPONENT_CONTROLLED_HDR,
+                            COMPONENT_CHANGED_HDR, false);
                     controlledEnables = parser.getEnables();
                     controlledDisables = parser.getDisables();
                     Collections.sort(controlledEnables);
@@ -269,13 +280,14 @@
             return val;
         }
 
-        private void parseComponentStates(String startHdr, String endHdr) throws Exception {
+        private void parseComponentStates(String startHdr, String endHdr,
+                boolean hasStateInfo) throws Exception {
             mEnables = new ArrayList<String>();
             mDisables = new ArrayList<String>();
             while (mIdx < (mLines.length - 1) && !mLines[++mIdx].contains(endHdr)) {
                 String stateStr = mLines[mIdx].trim();
                 String[] vals = stateStr.split(":\\s");
-                if (vals.length != 2) {
+                if (hasStateInfo && vals.length != 2) {
                     String errMsg = String.format("wrong format at %d in: %s ", mIdx, stateStr);
                     CLog.e(errMsg);
                     throw new IllegalArgumentException(errMsg);
@@ -292,15 +304,20 @@
                     throw new IllegalArgumentException(errMsg);
                 }
 
-                if (vals[1].startsWith("on")) {
-                    mEnables.add(vals[0]);
-                } else if (vals[1].startsWith("off")) {
-                    mDisables.add(vals[0]);
+                if (hasStateInfo) {
+                    if (vals[1].startsWith("on")) {
+                        mEnables.add(vals[0]);
+                    } else if (vals[1].startsWith("off")) {
+                        mDisables.add(vals[0]);
+                    } else {
+                        String errMsg =
+                                String.format("wrong state value at %d with (%s, %s) in: %s",
+                                mIdx, vals[0], vals[1], stateStr);
+                        CLog.e(errMsg);
+                        throw new IllegalArgumentException(errMsg);
+                    }
                 } else {
-                    String errMsg = String.format("wrong state value at %d with (%s, %s) in: %s",
-                            mIdx, vals[0], vals[1], stateStr);
-                    CLog.e(errMsg);
-                    throw new IllegalArgumentException(errMsg);
+                    mDisables.add(vals[0]);
                 }
             }
             mIdx--;
diff --git a/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyDef.java b/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyDef.java
index 1904785..70d7354 100644
--- a/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyDef.java
+++ b/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyDef.java
@@ -19,6 +19,7 @@
 import com.android.tradefed.log.LogUtil.CLog;
 
 import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 import java.util.StringTokenizer;
 
@@ -43,10 +44,20 @@
         return mPolicyId;
     }
 
+    public PowerComponent[] getEnables() {
+        return mEnables;
+    }
+
+    public PowerComponent[] getDisables() {
+        return mDisables;
+    }
+
     @Override
     public String toString() {
-        String[] enables = Arrays.stream(mEnables).map(c -> c.value).toArray(i -> new String[i]);
-        String[] disables = Arrays.stream(mDisables).map(c -> c.value).toArray(i -> new String[i]);
+        String[] enables = Arrays.stream(mEnables).map(PowerComponent::getValue)
+                .toArray(String[]::new);
+        String[] disables = Arrays.stream(mDisables).map(PowerComponent::getValue)
+                .toArray(String[]::new);
         StringBuilder str = new StringBuilder();
         str.append(mPolicyId);
         if (!enables[0].equals("none")) {
@@ -110,12 +121,7 @@
             throw new IllegalArgumentException("malformatted disabled headers string: "
                     + policyDefStr);
         }
-        PowerComponent[] enabledComps = null;
-        if (enables != null) {
-            normalizeComponentName(enables);
-            enabledComps = Arrays.stream(enables)
-                    .map(e -> PowerComponent.valueOf(e)).toArray(n -> new PowerComponent[n]);
-        }
+        PowerComponent[] enabledComps = PowerComponent.asComponentArray(enables);
 
         String[] disables = null;
         tmpStr = tokens.nextToken().trim();
@@ -123,34 +129,11 @@
         if (!tmpStr.isEmpty()) {
             disables = tmpStr.split(",\\s*");
         }
-        PowerComponent[] disabledComps = null;
-        if (disables != null) {
-            normalizeComponentName(disables);
-            disabledComps = Arrays.stream(disables)
-                    .map(e -> PowerComponent.valueOf(e)).toArray(n -> new PowerComponent[n]);
-        }
+        PowerComponent[] disabledComps = PowerComponent.asComponentArray(disables);
 
         return new PowerPolicyDef(policyId, enabledComps, disabledComps);
     }
 
-    private static void normalizeComponentName(String[] comps) throws Exception {
-        for (int i = 0; i < comps.length; i++) {
-            try {
-                PowerComponent.valueOf(comps[i]);
-            } catch (Exception e) {
-                if (comps[i] == null || comps[i].isEmpty()) {
-                    throw new IllegalArgumentException("empty PowerComponent name at " + i);
-                }
-
-                if (comps[i].equals("none")) {
-                    comps[i] = "NONE";
-                } else {
-                    throw new IllegalArgumentException("unknown PowerComponent: " + comps[i]);
-                }
-            }
-        }
-    }
-
     private static boolean search(String[] strList, String str) {
         return Arrays.stream(strList).anyMatch(s -> str.contains(s));
     }
@@ -186,10 +169,44 @@
         MICROPHONE("MICROPHONE"),
         CPU("CPU");
 
-        public final String value;
+        private final String mValue;
 
         PowerComponent(String v) {
-            value = v;
+            mValue = v;
+        }
+
+        public String getValue() {
+            return mValue;
+        }
+
+        public static PowerComponent[] asComponentArray(String[] componentNames) {
+            if (componentNames == null) {
+                return new PowerComponent[0];
+            }
+            normalizeComponentName(componentNames);
+            PowerComponent[] compArray = Arrays.stream(componentNames)
+                    .map(PowerComponent::valueOf).toArray(PowerComponent[]::new);
+            Arrays.sort(compArray);
+            return compArray;
+        }
+
+        public static PowerComponent[] asComponentArray(List<String> nameList) {
+            if (nameList == null) {
+                return new PowerComponent[0];
+            }
+            return asComponentArray(nameList.toArray(new String[0]));
+        }
+
+        private static void normalizeComponentName(String[] comps) {
+            for (int i = 0; i < comps.length; i++) {
+                try {
+                    PowerComponent.valueOf(comps[i]);
+                } catch (Exception e) {
+                    if (comps[i] != null && comps[i].equals("none")) {
+                        comps[i] = "NONE";
+                    }
+                }
+            }
         }
     }
 
diff --git a/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyTestHelper.java b/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyTestHelper.java
index 327ca1c..0e61af9 100644
--- a/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyTestHelper.java
+++ b/hostsidetests/car/src/android/car/cts/powerpolicy/PowerPolicyTestHelper.java
@@ -16,6 +16,7 @@
 
 package android.car.cts.powerpolicy;
 
+import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import com.android.tradefed.log.LogUtil.CLog;
@@ -29,6 +30,7 @@
 
     public static final String CURRENT_STATE_ASSERT_MSG = "current state";
     public static final String CURRENT_POLICY_ASSERT_MSG = "current policy";
+    public static final String CURRENT_POWER_COMPONENT_ASSERT_MSG = "current power components";
     public static final String REGISTERED_POLICY_ASSERT_MSG = "registered policy";
     public static final String SILENT_MODE_FULL_ASSERT_MSG = "silent mode in full";
     public static final String SILENT_MODE_STATUS_ASSERT_MSG = "silent mode status";
@@ -118,4 +120,11 @@
         assertWithMessage(TOTAL_REGISTERED_POLICIES_ASSERT_MSG)
                 .that(mSystemCpms.getRegisteredPolicies().size() == totalNum).isTrue();
     }
+
+    public void checkCurrentPowerComponents(PowerPolicyDef expected) throws Exception {
+        assertThat(mFrameCpms.getCurrentEnabledComponents()).asList()
+                .containsExactlyElementsIn(expected.getEnables());
+        assertThat(mFrameCpms.getCurrentDisabledComponents()).asList()
+                .containsExactlyElementsIn(expected.getDisables());
+    }
 }
diff --git a/hostsidetests/car/src/android/car/cts/powerpolicy/SystemInfoParser.java b/hostsidetests/car/src/android/car/cts/powerpolicy/SystemInfoParser.java
index 39f83b8..09506e2 100644
--- a/hostsidetests/car/src/android/car/cts/powerpolicy/SystemInfoParser.java
+++ b/hostsidetests/car/src/android/car/cts/powerpolicy/SystemInfoParser.java
@@ -35,7 +35,7 @@
             Object ret = m.invoke(null, cmdOutput);
             t = mType.cast(ret);
         } catch (Exception e) {
-            CLog.e("%s: %s", mType.getSimpleName(), e.toString());
+            CLog.wtf("ERROR: Apply failed with " + cmdOutput, e);
         }
         return t;
     }
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiSetHttpProxyTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiSetHttpProxyTest.java
index cddc732..4bd7670 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiSetHttpProxyTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiSetHttpProxyTest.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.deviceowner;
 
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import android.content.pm.PackageManager;
 
 import com.android.compatibility.common.util.WifiConfigCreator;
@@ -43,8 +45,9 @@
             return;
         }
         WifiConfigCreator configCreator = new WifiConfigCreator(mContext, mWifiManager);
-        String retreievedPacProxyUrl = configCreator.addHttpProxyNetworkVerifyAndRemove(
+        String retrievedPacProxyUrl = configCreator.addHttpProxyNetworkVerifyAndRemove(
                 TEST_SSID, TEST_PAC_URL);
-        assertEquals(TEST_PAC_URL, retreievedPacProxyUrl);
+        assertWithMessage("pacProxyUrl for SSID %s", TEST_SSID).that(retrievedPacProxyUrl)
+                .isEqualTo(TEST_PAC_URL);
     }
 }
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BluetoothTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BluetoothTest.java
index 4d7ddeb..322bf71 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BluetoothTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BluetoothTest.java
@@ -16,13 +16,17 @@
 
 package com.android.cts.managedprofile;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothServerSocket;
+import android.content.Intent;
 import android.test.AndroidTestCase;
 
+import com.android.compatibility.common.util.BlockingBroadcastReceiver;
+
 import java.io.IOException;
-import java.util.Set;
 import java.util.UUID;
 
 /**
@@ -36,11 +40,6 @@
  * TODO: Merge the primary and managed profile tests into one.
  */
 public class BluetoothTest extends AndroidTestCase {
-    private static final int DISABLE_TIMEOUT_MS = 8000;
-    private static final int ENABLE_TIMEOUT_MS = 10000;
-    private static final int POLL_TIME_MS = 400;
-    private static final int CHECK_WAIT_TIME_MS = 1000;
-
     private BluetoothAdapter mAdapter;
     private boolean mBtWasEnabled;
 
@@ -133,32 +132,21 @@
      * Behavior of getState() and isEnabled() are validated along the way.
      */
     private void disable() {
-        sleep(CHECK_WAIT_TIME_MS);
         if (mAdapter.getState() == BluetoothAdapter.STATE_OFF) {
             assertFalse(mAdapter.isEnabled());
             return;
         }
 
-        assertEquals(BluetoothAdapter.STATE_ON, mAdapter.getState());
-        assertTrue(mAdapter.isEnabled());
-        assertTrue(mAdapter.disable());
-        boolean turnOff = false;
-        for (int i=0; i<DISABLE_TIMEOUT_MS/POLL_TIME_MS; i++) {
-            sleep(POLL_TIME_MS);
-            int state = mAdapter.getState();
-            switch (state) {
-            case BluetoothAdapter.STATE_OFF:
-                assertFalse(mAdapter.isEnabled());
-                return;
-            default:
-                if (state != BluetoothAdapter.STATE_ON || turnOff) {
-                    assertEquals(BluetoothAdapter.STATE_TURNING_OFF, state);
-                    turnOff = true;
-                }
-                break;
-            }
+        assertThat(mAdapter.getState()).isEqualTo(BluetoothAdapter.STATE_ON);
+        assertThat(mAdapter.isEnabled()).isTrue();
+        assertThat(mAdapter.disable()).isTrue();
+        try (BlockingBroadcastReceiver r = new BlockingBroadcastReceiver(
+                mContext,
+                BluetoothAdapter.ACTION_STATE_CHANGED,
+                this::isStateDisabled).register()) {
+            assertThat(mAdapter.disable()).isTrue();
         }
-        fail("disable() timeout");
+        assertThat(mAdapter.isEnabled()).isFalse();
     }
 
     /**
@@ -167,37 +155,29 @@
      * Behavior of getState() and isEnabled() are validated along the way.
      */
     private void enable() {
-        sleep(CHECK_WAIT_TIME_MS);
         if (mAdapter.getState() == BluetoothAdapter.STATE_ON) {
             assertTrue(mAdapter.isEnabled());
             return;
         }
 
-        assertEquals(BluetoothAdapter.STATE_OFF, mAdapter.getState());
-        assertFalse(mAdapter.isEnabled());
-        assertTrue(mAdapter.enable());
-        boolean turnOn = false;
-        for (int i=0; i<ENABLE_TIMEOUT_MS/POLL_TIME_MS; i++) {
-            sleep(POLL_TIME_MS);
-            int state = mAdapter.getState();
-            switch (state) {
-            case BluetoothAdapter.STATE_ON:
-                assertTrue(mAdapter.isEnabled());
-                return;
-            default:
-                if (state != BluetoothAdapter.STATE_OFF || turnOn) {
-                    assertEquals(BluetoothAdapter.STATE_TURNING_ON, state);
-                    turnOn = true;
-                }
-                break;
-            }
+        assertThat(mAdapter.getState()).isEqualTo(BluetoothAdapter.STATE_OFF);
+        assertThat(mAdapter.isEnabled()).isFalse();
+        try (BlockingBroadcastReceiver r = new BlockingBroadcastReceiver(
+                mContext,
+                BluetoothAdapter.ACTION_STATE_CHANGED,
+                this::isStateEnabled).register()) {
+            assertThat(mAdapter.enable()).isTrue();
         }
-        fail("enable() timeout");
+        assertThat(mAdapter.isEnabled()).isTrue();
     }
 
-    private void sleep(long t) {
-        try {
-            Thread.sleep(t);
-        } catch (InterruptedException e) {}
+    private boolean isStateEnabled(Intent intent) {
+        return intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
+                == BluetoothAdapter.STATE_ON;
+    }
+
+    private boolean isStateDisabled(Intent intent) {
+        return intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
+                == BluetoothAdapter.STATE_OFF;
     }
 }
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
index f96615c..1dd888c 100644
--- a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
@@ -27,13 +27,17 @@
 import android.support.test.uiautomator.BySelector;
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.Until;
+import android.util.Log;
 
 import java.util.regex.Pattern;
 
 /**
  * This class tests manual package install and uninstall by a device owner.
  */
-public class ManualPackageInstallTest extends BasePackageInstallTest {
+public final class ManualPackageInstallTest extends BasePackageInstallTest {
+
+    private static final String TAG = ManualPackageInstallTest.class.getSimpleName();
+
     private static final int AUTOMATOR_WAIT_TIMEOUT = 5000;
     private static final int INSTALL_WAIT_TIME = 5000;
 
@@ -41,11 +45,13 @@
             Pattern.CASE_INSENSITIVE));
 
     private UiAutomation mUiAutomation;
+    private boolean mIsAutomotive;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         mUiAutomation = getInstrumentation().getUiAutomation();
+        mIsAutomotive = mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
     }
 
     public void testManualInstallSucceeded() throws Exception {
@@ -58,17 +64,21 @@
             mCallbackStatus = PACKAGE_INSTALLER_STATUS_UNDEFINED;
         }
         // Calls the original installPackage which does not click through the install button.
+        Log.d(TAG, "Installing " + TEST_APP_LOCATION);
         super.installPackage(TEST_APP_LOCATION);
         synchronized (mPackageInstallerTimeoutLock) {
             try {
                 mPackageInstallerTimeoutLock.wait(PACKAGE_INSTALLER_TIMEOUT_MS);
             } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                Log.e(TAG, "Interrupted", e);
             }
             assertTrue(mCallbackReceived);
             assertEquals(PackageInstaller.STATUS_PENDING_USER_ACTION, mCallbackStatus);
         }
 
         mCallbackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        Log.d(TAG, "Starting " + mCallbackIntent + " on user " + UserHandle.myUserId());
         mContext.startActivity(mCallbackIntent);
 
         automateDismissInstallBlockedDialog();
@@ -111,9 +121,10 @@
     }
 
     private void automateDismissInstallBlockedDialog() {
-        mDevice.wait(Until.hasObject(getPopUpImageSelector()), AUTOMATOR_WAIT_TIMEOUT);
-        UiObject2 icon = mDevice.findObject(getPopUpImageSelector());
-        assertNotNull("Policy transparency dialog icon not found", icon);
+        BySelector selector = getPopUpImageSelector();
+        mDevice.wait(Until.hasObject(selector), AUTOMATOR_WAIT_TIMEOUT);
+        UiObject2 icon = mDevice.findObject(selector);
+        assertNotNull("Policy transparency dialog icon not found: " + selector, icon);
         // "OK" button only present in the dialog if it is blocked by policy.
         UiObject2 button = mDevice.findObject(getPopUpButtonSelector());
         assertNotNull("OK button not found", button);
@@ -121,9 +132,11 @@
     }
 
     private String getSettingsPackageName() {
-        String settingsPackageName = "com.android.settings";
+        String settingsPackageName = mIsAutomotive
+                ? "com.android.car.settings"
+                : "com.android.settings";
+        mUiAutomation.adoptShellPermissionIdentity("android.permission.INTERACT_ACROSS_USERS");
         try {
-            mUiAutomation.adoptShellPermissionIdentity("android.permission.INTERACT_ACROSS_USERS");
             ResolveInfo resolveInfo = mPackageManager.resolveActivityAsUser(
                     new Intent(Settings.ACTION_SETTINGS), PackageManager.MATCH_SYSTEM_ONLY,
                     UserHandle.USER_SYSTEM);
@@ -133,6 +146,7 @@
         } finally {
             mUiAutomation.dropShellPermissionIdentity();
         }
+        Log.d(TAG, "getSettingsPackageName(): returning " + settingsPackageName);
         return settingsPackageName;
     }
 
@@ -144,8 +158,9 @@
 
     private BySelector getPopUpImageSelector() {
         final String settingsPackageName = getSettingsPackageName();
+        final String resId = mIsAutomotive ? "car_ui_alert_icon" : "admin_support_icon";
         return By.clazz(android.widget.ImageView.class.getName())
-                .res(settingsPackageName + ":id/admin_support_icon")
+                .res(settingsPackageName + ":id/" + resId)
                 .pkg(settingsPackageName);
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceOwnerTest.java
index e08f44c..99621be 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceOwnerTest.java
@@ -62,11 +62,21 @@
 
     @Override
     public void tearDown() throws Exception {
-        if (mDeviceOwnerSet && !removeAdmin(DEVICE_OWNER_COMPONENT, mDeviceOwnerUserId)) {
-            // Don't fail as it could hide the real failure from the test method
-            CLog.e("Failed to remove device owner on user " + mDeviceOwnerUserId);
+        // Don't fail as it could hide the real failure from the test method
+        if (mDeviceOwnerSet) {
+            if (!removeAdmin(DEVICE_OWNER_COMPONENT, mDeviceOwnerUserId)) {
+                CLog.e("Failed to remove device owner on user " + mDeviceOwnerUserId);
+            }
+            if (isHeadlessSystemUserMode()
+                    && !removeAdmin(DEVICE_OWNER_COMPONENT, mPrimaryUserId)) {
+                CLog.e("Failed to remove profile owner on user " + mPrimaryUserId);
+            }
         }
-        getDevice().uninstallPackage(DEVICE_OWNER_PKG);
+
+        String status = getDevice().uninstallPackage(DEVICE_OWNER_PKG);
+        if (status != null) {
+            CLog.e("Could not uninstall package %s: %s", DEVICE_OWNER_PKG, status);
+        }
 
         super.tearDown();
     }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java
index b906c0d..6646a1f 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java
@@ -269,4 +269,23 @@
                 "getprop ro.hdmi.set_menu_language");
         return val.trim().equals("true") ? true : false;
     }
+
+    public static String getSettingsValue(ITestDevice device, String setting) throws Exception {
+        return device.executeShellCommand("cmd hdmi_control cec_setting get " + setting)
+                .replace(setting + " = ", "").trim();
+    }
+
+    public String getSettingsValue(String setting) throws Exception {
+        return getSettingsValue(getDevice(), setting);
+    }
+
+    public static void setSettingsValue(ITestDevice device, String setting, String value)
+            throws Exception {
+        device.executeShellCommand("cmd hdmi_control cec_setting set " + setting + " " +
+                value);
+    }
+
+    public void setSettingsValue(String setting, String value) throws Exception {
+        setSettingsValue(getDevice(), setting, value);
+    }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java
index 712e56d..c059110 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java
@@ -55,6 +55,7 @@
     REPORT_FEATURES(0xa6),
     INITIATE_ARC(0xc0),
     ARC_INITIATED(0xc1),
+    ARC_TERMINATED(0xc2),
     REQUEST_ARC_INITIATION(0xc3),
     REQUEST_ARC_TERMINATION(0xc4),
     TERMINATE_ARC(0xc5),
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java
index c2654cf..2310eb1 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java
@@ -39,6 +39,10 @@
 public final class HdmiCecRoutingControlTest extends BaseHdmiCecCtsTest {
 
     private static final int PHYSICAL_ADDRESS = 0x1000;
+    private static final String POWER_CONTROL_MODE =
+            "power_control_mode";
+    private static final String POWER_CONTROL_MODE_NONE =
+            "none";
 
     public HdmiCecRoutingControlTest() {
         super(LogicalAddress.PLAYBACK_1);
@@ -52,6 +56,12 @@
             .around(CecRules.requiresDeviceType(this, LogicalAddress.PLAYBACK_1))
             .around(hdmiCecClient);
 
+    private String setPowerControlMode(String valToSet) throws Exception {
+        String val = getSettingsValue(POWER_CONTROL_MODE);
+        setSettingsValue(POWER_CONTROL_MODE, valToSet);
+        return val;
+    }
+
     /**
      * Test 11.1.2-2, HF4-7-2
      *
@@ -132,6 +142,7 @@
     @Test
     public void cect_11_2_2_4_InactiveSourceOnStandby() throws Exception {
         ITestDevice device = getDevice();
+        String previousPowerControlMode = setPowerControlMode(POWER_CONTROL_MODE_NONE);
         try {
             int dumpsysPhysicalAddress = getDumpsysPhysicalAddress();
             hdmiCecClient.sendCecMessage(
@@ -147,6 +158,7 @@
         } finally {
             /* Wake up the device */
             device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+            setPowerControlMode(previousPowerControlMode);
         }
     }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/targetprep/CecPortDiscoverer.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/targetprep/CecPortDiscoverer.java
index 3d5cc4b..1fdac27 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/targetprep/CecPortDiscoverer.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/targetprep/CecPortDiscoverer.java
@@ -87,6 +87,7 @@
         HdmiCecClientWrapper cecClientWrapper = new HdmiCecClientWrapper();
 
         launchCommand.add("cec-client");
+        String serialNo = "";
 
         try {
             List<String> comPorts = cecClientWrapper.getValidCecClientPorts();
@@ -106,7 +107,7 @@
                 launchCommand.add("x");
             }
 
-            String serialNo = device.getProperty("ro.serialno");
+            serialNo = device.getProperty("ro.serialno");
             String serialNoParam = CecMessage.convertStringToHexParams(serialNo);
             /*
              * formatParams prefixes with a ':' that we do not want in the vendorcommand
@@ -177,15 +178,21 @@
                     "Caught "
                             + e.getClass().getSimpleName()
                             + ". "
-                            + "Could not get adapter mapping.", e);
+                            + "Could not get adapter mapping for device"
+                            + serialNo
+                            + ".",
+                    e);
         } catch (Exception generic) {
             throw new TargetSetupError(
                     "Caught an exception with message '"
                             + generic.getMessage()
                             + "'. "
-                            + "Could not get adapter mapping.", generic);
+                            + "Could not get adapter mapping for device"
+                            + serialNo
+                            + ".",
+                    generic);
         }
-        throw new TargetSetupError("Device not connected to any adapter!");
+        throw new TargetSetupError("Device " + serialNo + " not connected to any adapter!");
     }
 
     private String getPortFilename(String port) {
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecAudioReturnChannelControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecAudioReturnChannelControlTest.java
new file mode 100644
index 0000000..017c7c3
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecAudioReturnChannelControlTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hdmicec.cts.tv;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.hdmicec.cts.BaseHdmiCecCtsTest;
+import android.hdmicec.cts.CecMessage;
+import android.hdmicec.cts.CecOperand;
+import android.hdmicec.cts.HdmiCecConstants;
+import android.hdmicec.cts.LogicalAddress;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+
+/** HDMI CEC test to test audio return channel control (Section 11.2.17) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecAudioReturnChannelControlTest extends BaseHdmiCecCtsTest {
+
+    private static final LogicalAddress TV_DEVICE = LogicalAddress.TV;
+
+    public HdmiCecAudioReturnChannelControlTest() {
+        super(TV_DEVICE, "-t", "a");
+    }
+
+    @Rule
+    public RuleChain ruleChain =
+            RuleChain.outerRule(CecRules.requiresCec(this))
+                    .around(CecRules.requiresLeanback(this))
+                    .around(CecRules.requiresDeviceType(this, TV_DEVICE))
+                    .around(hdmiCecClient);
+
+    /**
+     * Test 11.1.17-1
+     *
+     * <p>Tests that the DUT sends a directly addressed {@code <Request ARC Initiation>} message.
+     */
+    @Ignore("b/187168483")
+    @Test
+    public void cect_11_1_17_1_DutSendsRequestArcInitiation() throws Exception {
+        // Ensure that ARC is off.
+        changeArcState(false);
+        hdmiCecClient.broadcastReportPhysicalAddress(LogicalAddress.AUDIO_SYSTEM);
+        assertWithMessage("DUT does not send a <Request ARC Initiation> message.")
+                .that(changeArcState(true))
+                .isTrue();
+    }
+
+    /**
+     * Test 11.1.17-2
+     *
+     * <p>Tests that the DUT responds with a directly addressed {@code <Report ARC initiated>}
+     * message to the Audio System when ARC is initiated.
+     */
+    @Ignore("b/174813656")
+    @Test
+    public void cect_11_1_17_2_ReportArcInitiated() throws Exception {
+        String params =
+                String.format(
+                        "%04d%02d",
+                        hdmiCecClient.getPhysicalAddress(),
+                        HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM);
+        hdmiCecClient.sendCecMessage(
+                LogicalAddress.AUDIO_SYSTEM,
+                LogicalAddress.BROADCAST,
+                CecOperand.REPORT_PHYSICAL_ADDRESS,
+                CecMessage.formatParams(params));
+        hdmiCecClient.sendCecMessage(
+                LogicalAddress.AUDIO_SYSTEM, LogicalAddress.TV, CecOperand.INITIATE_ARC);
+        hdmiCecClient.checkExpectedOutput(LogicalAddress.AUDIO_SYSTEM, CecOperand.ARC_INITIATED);
+    }
+
+    /**
+     * Test 11.1.17-3
+     *
+     * <p>Tests that the DUT sends a directly addressed {@code <Request ARC Termination>} message.
+     */
+    @Ignore("b/187168483")
+    @Test
+    public void cect_11_1_17_3_DutSendsRequestArcTermination() throws Exception {
+        // Ensure that ARC is on.
+        changeArcState(true);
+        hdmiCecClient.broadcastReportPhysicalAddress(LogicalAddress.AUDIO_SYSTEM);
+        assertWithMessage("DUT does not send a <Request ARC Termination> message.")
+                .that(changeArcState(false))
+                .isTrue();
+    }
+
+    /**
+     * Test 11.1.17-2,4
+     *
+     * <p>Tests that the DUT responds with a directly addressed {@code <Report ARC terminated>}
+     * message to the Audio System when ARC is terminated.
+     */
+    @Ignore("b/174813656")
+    @Test
+    public void cect_11_1_17_2_4_ReportArcInitiatedTerminated() throws Exception {
+        /* We need to initiate ARC, so call the Initiate ARC test first */
+        cect_11_1_17_2_ReportArcInitiated();
+        hdmiCecClient.sendCecMessage(
+                LogicalAddress.AUDIO_SYSTEM, LogicalAddress.TV, CecOperand.TERMINATE_ARC);
+        hdmiCecClient.checkExpectedOutput(LogicalAddress.AUDIO_SYSTEM, CecOperand.ARC_TERMINATED);
+    }
+
+    /**
+     * Test 11.1.17-5
+     *
+     * <p>Tests that the DUT does not respond with any directly addressed {@code <Report ARC
+     * initiated>} message to a non-adjacent device
+     */
+    @Test
+    public void cect_11_1_17_5_NonAdjacentDeviceArcInitiation() throws Exception {
+        int originalPhyAdd = hdmiCecClient.getPhysicalAddress();
+        try {
+            int nonAdjacentPhyAdd = 0x1100;
+            String params =
+                    CecMessage.formatParams(nonAdjacentPhyAdd)
+                            + CecMessage.formatParams(
+                                    HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM);
+            /* Take physical address 1.1.0.0 */
+            hdmiCecClient.setPhysicalAddress(nonAdjacentPhyAdd);
+            hdmiCecClient.sendCecMessage(
+                    LogicalAddress.AUDIO_SYSTEM,
+                    LogicalAddress.BROADCAST,
+                    CecOperand.REPORT_PHYSICAL_ADDRESS,
+                    params);
+            hdmiCecClient.sendCecMessage(
+                    LogicalAddress.AUDIO_SYSTEM, LogicalAddress.TV, CecOperand.INITIATE_ARC);
+            hdmiCecClient.checkOutputDoesNotContainMessage(
+                    LogicalAddress.AUDIO_SYSTEM, CecOperand.ARC_INITIATED);
+        } finally {
+            /* Restore physical address */
+            hdmiCecClient.setPhysicalAddress(originalPhyAdd);
+        }
+    }
+
+    /**
+     * This method will turn on/off the ARC and ensure that it is processed successfully.
+     *
+     * @param enabled boolean value. Value true to turn ARC on.
+     * @return {@code true} if ARC process was successful.
+     */
+    private boolean changeArcState(boolean enabled) throws Exception {
+        getDevice().executeShellCommand("cmd hdmi_control setarc " + (enabled ? "on" : "off"));
+        try {
+            hdmiCecClient.checkExpectedOutput(
+                    LogicalAddress.AUDIO_SYSTEM,
+                    enabled
+                            ? CecOperand.REQUEST_ARC_INITIATION
+                            : CecOperand.REQUEST_ARC_TERMINATION);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+}
diff --git a/hostsidetests/incident/apps/batterystatsapp/Android.bp b/hostsidetests/incident/apps/batterystatsapp/Android.bp
index 96f6c37..cb3e3b7 100644
--- a/hostsidetests/incident/apps/batterystatsapp/Android.bp
+++ b/hostsidetests/incident/apps/batterystatsapp/Android.bp
@@ -29,6 +29,7 @@
         "ctstestrunner-axt",
         "compatibility-device-util-axt",
         "androidx.legacy_legacy-support-v4",
+        "testng", // for org.test.* support
     ],
     sdk_version: "test_current",
     // tag this module as a cts test artifact
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsRadioPowerStateTest.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsRadioPowerStateTest.java
new file mode 100644
index 0000000..d384852
--- /dev/null
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsRadioPowerStateTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.server.cts.device.batterystats;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.testng.Assert.assertThrows;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
+import android.os.BatteryStatsManager;
+import android.os.SystemClock;
+import android.system.Os;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class BatteryStatsRadioPowerStateTest {
+    private static final int UID = Os.getuid();
+    private static final String PATTERN_MOBILE = "modem-data";
+    private static final String PATTERN_WIFI = "wifi-data";
+    private BatteryStatsManager mBsm;
+    private ConnectivityManager mCm;
+    private Instrumentation mInstrumentation;
+    private Context mContext;
+    private UiAutomation mUiAutomation;
+
+    @Before
+    public void setUp() throws Exception {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = mInstrumentation.getContext();
+        mUiAutomation =  mInstrumentation.getUiAutomation();
+        mBsm = mContext.getSystemService(BatteryStatsManager.class);
+        mCm = mContext.getSystemService(ConnectivityManager.class);
+    }
+
+    @Test
+    public void testReportMobileRadioPowerState() throws Exception {
+        // Expect fail w/o UPDATE_DEVICE_STATS permission.
+        assertThrows(SecurityException.class, () -> mBsm.reportMobileRadioPowerState(true, UID));
+
+        mUiAutomation.adoptShellPermissionIdentity();
+        final NetworkCapabilities activeNc = mCm.getNetworkCapabilities(mCm.getActiveNetwork());
+        final boolean expectedCurrentMobileRadio = (activeNc == null) ? false :
+                activeNc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
+        try {
+            // Skip other information before testing to reduce the information contained in the dump
+            // result.
+            final long time = SystemClock.elapsedRealtime();
+            final String cmd = "dumpsys batterystats --history-start " + time;
+            // Mobile radio power stats only updates when:
+            // 1. the radio state is changed, and
+            // 2. the radio power is inactive.
+            // Thus, trigger twice with different radio power state to ensure that it updates.
+            mBsm.reportMobileRadioPowerState(!expectedCurrentMobileRadio, UID);
+            mBsm.reportMobileRadioPowerState(expectedCurrentMobileRadio, UID);
+            final String dump = runShellCommand(mInstrumentation, cmd);
+            assertTrue(Pattern.compile(PATTERN_MOBILE).matcher(dump).find());
+        } finally {
+            // Restore state
+            mBsm.reportMobileRadioPowerState(expectedCurrentMobileRadio, UID);
+            mUiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+    @Test
+    public void testReportWifiRadioPowerState() throws Exception {
+        // Expect fail w/o UPDATE_DEVICE_STATS permission.
+        assertThrows(SecurityException.class, () -> mBsm.reportWifiRadioPowerState(true, UID));
+
+        mUiAutomation.adoptShellPermissionIdentity();
+        final NetworkCapabilities activeNc = mCm.getNetworkCapabilities(mCm.getActiveNetwork());
+        final boolean expectedCurrentWifiRadio = (activeNc == null) ? false :
+                activeNc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
+        try {
+            // Skip other information before testing to reduce the information contained in the dump
+            // result.
+            final long time = SystemClock.elapsedRealtime();
+            final String cmd = "dumpsys batterystats --history-start " + time;
+            mBsm.reportWifiRadioPowerState(!expectedCurrentWifiRadio, UID);
+            final String dump = runShellCommand(mInstrumentation, cmd);
+            assertTrue(Pattern.compile(PATTERN_WIFI).matcher(dump).find());
+        } finally {
+            // Restore state
+            mBsm.reportWifiRadioPowerState(expectedCurrentWifiRadio, UID);
+            mUiAutomation.dropShellPermissionIdentity();
+        }
+    }
+}
diff --git a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
index f927646..69512de 100644
--- a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
@@ -241,6 +241,21 @@
         batteryOffScreenOn();
     }
 
+    public void testReportRadioPowerState() throws Exception {
+        // Simulate usb unplugged.
+        batteryOnScreenOff();
+
+        installPackage(DEVICE_SIDE_TEST_APK, true);
+        allowImmediateSyncs();
+
+        runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsRadioPowerStateTest",
+                "testReportMobileRadioPowerState");
+        runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsRadioPowerStateTest",
+                "testReportWifiRadioPowerState");
+
+        batteryOffScreenOn();
+    }
+
     private int getUid() throws Exception {
         String uidLine = getDevice().executeShellCommand("cmd package list packages -U "
                 + DEVICE_SIDE_TEST_PACKAGE);
diff --git a/hostsidetests/packagemanager/boottest/Android.bp b/hostsidetests/packagemanager/boottest/Android.bp
new file mode 100644
index 0000000..9d1f96e
--- /dev/null
+++ b/hostsidetests/packagemanager/boottest/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_test_host {
+    name: "CtsPackageManagerBootTestCases",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "general-tests",
+    ],
+    libs: [
+        "cts-tradefed",
+        "tradefed",
+        "compatibility-host-util",
+    ],
+}
\ No newline at end of file
diff --git a/hostsidetests/packagemanager/boottest/AndroidTest.xml b/hostsidetests/packagemanager/boottest/AndroidTest.xml
new file mode 100644
index 0000000..9889a52
--- /dev/null
+++ b/hostsidetests/packagemanager/boottest/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?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.
+  -->
+<configuration description="Config for the CTS PackageManager boot tests">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsPackageManagerBootTestCases.jar" />
+        <option name="runtime-hint" value="3m" />
+    </test>
+
+</configuration>
\ No newline at end of file
diff --git a/hostsidetests/packagemanager/boottest/app/Android.bp b/hostsidetests/packagemanager/boottest/app/Android.bp
new file mode 100644
index 0000000..d1a3271
--- /dev/null
+++ b/hostsidetests/packagemanager/boottest/app/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+    name: "CtsPackageManagerBootTestStubApp",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "general-tests",
+    ],
+    sdk_version: "current",
+    manifest: "AndroidManifest.xml",
+    compile_multilib: "both",
+}
\ No newline at end of file
diff --git a/hostsidetests/packagemanager/boottest/app/AndroidManifest.xml b/hostsidetests/packagemanager/boottest/app/AndroidManifest.xml
new file mode 100644
index 0000000..06b1e34
--- /dev/null
+++ b/hostsidetests/packagemanager/boottest/app/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.packagemanager.boottest.stub">
+
+    <application>
+        <activity android:name=".StubActivity"
+                  android:exported="true"/>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/hostsidetests/packagemanager/boottest/src/android/packagemanager/boot/cts/BootTest.java b/hostsidetests/packagemanager/boottest/src/android/packagemanager/boot/cts/BootTest.java
new file mode 100644
index 0000000..f86f5cf
--- /dev/null
+++ b/hostsidetests/packagemanager/boottest/src/android/packagemanager/boot/cts/BootTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.packagemanager.boot.cts;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class BootTest extends BaseHostJUnit4Test {
+    private static final String TEST_APK = "CtsPackageManagerBootTestStubApp.apk";
+    private static final String TEST_PACKAGE = "android.packagemanager.boottest.stub";
+
+    @Before
+    public void setUp() throws Exception {
+        installPackage(TEST_APK);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        uninstallPackage(getDevice(), TEST_PACKAGE);
+    }
+
+    @Test
+    public void testUninstallPackageWithKeepDataAndReboot() throws Exception {
+        Assert.assertTrue(isPackageInstalled(TEST_PACKAGE));
+        uninstallPackageWithKeepData(TEST_PACKAGE);
+        getDevice().rebootUntilOnline();
+        waitForBootCompleted();
+    }
+
+    private void uninstallPackageWithKeepData(String packageName)
+            throws DeviceNotAvailableException {
+        getDevice().executeShellCommand("pm uninstall -k " + packageName);
+    }
+
+    private void waitForBootCompleted() throws Exception {
+        for (int i = 0; i < 45; i++) {
+            if (isBootCompleted()) {
+                return;
+            }
+            Thread.sleep(1000);
+        }
+        throw new AssertionError("System failed to become ready!");
+    }
+
+    private boolean isBootCompleted() throws Exception {
+        return "1".equals(getDevice().executeShellCommand("getprop sys.boot_completed").trim());
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/packagemanager/extractnativelibs/apps/app_extract/src/com/android/cts/extractnativelibs/app/extract/MainActivity.java b/hostsidetests/packagemanager/extractnativelibs/apps/app_extract/src/com/android/cts/extractnativelibs/app/extract/MainActivity.java
index fbcc783..58868d4 100644
--- a/hostsidetests/packagemanager/extractnativelibs/apps/app_extract/src/com/android/cts/extractnativelibs/app/extract/MainActivity.java
+++ b/hostsidetests/packagemanager/extractnativelibs/apps/app_extract/src/com/android/cts/extractnativelibs/app/extract/MainActivity.java
@@ -30,6 +30,7 @@
 
     @Override
     public void onCreate(Bundle savedOnstanceState) {
+        super.onCreate(savedOnstanceState);
         // The native lib should have been loaded already
         Intent intent = new Intent(
                 getApplicationContext().getPackageName() + ".NativeLibLoaded");
diff --git a/hostsidetests/packagemanager/extractnativelibs/apps/app_no_extract/src/com/android/cts/extractnativelibs/app/noextract/MainActivity.java b/hostsidetests/packagemanager/extractnativelibs/apps/app_no_extract/src/com/android/cts/extractnativelibs/app/noextract/MainActivity.java
index 9200260..72367c4 100644
--- a/hostsidetests/packagemanager/extractnativelibs/apps/app_no_extract/src/com/android/cts/extractnativelibs/app/noextract/MainActivity.java
+++ b/hostsidetests/packagemanager/extractnativelibs/apps/app_no_extract/src/com/android/cts/extractnativelibs/app/noextract/MainActivity.java
@@ -30,6 +30,7 @@
 
     @Override
     public void onCreate(Bundle savedOnstanceState) {
+        super.onCreate(savedOnstanceState);
         // The native lib should have been loaded already
         Intent intent = new Intent(
                 getApplicationContext().getPackageName() + ".NativeLibLoaded");
diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
index e2424b9..8f3022b 100644
--- a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
+++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
@@ -1076,6 +1076,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 31, codeName = "S")
     public void testDefaultNoIsolatedStorageFlag() throws Exception {
         assertThat(Environment.isExternalStorageLegacy()).isFalse();
     }
diff --git a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
index 090b125..eeee104 100644
--- a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
+++ b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
@@ -536,7 +536,9 @@
     @Test
     public void testAndroidMedia() throws Exception {
         // Check that the app does not have legacy external storage access
-        assertThat(Environment.isExternalStorageLegacy()).isFalse();
+        if (BuildCompat.isAtLeastS()) {
+            assertThat(Environment.isExternalStorageLegacy()).isFalse();
+        }
 
         pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /*granted*/ true);
 
@@ -686,7 +688,9 @@
 
     @Test
     public void testNoIsolatedStorageCanCreateFilesAnywhere() throws Exception {
-        assertThat(Environment.isExternalStorageLegacy()).isTrue();
+        if (BuildCompat.isAtLeastS()) {
+            assertThat(Environment.isExternalStorageLegacy()).isTrue();
+        }
         final File topLevelPdf = new File(getExternalStorageDir(), NONMEDIA_FILE_NAME);
         final File musicFileInMovies = new File(getMoviesDir(), AUDIO_FILE_NAME);
         final File imageFileInDcim = new File(getDcimDir(), IMAGE_FILE_NAME);
@@ -701,7 +705,9 @@
 
     @Test
     public void testNoIsolatedStorageCantReadWriteOtherAppExternalDir() throws Exception {
-        assertThat(Environment.isExternalStorageLegacy()).isTrue();
+        if (BuildCompat.isAtLeastS()) {
+            assertThat(Environment.isExternalStorageLegacy()).isTrue();
+        }
         // Let app A create a file in its data dir
         final File otherAppExternalDataDir = new File(getExternalFilesDir().getPath().replace(
                 THIS_PACKAGE_NAME, APP_A_HAS_RES.getPackageName()));
@@ -725,7 +731,9 @@
 
     @Test
     public void testNoIsolatedStorageStorageReaddir() throws Exception {
-        assertThat(Environment.isExternalStorageLegacy()).isTrue();
+        if (BuildCompat.isAtLeastS()) {
+            assertThat(Environment.isExternalStorageLegacy()).isTrue();
+        }
         final File otherAppPdf = new File(getDownloadDir(), "other" + NONMEDIA_FILE_NAME);
         final File otherAppImg = new File(getDcimDir(), "other" + IMAGE_FILE_NAME);
         final File otherAppMusic = new File(getMusicDir(), "other" + AUDIO_FILE_NAME);
@@ -752,7 +760,9 @@
 
     @Test
     public void testNoIsolatedStorageQueryOtherAppsFile() throws Exception {
-        assertThat(Environment.isExternalStorageLegacy()).isTrue();
+        if (BuildCompat.isAtLeastS()) {
+            assertThat(Environment.isExternalStorageLegacy()).isTrue();
+        }
         final File otherAppPdf = new File(getDownloadDir(), "other" + NONMEDIA_FILE_NAME);
         final File otherAppImg = new File(getDcimDir(), "other" + IMAGE_FILE_NAME);
         final File otherAppMusic = new File(getMusicDir(), "other" + AUDIO_FILE_NAME);
@@ -816,7 +826,9 @@
     @Test
     public void testClearPackageData() throws Exception {
         // Check that the app does not have legacy external storage access
-        assertThat(Environment.isExternalStorageLegacy()).isFalse();
+        if (BuildCompat.isAtLeastS()) {
+            assertThat(Environment.isExternalStorageLegacy()).isFalse();
+        }
 
         pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /*granted*/ true);
 
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2022/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2022/Android.bp
index 8d95e36..2187f92 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2022/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2022/Android.bp
@@ -15,6 +15,10 @@
  *
  */
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_test {
     name: "CVE-2019-2022",
     defaults: ["cts_hostsidetests_securitybulletin_defaults"],
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2038/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2038/Android.bp
index d343438..032f4cd 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2038/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2038/Android.bp
@@ -15,6 +15,10 @@
  *
  */
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_test {
     name: "CVE-2019-2038",
     defaults: ["cts_hostsidetests_securitybulletin_defaults"],
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2039/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2039/Android.bp
index 48fb497..485c92a 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2039/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2039/Android.bp
@@ -15,6 +15,10 @@
  *
  */
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_test {
     name: "CVE-2019-2039",
     defaults: ["cts_hostsidetests_securitybulletin_defaults"],
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/Android.bp
deleted file mode 100644
index f4554af..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/Android.bp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_test {
-    name: "CVE-2020-0408",
-    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
-    srcs: ["poc.cpp"],
-    shared_libs: [
-        "libutils",
-    ],
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/poc.cpp
deleted file mode 100644
index 6392952..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/poc.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "utils/String16.h"
-
-int main(void) {
-    android::String16 str{u"hello world"};
-    android::String16 substr{u"hello"};
-    const size_t begin = substr.size();
-    const size_t len = std::numeric_limits<size_t>::max();
-    if (str.remove(len, begin) != android::OK) {
-        return EXIT_FAILURE;
-    }
-    if (strcmp16(str, substr) != 0) {
-        return EXIT_FAILURE;
-    }
-    return EXIT_SUCCESS;
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/Android.bp
index 9912e5e..c24f1af 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/Android.bp
@@ -15,6 +15,10 @@
  *
  */
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_test {
     name: "CVE-2021-0484",
     defaults: [
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11164.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11164.java
new file mode 100644
index 0000000..4132917
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11164.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 android.security.cts;
+
+import static org.junit.Assert.*;
+
+import android.platform.test.annotations.SecurityTest;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2020_11164 extends SecurityTestCase {
+
+    /**
+     * CVE-2020-11164
+     */
+    @SecurityTest(minPatchLevel = "2020-10")
+    @Test
+    public void testPocCVE_2020_11164() throws Exception {
+        String result =
+                AdbUtils.runCommandLine("pm list package com.qualcomm.qti.perfdump", getDevice());
+        assertFalse(result.contains("com.qualcomm.qti.perfdump"));
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index 3d4ae46..65cd58a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -131,21 +131,6 @@
     }
 
     /**
-     * b/156999009
-     * Vulnerability Behaviour: SIGABRT in self
-     */
-    @SecurityTest(minPatchLevel = "2020-10")
-    @Test
-    public void testPocCVE_2020_0408() throws Exception {
-        String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
-        String binaryName = "CVE-2020-0408";
-        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
-        testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
-        testConfig.config.setSignals(signals);
-        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
-    }
-
-    /**
      * b/161894517
      * Vulnerability Behaviour: SIGABRT in self
      */
diff --git a/hostsidetests/stagedinstall/Android.bp b/hostsidetests/stagedinstall/Android.bp
index 8ea3089..e3e84f1 100644
--- a/hostsidetests/stagedinstall/Android.bp
+++ b/hostsidetests/stagedinstall/Android.bp
@@ -66,6 +66,7 @@
         ":StagedInstallTestCorruptedApex_b146895998",
         ":StagedInstallTestApexV2_NoApkSignature",
         ":StagedInstallTestApexV2_UnsignedPayload",
+        ":StagedInstallTestApexV2_SignPayloadWithDifferentKey",
     ],
     static_libs: [
         "androidx.test.runner",
@@ -533,6 +534,28 @@
   installable: false,
 }
 
+ApexFilenameSigningPayloadWithDifferentKey =
+  "com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex"
+prebuilt_apex {
+  name: "StagedInstallTestApexV2_SignPayloadWithDifferentKey",
+  arch: {
+        arm: {
+              src: "testdata/apex/arm/" + ApexFilenameSigningPayloadWithDifferentKey,
+        },
+        arm64: {
+              src: "testdata/apex/arm/" + ApexFilenameSigningPayloadWithDifferentKey,
+        },
+        x86: {
+              src: "testdata/apex/x86/" + ApexFilenameSigningPayloadWithDifferentKey,
+        },
+        x86_64: {
+              src: "testdata/apex/x86/" + ApexFilenameSigningPayloadWithDifferentKey,
+        },
+    },
+  filename: ApexFilenameSigningPayloadWithDifferentKey,
+  installable: false,
+}
+
 // collects deapexer and its dependency modules (libc++ and debugfs_static) to the zip file.
 genrule {
   name: "deapexer.zip",
diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
index 4a69184..9ba9448 100644
--- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
@@ -17,7 +17,6 @@
 package com.android.tests.stagedinstall;
 
 import static com.android.cts.install.lib.InstallUtils.assertStatusSuccess;
-import static com.android.cts.install.lib.InstallUtils.getInstalledVersion;
 import static com.android.cts.install.lib.InstallUtils.getPackageInstaller;
 import static com.android.cts.shim.lib.ShimPackage.DIFFERENT_APEX_PACKAGE_NAME;
 import static com.android.cts.shim.lib.ShimPackage.NOT_PRE_INSTALL_APEX_PACKAGE_NAME;
@@ -162,6 +161,9 @@
     private static final TestApp Apex2UnsignedPayload = new TestApp(
             "StagedInstallTestApexV2_UnsignedPayload", SHIM_APEX_PACKAGE_NAME, 1,
             /*isApex*/true, "com.android.apex.cts.shim.v2_unsigned_payload.apex");
+    private static final TestApp Apex2SignPayloadWithDifferentKey = new TestApp(
+            "StagedInstallTestApexV2_SignPayloadWithDifferentKey", SHIM_APEX_PACKAGE_NAME, 1,
+            /*isApex*/true, "com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex");
 
     @Before
     public void adoptShellPermissions() {
@@ -1191,6 +1193,19 @@
     }
 
     /**
+     * Should fail to verify apex signed payload with a different key
+     */
+    @Test
+    public void testApexSignPayloadWithDifferentKeyFailsVerification() throws Exception {
+        int sessionId = stageSingleApk(
+                Apex2SignPayloadWithDifferentKey).assertSuccessful().getSessionId();
+        PackageInstaller.SessionInfo sessionInfo = waitForBroadcast(sessionId);
+        assertThat(sessionInfo).isStagedSessionFailed();
+        assertThat(sessionInfo.getStagedSessionErrorMessage())
+                .contains("public key doesn't match the pre-installed one");
+    }
+
+    /**
      * Test non-priv apps cannot access /data/app-staging folder contents
      */
     @Test
diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
index fd9b0f9..08da8a1 100644
--- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
@@ -649,6 +649,16 @@
     }
 
     /**
+     * Should fail to verify apex signed payload with a different key
+     */
+    @Test
+    public void testApexSignPayloadWithDifferentKeyFailsVerification() throws Exception {
+        assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported());
+
+        runPhase("testApexSignPayloadWithDifferentKeyFailsVerification");
+    }
+
+    /**
      * Should fail to verify apex with unsigned payload
      */
     @Test
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v1.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v1.apex
index 3019791..b9ba412 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v1.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v1.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2.apex
index 258eadc..381c03e 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_file.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_file.apex
index f72afda..ab0bd3b 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_file.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_file.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_folder.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_folder.apex
index f9aa433..49eb049 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_folder.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_folder.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
index 97da742..7a3c698 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_certificate.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_certificate.apex
index 876ca57..549ef2f 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_certificate.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_certificate.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_package_name.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_package_name.apex
index 4e801f8..7f6c3f7 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_package_name.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_package_name.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_no_hashtree.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_no_hashtree.apex
index b76f639..22af8a6 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_no_hashtree.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_no_hashtree.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sdk_target_p.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sdk_target_p.apex
index d672bc2..0ca48f6 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sdk_target_p.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sdk_target_p.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex
new file mode 100644
index 0000000..a9b6105
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob.apex
index bf7d8c4..4d8b380 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot.apex
index ac0d06e..a520f63 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
index 405ed92..8a86a33 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_payload.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_payload.apex
index 1a524fb..9ee1bbb 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_payload.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_payload.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_post_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_post_install_hook.apex
index 5d294ae..3352c03 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_post_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_post_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_pre_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
index 3f1cde1..d23c81c 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_without_apk_in_apex.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_without_apk_in_apex.apex
index cd3e8ba..ac71363 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_without_apk_in_apex.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_without_apk_in_apex.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_wrong_sha.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_wrong_sha.apex
index 9f30c4f..0673492 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_wrong_sha.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_wrong_sha.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3.apex
index aaa0d36..1de3948 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob.apex
index fdc764b..8643df9 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob_rot.apex
index b4bafaf..742395a 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob_rot.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v1.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v1.apex
index fc2a7f8..ac9ddb6 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v1.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v1.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2.apex
index 29daf35..c7051e8 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_file.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_file.apex
index f72afda..ab0bd3b 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_file.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_file.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_folder.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_folder.apex
index f9aa433..49eb049 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_folder.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_folder.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
index 97da742..7a3c698 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_certificate.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_certificate.apex
index 876ca57..549ef2f 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_certificate.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_certificate.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_package_name.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_package_name.apex
index bf5dee0..dc517ab 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_package_name.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_package_name.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_no_hashtree.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_no_hashtree.apex
index 145e974..207083c 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_no_hashtree.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_no_hashtree.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sdk_target_p.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sdk_target_p.apex
index 458dc15..459cdd7d 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sdk_target_p.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sdk_target_p.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex
new file mode 100644
index 0000000..a9b6105
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob.apex
index 1607d35..fa289c0 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot.apex
index 31f08a1..9d09714 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
index 0432704..2b9e42f 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_payload.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_payload.apex
index 0f10c19..cfc8c0e 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_payload.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_payload.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_post_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_post_install_hook.apex
index 5d294ae..3352c03 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_post_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_post_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_pre_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
index 3f1cde1..d23c81c 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_without_apk_in_apex.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_without_apk_in_apex.apex
index cd3e8ba..ac71363 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_without_apk_in_apex.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_without_apk_in_apex.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_wrong_sha.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_wrong_sha.apex
index 9f30c4f..0673492 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_wrong_sha.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_wrong_sha.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3.apex
index 57a4e8e..66ad34e 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob.apex
index fe0be5b..21ba7bb 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob_rot.apex
index 1bd82d0..a1087fc 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob_rot.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/arm/CtsShimTargetPSdk.apk b/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/arm/CtsShimTargetPSdk.apk
index e852251..cbd5a8b 100644
--- a/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/arm/CtsShimTargetPSdk.apk
+++ b/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/arm/CtsShimTargetPSdk.apk
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/x86/CtsShimTargetPSdk.apk b/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/x86/CtsShimTargetPSdk.apk
index e852251..cbd5a8b 100644
--- a/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/x86/CtsShimTargetPSdk.apk
+++ b/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/x86/CtsShimTargetPSdk.apk
Binary files differ
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/apphibernation/AppHibernationStatsTest.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/apphibernation/AppHibernationStatsTest.java
index c397583..8564d49 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/apphibernation/AppHibernationStatsTest.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/apphibernation/AppHibernationStatsTest.java
@@ -123,6 +123,22 @@
         fail(String.format("Did not find a matching atom for user %d", userId));
     }
 
+    public void testGlobalHibernatedApps() throws Exception {
+        ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
+                AtomsProto.Atom.GLOBAL_HIBERNATED_APPS_FIELD_NUMBER);
+        getDevice().executeShellCommand(
+                getHibernationCommand(DeviceUtils.STATSD_ATOM_TEST_PKG,
+                        /* isGlobal */ true, /* isHibernating */ true));
+
+        AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice());
+        Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
+
+        final List<AtomsProto.Atom> atoms = ReportUtils.getGaugeMetricAtoms(getDevice());
+        assertThat(atoms.size()).isEqualTo(1);
+        AtomsProto.GlobalHibernatedApps apps = atoms.get(0).getGlobalHibernatedApps();
+        assertThat(apps.getHibernatedAppCount()).isAtLeast(1);
+    }
+
     private static void assertUserLevelHibernationStateChangedEvent(
             List<StatsLog.EventMetricData> data, boolean isHibernating) {
         for (StatsLog.EventMetricData d : data) {
diff --git a/tests/MediaProviderTranscode/src/android/mediaprovidertranscode/cts/TranscodeTest.java b/tests/MediaProviderTranscode/src/android/mediaprovidertranscode/cts/TranscodeTest.java
index 8f34997..ed2495d 100644
--- a/tests/MediaProviderTranscode/src/android/mediaprovidertranscode/cts/TranscodeTest.java
+++ b/tests/MediaProviderTranscode/src/android/mediaprovidertranscode/cts/TranscodeTest.java
@@ -20,6 +20,7 @@
 
 import static android.mediaprovidertranscode.cts.TranscodeTestUtils.assertFileContent;
 import static android.mediaprovidertranscode.cts.TranscodeTestUtils.assertTranscode;
+import static android.mediaprovidertranscode.cts.TranscodeTestUtils.executeShellCommand;
 import static android.mediaprovidertranscode.cts.TranscodeTestUtils.installAppWithStoragePermissions;
 import static android.mediaprovidertranscode.cts.TranscodeTestUtils.isAppIoBlocked;
 import static android.mediaprovidertranscode.cts.TranscodeTestUtils.open;
@@ -905,6 +906,8 @@
             // Trigger transcoding so that the transcoded file gets added to cache.
             assertTranscode(modernFile, true);
 
+            // To make the cache clearing logic easier to verify, ignore any cache reserved space.
+            executeShellCommand("settings put global sys_storage_cache_max_bytes 0");
             // Invoke StorageManager to free maximum allocatable bytes, so that it tries to clear
             // all available caches.
             StorageManager storageManager = getContext().getSystemService(StorageManager.class);
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
index 038af75..adf2f4f 100644
--- a/tests/accessibilityservice/AndroidManifest.xml
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -57,6 +57,10 @@
              android:supportsPictureInPicture="true"
              android:screenOrientation="locked"/>
 
+        <activity android:label="@string/non_default_display_activity"
+                  android:name=".activities.NonDefaultDisplayActivity"
+                  android:screenOrientation="locked"/>
+
         <activity android:label="Full screen activity for gesture dispatch testing"
              android:name=".AccessibilityGestureDispatchTest$GestureDispatchActivity"
              android:theme="@style/Theme_NoSwipeDismiss"
@@ -65,15 +69,6 @@
         <activity android:label="@string/accessibility_soft_keyboard_modes_activity"
              android:name=".AccessibilitySoftKeyboardModesTest$SoftKeyboardModesActivity"/>
 
-        <activity android:label="@string/accessibility_embedded_display_test_parent_activity"
-             android:name=".AccessibilityEmbeddedDisplayTest$EmbeddedDisplayParentActivity"
-             android:theme="@android:style/Theme.Dialog"
-             android:screenOrientation="locked"/>
-
-        <activity android:label="@string/accessibility_embedded_display_test_activity"
-             android:name=".AccessibilityEmbeddedDisplayTest$EmbeddedDisplayActivity"
-             android:screenOrientation="locked"/>
-
         <activity android:label="@string/accessibility_embedded_hierarchy_test_activity"
              android:name=".AccessibilityEmbeddedHierarchyTest$AccessibilityEmbeddedHierarchyActivity"
              android:theme="@android:style/Theme.Dialog"
diff --git a/tests/accessibilityservice/res/layout/accessibility_embedded_display_test.xml b/tests/accessibilityservice/res/layout/non_default_display_activity.xml
similarity index 100%
rename from tests/accessibilityservice/res/layout/accessibility_embedded_display_test.xml
rename to tests/accessibilityservice/res/layout/non_default_display_activity.xml
diff --git a/tests/accessibilityservice/res/values/strings.xml b/tests/accessibilityservice/res/values/strings.xml
index 03de62d..747ce54 100644
--- a/tests/accessibilityservice/res/values/strings.xml
+++ b/tests/accessibilityservice/res/values/strings.xml
@@ -178,13 +178,7 @@
     <!-- Description of the accessibility service -->
     <string name="soft_keyboard_modes_accessibility_service_description">This Accessibility Service was installed for testing purposes. It can be uninstalled by going to Settings > Apps > android.view.accessibilityservice.services and selecting \"Uninstall\".</string>
 
-    <!-- AccessibilityEmbeddedDisplayTest -->
-
-    <!-- String title of accessibility embedded display test parent window activity -->
-    <string name="accessibility_embedded_display_test_parent_activity">Embedded display test parent</string>
-
-    <!-- String title of accessibility embedded display test activity -->
-    <string name="accessibility_embedded_display_test_activity">Embedded display test</string>
+    <!-- AccessibilityTextActionTest -->
 
     <!-- String the default label of AccessibilityAction ACTION_IME_ENTER -->
     <string name="accessibility_action_ime_enter_label">Enter</string>
@@ -196,4 +190,9 @@
 
     <string name="stub_focus_indicator_service_description">com.android.accessibilityservice.cts.StubFocusIndicatorService</string>
 
+    <!-- AccessibilityWindowQueryTest and AccessibilityReportingTest -->
+
+    <!-- String title of embedded display activity -->
+    <string name="non_default_display_activity">Non default display activity</string>
+
 </resources>
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedDisplayTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedDisplayTest.java
deleted file mode 100644
index 03324b8..0000000
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedDisplayTest.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.accessibilityservice.cts;
-
-import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWindowsChangeTypesAndWindowTitle;
-import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.findWindowByTitle;
-import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
-import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.supportsMultiDisplay;
-import static android.accessibilityservice.cts.utils.AsyncUtils.DEFAULT_TIMEOUT_MS;
-import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
-import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ADDED;
-import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_BOUNDS;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
-
-import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
-import android.accessibilityservice.AccessibilityServiceInfo;
-import android.accessibilityservice.cts.activities.AccessibilityTestActivity;
-import android.app.Activity;
-import android.app.ActivityView;
-import android.app.Instrumentation;
-import android.app.UiAutomation;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.platform.test.annotations.Presubmit;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityWindowInfo;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.ActivityTestRule;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.compatibility.common.util.SystemUtil;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
-import org.junit.runner.RunWith;
-
-/**
- * Tests that AccessibilityWindowInfos and AccessibilityNodeInfos from a window on an embedded
- * display that is re-parented to another window are properly populated.
- */
-@RunWith(AndroidJUnit4.class)
-public class AccessibilityEmbeddedDisplayTest {
-    private static Instrumentation sInstrumentation;
-    private static UiAutomation sUiAutomation;
-
-    private EmbeddedDisplayParentActivity mActivity;
-    private EmbeddedDisplayActivity mEmbeddedDisplayActivity;
-    private ActivityView mActivityView;
-    private Context mContext;
-
-    private String mParentActivityTitle;
-    private String mActivityTitle;
-
-    private final ActivityTestRule<EmbeddedDisplayParentActivity> mActivityRule =
-            new ActivityTestRule<>(EmbeddedDisplayParentActivity.class, false, false);
-
-    private final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
-            new AccessibilityDumpOnFailureRule();
-
-    @Rule
-    public final RuleChain mRuleChain = RuleChain
-            .outerRule(mActivityRule)
-            .around(mDumpOnFailureRule);
-
-    @BeforeClass
-    public static void oneTimeSetup() {
-        sInstrumentation = InstrumentationRegistry.getInstrumentation();
-        sUiAutomation = sInstrumentation.getUiAutomation();
-    }
-
-    @AfterClass
-    public static void postTestTearDown() {
-        sUiAutomation.destroy();
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        mContext = sInstrumentation.getContext();
-        assumeTrue(supportsMultiDisplay(mContext));
-
-        mParentActivityTitle = mContext.getString(
-                R.string.accessibility_embedded_display_test_parent_activity);
-        mActivityTitle = mContext.getString(R.string.accessibility_embedded_display_test_activity);
-
-        SystemUtil.runWithShellPermissionIdentity(() -> {
-            mActivity = launchActivityAndWaitForItToBeOnscreen(
-                    sInstrumentation, sUiAutomation, mActivityRule);
-            mActivityView = mActivity.getActivityView();
-        });
-
-        launchActivityInActivityView();
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        mEmbeddedDisplayActivity = null;
-        if (mActivityView != null) {
-            SystemUtil.runWithShellPermissionIdentity(() -> mActivityView.release());
-        }
-    }
-
-    @Presubmit
-    @Test
-    public void testA11yWindowInfoHasCorrectLayer() {
-        final AccessibilityWindowInfo parentActivityWindow =
-                findWindowByTitle(sUiAutomation, mParentActivityTitle);
-        final AccessibilityWindowInfo activityWindow =
-                findWindowByTitle(sUiAutomation, mActivityTitle);
-
-        assertNotNull(parentActivityWindow);
-        assertNotNull(activityWindow);
-        assertTrue(parentActivityWindow.getLayer() > activityWindow.getLayer());
-    }
-
-    @Presubmit
-    @Test
-    public void testA11yWindowInfoAndA11yNodeInfoHasCorrectBoundsInScreen() {
-        final AccessibilityWindowInfo parentActivityWindow =
-                findWindowByTitle(sUiAutomation, mParentActivityTitle);
-        final AccessibilityWindowInfo activityWindow =
-                findWindowByTitle(sUiAutomation, mActivityTitle);
-        final AccessibilityNodeInfo button = findWindowByTitle(sUiAutomation,
-                mActivityTitle).getRoot().findAccessibilityNodeInfosByViewId(
-                "android.accessibilityservice.cts:id/button").get(0);
-
-        assertNotNull(parentActivityWindow);
-        assertNotNull(activityWindow);
-        assertNotNull(button);
-
-        final Rect parentActivityBound = new Rect();
-        final Rect activityBound = new Rect();
-        final Rect buttonBound = new Rect();
-        parentActivityWindow.getBoundsInScreen(parentActivityBound);
-        activityWindow.getBoundsInScreen(activityBound);
-        button.getBoundsInScreen(buttonBound);
-
-        assertTrue("parentActivityBound" + parentActivityBound.toShortString()
-                        + " doesn't contain activityBound" + activityBound.toShortString(),
-                parentActivityBound.contains(activityBound));
-        assertTrue("parentActivityBound" + parentActivityBound.toShortString()
-                        + " doesn't contain buttonBound" + buttonBound.toShortString(),
-                parentActivityBound.contains(buttonBound));
-    }
-
-    @Test
-    public void testA11yWindowNotifyWhenResizeWindowInActivityView() throws Exception {
-        testA11yWindowNotifyAfterResizeWindowInActivityView();
-    }
-
-    @Test
-    public void testA11yWindowNotifyWhenResizeWindowInActivityViewAfterServiceOffAndOn()
-            throws Exception {
-        // Clears window access flag to disable the A11y window tracking.
-        AccessibilityServiceInfo info = sUiAutomation.getServiceInfo();
-        info.flags &= ~AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
-        sUiAutomation.setServiceInfo(info);
-
-        // Only needs to make sure the windows cannot be accessed for UiAutomation service
-        // because other A11y services had been disabled when calling the method, getUiAutomation().
-        assertTrue(sUiAutomation.getWindows().isEmpty());
-
-        // Sets window access flag to enable the A11y window tracking.
-        sUiAutomation.executeAndWaitForEvent(
-                () -> sInstrumentation.runOnMainSync(() -> {
-                    // Make sure we get window events, so we'll know when the window appears
-                    info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
-                    sUiAutomation.setServiceInfo(info);
-                }),
-                filterWindowsChangeTypesAndWindowTitle(sUiAutomation, WINDOWS_CHANGE_ADDED,
-                        mActivityTitle),
-                DEFAULT_TIMEOUT_MS);
-
-        testA11yWindowNotifyAfterResizeWindowInActivityView();
-    }
-
-    private void testA11yWindowNotifyAfterResizeWindowInActivityView() throws Exception {
-        final AccessibilityWindowInfo oldActivityWindow =
-                findWindowByTitle(sUiAutomation, mActivityTitle);
-        final Rect activityBound = new Rect();
-        oldActivityWindow.getBoundsInScreen(activityBound);
-
-        final int width = activityBound.width() / 2;
-        final int height = activityBound.height() / 2;
-        sUiAutomation.executeAndWaitForEvent(() -> sInstrumentation.runOnMainSync(
-                () -> mEmbeddedDisplayActivity.getWindow().setLayout(width, height)),
-                filterWindowsChangeTypesAndWindowTitle(sUiAutomation, WINDOWS_CHANGE_BOUNDS,
-                        mActivityTitle),
-                DEFAULT_TIMEOUT_MS);
-
-        final AccessibilityWindowInfo newActivityWindow =
-                findWindowByTitle(sUiAutomation, mActivityTitle);
-        newActivityWindow.getBoundsInScreen(activityBound);
-
-        assertEquals(height, activityBound.height());
-        assertEquals(width, activityBound.width());
-    }
-
-    private void launchActivityInActivityView() throws Exception {
-        final Instrumentation.ActivityMonitor am = sInstrumentation.addMonitor(
-                EmbeddedDisplayActivity.class.getName(), null, false);
-        final Rect bounds = new Rect();
-        sUiAutomation.executeAndWaitForEvent(
-                () -> sInstrumentation.runOnMainSync(() -> {
-                    Intent intent = new Intent(mContext, EmbeddedDisplayActivity.class);
-                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    SystemUtil.runWithShellPermissionIdentity(
-                            () -> mActivityView.startActivity(intent));
-                }),
-                (event) -> {
-                    // Ensure the target activity is shown
-                    final AccessibilityWindowInfo window =
-                            findWindowByTitle(sUiAutomation, mActivityTitle);
-                    if (window == null) {
-                        return false;
-                    }
-                    window.getBoundsInScreen(bounds);
-                    return !bounds.isEmpty();
-                }, DEFAULT_TIMEOUT_MS);
-        mEmbeddedDisplayActivity = (EmbeddedDisplayActivity)
-                am.waitForActivityWithTimeout(DEFAULT_TIMEOUT_MS);
-        assertNotNull(mEmbeddedDisplayActivity);
-    }
-
-    public static class EmbeddedDisplayParentActivity extends AccessibilityTestActivity {
-        private ActivityView mActivityView;
-
-        @Override
-        public void onCreate(Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-            mActivityView = new ActivityView.Builder(this)
-                    .setUsePublicVirtualDisplay(true).build();
-            setContentView(mActivityView);
-        }
-
-        ActivityView getActivityView() {
-            return mActivityView;
-        }
-    }
-
-    public static class EmbeddedDisplayActivity extends AccessibilityTestActivity {
-
-        @Override
-        public void onCreate(Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-            setContentView(R.layout.accessibility_embedded_display_test);
-        }
-    }
-}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index a4dd8ab..571c0d9 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -21,7 +21,6 @@
 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWindowsChangTypesAndWindowId;
 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWindowsChangeTypesAndWindowTitle;
 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWindowsChangedWithChangeTypes;
-import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.findWindowByTitle;
 import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
 import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityOnSpecifiedDisplayAndWaitForItToBeOnscreen;
 import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.supportsMultiDisplay;
@@ -63,11 +62,11 @@
 import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.cts.activities.AccessibilityWindowQueryActivity;
+import android.accessibilityservice.cts.activities.NonDefaultDisplayActivity;
 import android.app.Activity;
 import android.app.ActivityTaskManager;
 import android.app.Instrumentation;
 import android.app.UiAutomation;
-import android.content.pm.PackageManager;
 import android.graphics.Rect;
 import android.platform.test.annotations.AppModeFull;
 import android.test.suitebuilder.annotation.MediumTest;
@@ -665,7 +664,7 @@
             // Launches an activity on virtual display.
             mActivityOnVirtualDisplay = launchActivityOnSpecifiedDisplayAndWaitForItToBeOnscreen(
                     sInstrumentation, sUiAutomation,
-                    AccessibilityEmbeddedDisplayTest.EmbeddedDisplayActivity.class,
+                    NonDefaultDisplayActivity.class,
                     virtualDisplayId);
             // Adds two app panel windows on activity of virtual display.
             addTwoAppPanelWindows(mActivityOnVirtualDisplay);
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
index 416d5ca..94791de 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
@@ -47,13 +47,12 @@
 import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.cts.activities.AccessibilityWindowReportingActivity;
-import android.accessibilityservice.cts.utils.DisplayUtils;
+import android.accessibilityservice.cts.activities.NonDefaultDisplayActivity;
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.app.UiAutomation;
 import android.graphics.Rect;
 import android.os.SystemClock;
-import android.view.Display;
 import android.view.Gravity;
 import android.view.InputDevice;
 import android.view.MotionEvent;
@@ -265,7 +264,7 @@
             final Activity activityOnVirtualDisplay =
                     launchActivityOnSpecifiedDisplayAndWaitForItToBeOnscreen(sInstrumentation,
                             sUiAutomation,
-                            AccessibilityEmbeddedDisplayTest.EmbeddedDisplayActivity.class,
+                            NonDefaultDisplayActivity.class,
                             virtualDisplayId);
 
             final CharSequence activityTitle = getActivityTitle(sInstrumentation,
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/NonDefaultDisplayActivity.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/NonDefaultDisplayActivity.java
new file mode 100644
index 0000000..11b763f
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/NonDefaultDisplayActivity.java
@@ -0,0 +1,32 @@
+/*
+ * 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.accessibilityservice.cts.activities;
+
+import android.accessibilityservice.cts.R;
+import android.os.Bundle;
+
+/**
+ * Activity used by AccessibilityWindowQueryTest and AccessibilityWindowReportingTest
+ */
+public class NonDefaultDisplayActivity extends AccessibilityTestActivity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.non_default_display_activity);
+    }
+}
diff --git a/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java b/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
index 77973bb..db74563 100644
--- a/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
+++ b/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
@@ -825,6 +825,11 @@
         // Start a process and crash it
         startService(ACTION_NATIVE_CRASH, STUB_SERVICE_NAME, true, false);
 
+        // Native crashes are handled asynchronously from the actual crash, so
+        // it's possible for us to notice that the process crashed before an
+        // actual tombstone exists.
+        Thread.sleep(1000);
+
         long now2 = System.currentTimeMillis();
         List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions(
                 STUB_PACKAGE_NAME, mStubPackagePid, 1,
diff --git a/tests/appsearch/src/com/android/cts/appsearch/AppSearchSchemaMigrationCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/app/AppSearchSchemaMigrationCtsTest.java
similarity index 92%
rename from tests/appsearch/src/com/android/cts/appsearch/AppSearchSchemaMigrationCtsTest.java
rename to tests/appsearch/src/com/android/cts/appsearch/app/AppSearchSchemaMigrationCtsTest.java
index 916375b..2c6e032 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/AppSearchSchemaMigrationCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/app/AppSearchSchemaMigrationCtsTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 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.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch.cts;
+package android.app.appsearch.cts.app;
 
 import android.app.appsearch.AppSearchManager;
 import android.app.appsearch.AppSearchSessionShim;
diff --git a/tests/appsearch/src/com/android/cts/appsearch/AppSearchSessionCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/app/AppSearchSessionCtsTest.java
similarity index 82%
rename from tests/appsearch/src/com/android/cts/appsearch/AppSearchSessionCtsTest.java
rename to tests/appsearch/src/com/android/cts/appsearch/app/AppSearchSessionCtsTest.java
index 54c867d..559653cf 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/AppSearchSessionCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/app/AppSearchSessionCtsTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 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.
@@ -13,12 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch.cts;
+package android.app.appsearch.cts.app;
 
 import android.app.appsearch.AppSearchManager;
 import android.app.appsearch.AppSearchSessionShim;
+import android.content.Context;
 
 import androidx.annotation.NonNull;
+import androidx.test.core.app.ApplicationProvider;
 
 import com.android.server.appsearch.testing.AppSearchSessionShimImpl;
 
@@ -36,7 +38,8 @@
     @Override
     protected ListenableFuture<AppSearchSessionShim> createSearchSession(
             @NonNull String dbName, @NonNull ExecutorService executor) {
-        return AppSearchSessionShimImpl.createSearchSession(
+        Context context = ApplicationProvider.getApplicationContext();
+        return AppSearchSessionShimImpl.createSearchSession(context,
                 new AppSearchManager.SearchContext.Builder(dbName).build(), executor);
     }
 }
diff --git a/tests/appsearch/src/com/android/cts/appsearch/AppSearchSessionPlatformCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/app/AppSearchSessionPlatformCtsTest.java
similarity index 99%
rename from tests/appsearch/src/com/android/cts/appsearch/AppSearchSessionPlatformCtsTest.java
rename to tests/appsearch/src/com/android/cts/appsearch/app/AppSearchSessionPlatformCtsTest.java
index 3569cba..9f42c74 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/AppSearchSessionPlatformCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/app/AppSearchSessionPlatformCtsTest.java
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+package android.app.appsearch.cts.app;
+
 import static android.os.storage.StorageManager.UUID_DEFAULT;
 
 import static com.google.common.truth.Truth.assertThat;
diff --git a/tests/appsearch/src/com/android/cts/appsearch/GlobalSearchSessionCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/app/GlobalSearchSessionCtsTest.java
similarity index 93%
rename from tests/appsearch/src/com/android/cts/appsearch/GlobalSearchSessionCtsTest.java
rename to tests/appsearch/src/com/android/cts/appsearch/app/GlobalSearchSessionCtsTest.java
index 7df7a51..ecdc9c0 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/GlobalSearchSessionCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/app/GlobalSearchSessionCtsTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 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.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch.cts;
+package android.app.appsearch.cts.app;
 
 import android.app.appsearch.AppSearchManager;
 import android.app.appsearch.AppSearchSessionShim;
diff --git a/tests/appsearch/src/com/android/cts/appsearch/GlobalSearchSessionPlatformCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/app/GlobalSearchSessionPlatformCtsTest.java
similarity index 99%
rename from tests/appsearch/src/com/android/cts/appsearch/GlobalSearchSessionPlatformCtsTest.java
rename to tests/appsearch/src/com/android/cts/appsearch/app/GlobalSearchSessionPlatformCtsTest.java
index ee71acf..d8fbc84 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/GlobalSearchSessionPlatformCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/app/GlobalSearchSessionPlatformCtsTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch.cts;
+package android.app.appsearch.cts.app;
 
 import static com.android.server.appsearch.testing.AppSearchTestUtils.checkIsBatchResultSuccess;
 
@@ -58,7 +58,7 @@
 import java.util.concurrent.TimeUnit;
 
 /**
- * This doesn't extend the {@link android.app.appsearch.cts.GlobalSearchSessionCtsTestBase} since
+ * This doesn't extend {@link android.app.appsearch.cts.app.GlobalSearchSessionCtsTestBase} since
  * these test cases can't be run in a non-platform environment.
  */
 @AppModeFull(reason = "Can't bind to helper apps from instant mode")
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/SearchSpecCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/SearchSpecCtsTest.java
deleted file mode 100644
index 5eb18b3..0000000
--- a/tests/appsearch/src/com/android/cts/appsearch/external/SearchSpecCtsTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.appsearch.SearchSpec;
-
-import org.junit.Test;
-
-public class SearchSpecCtsTest {
-    @Test
-    public void testBuildSearchSpecWithoutTermMatch() {
-        SearchSpec searchSpec = new SearchSpec.Builder().addFilterSchemas("testSchemaType").build();
-        assertThat(searchSpec.getTermMatch()).isEqualTo(SearchSpec.TERM_MATCH_PREFIX);
-    }
-
-    @Test
-    public void testBuildSearchSpec() {
-        SearchSpec searchSpec =
-                new SearchSpec.Builder()
-                        .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
-                        .addFilterNamespaces("namespace1", "namespace2")
-                        .addFilterSchemas("schemaTypes1", "schemaTypes2")
-                        .addFilterPackageNames("package1", "package2")
-                        .setSnippetCount(5)
-                        .setSnippetCountPerProperty(10)
-                        .setMaxSnippetSize(15)
-                        .setResultCountPerPage(42)
-                        .setOrder(SearchSpec.ORDER_ASCENDING)
-                        .setRankingStrategy(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE)
-                        .setResultGrouping(
-                                SearchSpec.GROUPING_TYPE_PER_NAMESPACE
-                                        | SearchSpec.GROUPING_TYPE_PER_PACKAGE,
-                                /*limit=*/ 37)
-                        .build();
-
-        assertThat(searchSpec.getTermMatch()).isEqualTo(SearchSpec.TERM_MATCH_PREFIX);
-        assertThat(searchSpec.getFilterNamespaces())
-                .containsExactly("namespace1", "namespace2")
-                .inOrder();
-        assertThat(searchSpec.getFilterSchemas())
-                .containsExactly("schemaTypes1", "schemaTypes2")
-                .inOrder();
-        assertThat(searchSpec.getFilterPackageNames())
-                .containsExactly("package1", "package2")
-                .inOrder();
-        assertThat(searchSpec.getSnippetCount()).isEqualTo(5);
-        assertThat(searchSpec.getSnippetCountPerProperty()).isEqualTo(10);
-        assertThat(searchSpec.getMaxSnippetSize()).isEqualTo(15);
-        assertThat(searchSpec.getResultCountPerPage()).isEqualTo(42);
-        assertThat(searchSpec.getOrder()).isEqualTo(SearchSpec.ORDER_ASCENDING);
-        assertThat(searchSpec.getRankingStrategy())
-                .isEqualTo(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE);
-        assertThat(searchSpec.getResultGroupingTypeFlags())
-                .isEqualTo(
-                        SearchSpec.GROUPING_TYPE_PER_NAMESPACE
-                                | SearchSpec.GROUPING_TYPE_PER_PACKAGE);
-        assertThat(searchSpec.getResultGroupingLimit()).isEqualTo(37);
-    }
-}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/SetSchemaResponseCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/SetSchemaResponseCtsTest.java
deleted file mode 100644
index 4632fd7..0000000
--- a/tests/appsearch/src/com/android/cts/appsearch/external/SetSchemaResponseCtsTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.appsearch.AppSearchResult;
-import android.app.appsearch.SetSchemaResponse;
-
-import org.junit.Test;
-
-public class SetSchemaResponseCtsTest {
-    @Test
-    public void testRebuild() {
-        SetSchemaResponse.MigrationFailure failure1 =
-                new SetSchemaResponse.MigrationFailure(
-                        "namespace",
-                        "failure1",
-                        "schemaType",
-                        AppSearchResult.newFailedResult(
-                                AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
-        SetSchemaResponse.MigrationFailure failure2 =
-                new SetSchemaResponse.MigrationFailure(
-                        "namespace",
-                        "failure2",
-                        "schemaType",
-                        AppSearchResult.newFailedResult(
-                                AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
-
-        SetSchemaResponse original =
-                new SetSchemaResponse.Builder()
-                        .addDeletedType("delete1")
-                        .addIncompatibleType("incompatible1")
-                        .addMigratedType("migrated1")
-                        .addMigrationFailure(failure1)
-                        .build();
-        assertThat(original.getDeletedTypes()).containsExactly("delete1");
-        assertThat(original.getIncompatibleTypes()).containsExactly("incompatible1");
-        assertThat(original.getMigratedTypes()).containsExactly("migrated1");
-        assertThat(original.getMigrationFailures()).containsExactly(failure1);
-
-        SetSchemaResponse rebuild =
-                original.toBuilder()
-                        .addDeletedType("delete2")
-                        .addIncompatibleType("incompatible2")
-                        .addMigratedType("migrated2")
-                        .addMigrationFailure(failure2)
-                        .build();
-
-        // rebuild won't effect the original object
-        assertThat(original.getDeletedTypes()).containsExactly("delete1");
-        assertThat(original.getIncompatibleTypes()).containsExactly("incompatible1");
-        assertThat(original.getMigratedTypes()).containsExactly("migrated1");
-        assertThat(original.getMigrationFailures()).containsExactly(failure1);
-
-        assertThat(rebuild.getDeletedTypes()).containsExactly("delete1", "delete2");
-        assertThat(rebuild.getIncompatibleTypes())
-                .containsExactly("incompatible1", "incompatible2");
-        assertThat(rebuild.getMigratedTypes()).containsExactly("migrated1", "migrated2");
-        assertThat(rebuild.getMigrationFailures()).containsExactly(failure1, failure2);
-    }
-}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchBatchResultCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchBatchResultCtsTest.java
similarity index 99%
rename from tests/appsearch/src/com/android/cts/appsearch/external/AppSearchBatchResultCtsTest.java
rename to tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchBatchResultCtsTest.java
index 0644ed4..aab7098 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchBatchResultCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchBatchResultCtsTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.app.appsearch.cts;
+package android.app.appsearch.cts.app;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchMigratorTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchMigratorTest.java
similarity index 99%
rename from tests/appsearch/src/com/android/cts/appsearch/external/AppSearchMigratorTest.java
rename to tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchMigratorTest.java
index 74af26d..f847769 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchMigratorTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchMigratorTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.app.appsearch.cts;
+package android.app.appsearch.cts.app;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchResultCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchResultCtsTest.java
similarity index 98%
rename from tests/appsearch/src/com/android/cts/appsearch/external/AppSearchResultCtsTest.java
rename to tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchResultCtsTest.java
index 9c34b17..2691ecf 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchResultCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchResultCtsTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.app.appsearch.cts;
+package android.app.appsearch.cts.app;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchSchemaCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSchemaCtsTest.java
similarity index 68%
rename from tests/appsearch/src/com/android/cts/appsearch/external/AppSearchSchemaCtsTest.java
rename to tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSchemaCtsTest.java
index 191438c..b74664c 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchSchemaCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSchemaCtsTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.app.appsearch.cts;
+package android.app.appsearch.cts.app;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -25,8 +25,12 @@
 import android.app.appsearch.AppSearchSchema.StringPropertyConfig;
 import android.app.appsearch.exceptions.IllegalSchemaException;
 
+import com.android.server.appsearch.testing.AppSearchEmail;
+
 import org.junit.Test;
 
+import java.util.List;
+
 public class AppSearchSchemaCtsTest {
     @Test
     public void testInvalidEnums() {
@@ -187,4 +191,82 @@
         assertThat(schema1).isNotEqualTo(schema2);
         assertThat(schema1.hashCode()).isNotEqualTo(schema2.hashCode());
     }
+
+    @Test
+    public void testPropertyConfig() {
+        AppSearchSchema schema =
+                new AppSearchSchema.Builder("Test")
+                        .addProperty(
+                                new StringPropertyConfig.Builder("string")
+                                        .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+                                        .setIndexingType(
+                                                StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+                                        .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+                                        .build())
+                        .addProperty(
+                                new AppSearchSchema.Int64PropertyConfig.Builder("long")
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .build())
+                        .addProperty(
+                                new AppSearchSchema.DoublePropertyConfig.Builder("double")
+                                        .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+                                        .build())
+                        .addProperty(
+                                new AppSearchSchema.BooleanPropertyConfig.Builder("boolean")
+                                        .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+                                        .build())
+                        .addProperty(
+                                new AppSearchSchema.BytesPropertyConfig.Builder("bytes")
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .build())
+                        .addProperty(
+                                new AppSearchSchema.DocumentPropertyConfig.Builder(
+                                                "document", AppSearchEmail.SCHEMA_TYPE)
+                                        .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+                                        .setShouldIndexNestedProperties(true)
+                                        .build())
+                        .build();
+
+        assertThat(schema.getSchemaType()).isEqualTo("Test");
+        List<PropertyConfig> properties = schema.getProperties();
+        assertThat(properties).hasSize(6);
+
+        assertThat(properties.get(0).getName()).isEqualTo("string");
+        assertThat(properties.get(0).getCardinality())
+                .isEqualTo(PropertyConfig.CARDINALITY_REQUIRED);
+        assertThat(((StringPropertyConfig) properties.get(0)).getIndexingType())
+                .isEqualTo(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS);
+        assertThat(((StringPropertyConfig) properties.get(0)).getTokenizerType())
+                .isEqualTo(StringPropertyConfig.TOKENIZER_TYPE_PLAIN);
+
+        assertThat(properties.get(1).getName()).isEqualTo("long");
+        assertThat(properties.get(1).getCardinality())
+                .isEqualTo(PropertyConfig.CARDINALITY_OPTIONAL);
+        assertThat(properties.get(1)).isInstanceOf(AppSearchSchema.Int64PropertyConfig.class);
+
+        assertThat(properties.get(2).getName()).isEqualTo("double");
+        assertThat(properties.get(2).getCardinality())
+                .isEqualTo(PropertyConfig.CARDINALITY_REPEATED);
+        assertThat(properties.get(2)).isInstanceOf(AppSearchSchema.DoublePropertyConfig.class);
+
+        assertThat(properties.get(3).getName()).isEqualTo("boolean");
+        assertThat(properties.get(3).getCardinality())
+                .isEqualTo(PropertyConfig.CARDINALITY_REQUIRED);
+        assertThat(properties.get(3)).isInstanceOf(AppSearchSchema.BooleanPropertyConfig.class);
+
+        assertThat(properties.get(4).getName()).isEqualTo("bytes");
+        assertThat(properties.get(4).getCardinality())
+                .isEqualTo(PropertyConfig.CARDINALITY_OPTIONAL);
+        assertThat(properties.get(4)).isInstanceOf(AppSearchSchema.BytesPropertyConfig.class);
+
+        assertThat(properties.get(5).getName()).isEqualTo("document");
+        assertThat(properties.get(5).getCardinality())
+                .isEqualTo(PropertyConfig.CARDINALITY_REPEATED);
+        assertThat(((AppSearchSchema.DocumentPropertyConfig) properties.get(5)).getSchemaType())
+                .isEqualTo(AppSearchEmail.SCHEMA_TYPE);
+        assertThat(
+                        ((AppSearchSchema.DocumentPropertyConfig) properties.get(5))
+                                .shouldIndexNestedProperties())
+                .isEqualTo(true);
+    }
 }
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchSchemaMigrationCtsTestBase.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSchemaMigrationCtsTestBase.java
similarity index 99%
rename from tests/appsearch/src/com/android/cts/appsearch/external/AppSearchSchemaMigrationCtsTestBase.java
rename to tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSchemaMigrationCtsTestBase.java
index d932e0d..6dc46c2 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchSchemaMigrationCtsTestBase.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSchemaMigrationCtsTestBase.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.app.appsearch.cts;
+package android.app.appsearch.cts.app;
 
 import static com.android.server.appsearch.testing.AppSearchTestUtils.checkIsBatchResultSuccess;
 import static com.android.server.appsearch.testing.AppSearchTestUtils.convertSearchResultsToDocuments;
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchSessionCtsTestBase.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSessionCtsTestBase.java
similarity index 91%
rename from tests/appsearch/src/com/android/cts/appsearch/external/AppSearchSessionCtsTestBase.java
rename to tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSessionCtsTestBase.java
index e180218..486ad3a 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchSessionCtsTestBase.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchSessionCtsTestBase.java
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package android.app.appsearch.cts;
+package android.app.appsearch.cts.app;
 
 import static android.app.appsearch.AppSearchResult.RESULT_INVALID_SCHEMA;
+import static android.app.appsearch.AppSearchResult.RESULT_NOT_FOUND;
 
 import static com.android.server.appsearch.testing.AppSearchTestUtils.checkIsBatchResultSuccess;
 import static com.android.server.appsearch.testing.AppSearchTestUtils.convertSearchResultsToDocuments;
@@ -234,6 +235,101 @@
     }
 
     @Test
+    public void testGetSchema_allPropertyTypes() throws Exception {
+        AppSearchSchema inSchema =
+                new AppSearchSchema.Builder("Test")
+                        .addProperty(
+                                new StringPropertyConfig.Builder("string")
+                                        .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+                                        .setIndexingType(
+                                                StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+                                        .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+                                        .build())
+                        .addProperty(
+                                new AppSearchSchema.Int64PropertyConfig.Builder("long")
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .build())
+                        .addProperty(
+                                new AppSearchSchema.DoublePropertyConfig.Builder("double")
+                                        .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+                                        .build())
+                        .addProperty(
+                                new AppSearchSchema.BooleanPropertyConfig.Builder("boolean")
+                                        .setCardinality(PropertyConfig.CARDINALITY_REQUIRED)
+                                        .build())
+                        .addProperty(
+                                new AppSearchSchema.BytesPropertyConfig.Builder("bytes")
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .build())
+                        .addProperty(
+                                new AppSearchSchema.DocumentPropertyConfig.Builder(
+                                                "document", AppSearchEmail.SCHEMA_TYPE)
+                                        .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
+                                        .setShouldIndexNestedProperties(true)
+                                        .build())
+                        .build();
+
+        // Add it to AppSearch and then obtain it again
+        mDb1.setSchema(
+                        new SetSchemaRequest.Builder()
+                                .addSchemas(inSchema, AppSearchEmail.SCHEMA)
+                                .build())
+                .get();
+        GetSchemaResponse response = mDb1.getSchema().get();
+        List<AppSearchSchema> schemas = new ArrayList<>(response.getSchemas());
+        assertThat(schemas).containsExactly(inSchema, AppSearchEmail.SCHEMA);
+        AppSearchSchema outSchema;
+        if (schemas.get(0).getSchemaType().equals("Test")) {
+            outSchema = schemas.get(0);
+        } else {
+            outSchema = schemas.get(1);
+        }
+        assertThat(outSchema.getSchemaType()).isEqualTo("Test");
+        assertThat(outSchema).isNotSameInstanceAs(inSchema);
+
+        List<PropertyConfig> properties = outSchema.getProperties();
+        assertThat(properties).hasSize(6);
+
+        assertThat(properties.get(0).getName()).isEqualTo("string");
+        assertThat(properties.get(0).getCardinality())
+                .isEqualTo(PropertyConfig.CARDINALITY_REQUIRED);
+        assertThat(((StringPropertyConfig) properties.get(0)).getIndexingType())
+                .isEqualTo(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS);
+        assertThat(((StringPropertyConfig) properties.get(0)).getTokenizerType())
+                .isEqualTo(StringPropertyConfig.TOKENIZER_TYPE_PLAIN);
+
+        assertThat(properties.get(1).getName()).isEqualTo("long");
+        assertThat(properties.get(1).getCardinality())
+                .isEqualTo(PropertyConfig.CARDINALITY_OPTIONAL);
+        assertThat(properties.get(1)).isInstanceOf(AppSearchSchema.Int64PropertyConfig.class);
+
+        assertThat(properties.get(2).getName()).isEqualTo("double");
+        assertThat(properties.get(2).getCardinality())
+                .isEqualTo(PropertyConfig.CARDINALITY_REPEATED);
+        assertThat(properties.get(2)).isInstanceOf(AppSearchSchema.DoublePropertyConfig.class);
+
+        assertThat(properties.get(3).getName()).isEqualTo("boolean");
+        assertThat(properties.get(3).getCardinality())
+                .isEqualTo(PropertyConfig.CARDINALITY_REQUIRED);
+        assertThat(properties.get(3)).isInstanceOf(AppSearchSchema.BooleanPropertyConfig.class);
+
+        assertThat(properties.get(4).getName()).isEqualTo("bytes");
+        assertThat(properties.get(4).getCardinality())
+                .isEqualTo(PropertyConfig.CARDINALITY_OPTIONAL);
+        assertThat(properties.get(4)).isInstanceOf(AppSearchSchema.BytesPropertyConfig.class);
+
+        assertThat(properties.get(5).getName()).isEqualTo("document");
+        assertThat(properties.get(5).getCardinality())
+                .isEqualTo(PropertyConfig.CARDINALITY_REPEATED);
+        assertThat(((AppSearchSchema.DocumentPropertyConfig) properties.get(5)).getSchemaType())
+                .isEqualTo(AppSearchEmail.SCHEMA_TYPE);
+        assertThat(
+                        ((AppSearchSchema.DocumentPropertyConfig) properties.get(5))
+                                .shouldIndexNestedProperties())
+                .isEqualTo(true);
+    }
+
+    @Test
     public void testGetNamespaces() throws Exception {
         // Schema registration
         mDb1.setSchema(new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build())
@@ -1920,7 +2016,6 @@
     @Test
     public void testSnippet() throws Exception {
         // Schema registration
-        // TODO(tytytyww) add property for long and  double.
         AppSearchSchema genericSchema =
                 new AppSearchSchema.Builder("Generic")
                         .addProperty(
@@ -1975,6 +2070,57 @@
     }
 
     @Test
+    public void testCJKSnippet() throws Exception {
+        // Schema registration
+        AppSearchSchema genericSchema =
+                new AppSearchSchema.Builder("Generic")
+                        .addProperty(
+                                new StringPropertyConfig.Builder("subject")
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+                                        .setIndexingType(
+                                                StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+                                        .build())
+                        .build();
+        mDb1.setSchema(new SetSchemaRequest.Builder().addSchemas(genericSchema).build()).get();
+
+        String japanese =
+                "差し出されたのが今日ランドセルでした普通の子であれば満面の笑みで俺を言うでしょうしかし私は赤いランド"
+                        + "セルを見て笑うことができませんでしたどうしたのと心配そうな仕事ガラスながら渋い顔する私書いたこと言"
+                        + "うんじゃないのカードとなる声を聞きたい私は目から涙をこぼしながらおじいちゃんの近くにかけおり頭をポ"
+                        + "ンポンと叩きピンクが良かったんだもん";
+        // Index a document
+        GenericDocument document =
+                new GenericDocument.Builder<>("namespace", "id", "Generic")
+                        .setPropertyString("subject", japanese)
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.put(new PutDocumentsRequest.Builder().addGenericDocuments(document).build()));
+
+        // Query for the document
+        SearchResultsShim searchResults =
+                mDb1.search(
+                        "は",
+                        new SearchSpec.Builder()
+                                .addFilterSchemas("Generic")
+                                .setSnippetCount(1)
+                                .setSnippetCountPerProperty(1)
+                                .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+                                .build());
+        List<SearchResult> results = searchResults.getNextPage().get();
+        assertThat(results).hasSize(1);
+
+        List<SearchResult.MatchInfo> matchInfos = results.get(0).getMatchInfos();
+        assertThat(matchInfos).isNotNull();
+        assertThat(matchInfos).hasSize(1);
+        SearchResult.MatchInfo matchInfo = matchInfos.get(0);
+        assertThat(matchInfo.getFullText()).isEqualTo(japanese);
+        assertThat(matchInfo.getExactMatchRange())
+                .isEqualTo(new SearchResult.MatchRange(/*lower=*/ 44, /*upper=*/ 45));
+        assertThat(matchInfo.getExactMatch()).isEqualTo("は");
+    }
+
+    @Test
     public void testRemove() throws Exception {
         // Schema registration
         mDb1.setSchema(new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build())
@@ -2035,6 +2181,58 @@
     }
 
     @Test
+    public void testRemove_multipleIds() throws Exception {
+        // Schema registration
+        mDb1.setSchema(new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build())
+                .get();
+
+        // Index documents
+        AppSearchEmail email1 =
+                new AppSearchEmail.Builder("namespace", "id1")
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        AppSearchEmail email2 =
+                new AppSearchEmail.Builder("namespace", "id2")
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example 2")
+                        .setBody("This is the body of the testPut second email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.put(
+                        new PutDocumentsRequest.Builder()
+                                .addGenericDocuments(email1, email2)
+                                .build()));
+
+        // Check the presence of the documents
+        assertThat(doGet(mDb1, "namespace", "id1")).hasSize(1);
+        assertThat(doGet(mDb1, "namespace", "id2")).hasSize(1);
+
+        // Delete the document
+        checkIsBatchResultSuccess(
+                mDb1.remove(
+                        new RemoveByDocumentIdRequest.Builder("namespace")
+                                .addIds("id1", "id2")
+                                .build()));
+
+        // Make sure it's really gone
+        AppSearchBatchResult<String, GenericDocument> getResult =
+                mDb1.getByDocumentId(
+                                new GetByDocumentIdRequest.Builder("namespace")
+                                        .addIds("id1", "id2")
+                                        .build())
+                        .get();
+        assertThat(getResult.isSuccess()).isFalse();
+        assertThat(getResult.getFailures().get("id1").getResultCode())
+                .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+        assertThat(getResult.getFailures().get("id2").getResultCode())
+                .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+    }
+
+    @Test
     public void testRemoveByQuery() throws Exception {
         // Schema registration
         mDb1.setSchema(new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build())
@@ -2803,13 +3001,13 @@
         // Email 1 has three usages and email 2 has two usages.
         assertThat(results).hasSize(2);
         assertThat(results.get(0).getGenericDocument()).isEqualTo(email1);
-        assertThat(results.get(0).getRankingSignal()).isEqualTo(3);
         assertThat(results.get(1).getGenericDocument()).isEqualTo(email2);
+        assertThat(results.get(0).getRankingSignal()).isEqualTo(3);
         assertThat(results.get(1).getRankingSignal()).isEqualTo(2);
 
-        // Query by most recent usag.
-        List<GenericDocument> documents =
-                convertSearchResultsToDocuments(
+        // Query by most recent usage.
+        results =
+                retrieveAllSearchResults(
                         mDb1.search(
                                 "",
                                 new SearchSpec.Builder()
@@ -2818,8 +3016,36 @@
                                                         .RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP)
                                         .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
                                         .build()));
-        // TODO(b/182958600) Check the score for usage timestamp once b/182958600 is fixed.
-        assertThat(documents).containsExactly(email2, email1).inOrder();
+        assertThat(results).hasSize(2);
+        assertThat(results.get(0).getGenericDocument()).isEqualTo(email2);
+        assertThat(results.get(1).getGenericDocument()).isEqualTo(email1);
+        assertThat(results.get(0).getRankingSignal()).isEqualTo(20000);
+        assertThat(results.get(1).getRankingSignal()).isEqualTo(3000);
+    }
+
+    @Test
+    public void testReportUsage_invalidNamespace() throws Exception {
+        mDb1.setSchema(new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build())
+                .get();
+        AppSearchEmail email1 = new AppSearchEmail.Builder("namespace", "id1").build();
+        checkIsBatchResultSuccess(
+                mDb1.put(new PutDocumentsRequest.Builder().addGenericDocuments(email1).build()));
+
+        // Use the correct namespace; it works
+        mDb1.reportUsage(new ReportUsageRequest.Builder("namespace", "id1").build()).get();
+
+        // Use an incorrect namespace; it fails
+        ExecutionException e =
+                expectThrows(
+                        ExecutionException.class,
+                        () ->
+                                mDb1.reportUsage(
+                                                new ReportUsageRequest.Builder("namespace2", "id1")
+                                                        .build())
+                                        .get());
+        assertThat(e).hasCauseThat().isInstanceOf(AppSearchException.class);
+        AppSearchException cause = (AppSearchException) e.getCause();
+        assertThat(cause.getResultCode()).isEqualTo(RESULT_NOT_FOUND);
     }
 
     @Test
@@ -3031,4 +3257,47 @@
         assertThat(matches.get(0).getFullText()).isEqualTo("This is the body");
         assertThat(matches.get(0).getExactMatch()).isEqualTo("body");
     }
+
+    @Test
+    public void testCJKTQuery() throws Exception {
+        // Schema registration
+        mDb1.setSchema(new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build())
+                .get();
+
+        // Index a document to instance 1.
+        AppSearchEmail inEmail1 =
+                new AppSearchEmail.Builder("namespace", "uri1").setBody("他是個男孩 is a boy").build();
+        checkIsBatchResultSuccess(
+                mDb1.put(new PutDocumentsRequest.Builder().addGenericDocuments(inEmail1).build()));
+
+        // Query for "他" (He)
+        SearchResultsShim searchResults =
+                mDb1.search(
+                        "他",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+                                .build());
+        List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+        assertThat(documents).containsExactly(inEmail1);
+
+        // Query for "男孩" (boy)
+        searchResults =
+                mDb1.search(
+                        "男孩",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+                                .build());
+        documents = convertSearchResultsToDocuments(searchResults);
+        assertThat(documents).containsExactly(inEmail1);
+
+        // Query for "boy"
+        searchResults =
+                mDb1.search(
+                        "boy",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+                                .build());
+        documents = convertSearchResultsToDocuments(searchResults);
+        assertThat(documents).containsExactly(inEmail1);
+    }
 }
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/GenericDocumentCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java
similarity index 86%
rename from tests/appsearch/src/com/android/cts/appsearch/external/GenericDocumentCtsTest.java
rename to tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java
index c561473..649448a 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/GenericDocumentCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/GenericDocumentCtsTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.app.appsearch.cts;
+package android.app.appsearch.cts.app;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -39,6 +39,11 @@
                     .build();
 
     @Test
+    public void testMaxIndexedProperties() {
+        assertThat(GenericDocument.getMaxIndexedProperties()).isEqualTo(16);
+    }
+
+    @Test
     public void testDocumentEquals_identical() {
         GenericDocument document1 =
                 new GenericDocument.Builder<>("namespace", "id1", "schemaType1")
@@ -166,6 +171,28 @@
                 .containsExactly((byte) 1, (byte) 2, (byte) 3)
                 .inOrder();
         assertThat(document.getPropertyDocument("documentKey1")).isEqualTo(sDocumentProperties1);
+
+        assertThat(document.getProperty("longKey1")).isInstanceOf(long[].class);
+        assertThat((long[]) document.getProperty("longKey1")).asList().containsExactly(1L);
+        assertThat(document.getProperty("doubleKey1")).isInstanceOf(double[].class);
+        assertThat((double[]) document.getProperty("doubleKey1"))
+                .usingTolerance(0.05)
+                .containsExactly(1.0);
+        assertThat(document.getProperty("booleanKey1")).isInstanceOf(boolean[].class);
+        assertThat((boolean[]) document.getProperty("booleanKey1")).asList().containsExactly(true);
+        assertThat(document.getProperty("stringKey1")).isInstanceOf(String[].class);
+        assertThat((String[]) document.getProperty("stringKey1"))
+                .asList()
+                .containsExactly("test-value1");
+        assertThat(document.getProperty("byteKey1")).isInstanceOf(byte[][].class);
+        assertThat((byte[][]) document.getProperty("byteKey1"))
+                .asList()
+                .containsExactly(sByteArray1)
+                .inOrder();
+        assertThat(document.getProperty("documentKey1")).isInstanceOf(GenericDocument[].class);
+        assertThat((GenericDocument[]) document.getProperty("documentKey1"))
+                .asList()
+                .containsExactly(sDocumentProperties1);
     }
 
     @Test
@@ -213,48 +240,61 @@
 
     @Test
     public void testDocument_toString() {
-        GenericDocument document =
-                new GenericDocument.Builder<>(/*namespace=*/ "", "id1", "schemaType1")
-                        .setCreationTimestampMillis(5L)
-                        .setPropertyLong("longKey1", 1L, 2L, 3L)
-                        .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
-                        .setPropertyBoolean("booleanKey1", true, false, true)
-                        .setPropertyString("stringKey1", "String1", "String2", "String3")
-                        .setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
-                        .setPropertyDocument(
-                                "documentKey1", sDocumentProperties1, sDocumentProperties2)
+        GenericDocument nestedDocValue =
+                new GenericDocument.Builder<GenericDocument.Builder<?>>(
+                                "namespace", "id2", "schemaType2")
+                        .setCreationTimestampMillis(1L)
+                        .setScore(1)
+                        .setTtlMillis(1L)
+                        .setPropertyString("stringKey1", "val1", "val2")
                         .build();
-        String exceptedString =
-                "{ name: 'creationTimestampMillis' value: 5 } "
-                        + "{ name: 'id' value: id1 } "
-                        + "{ name: 'namespace' value:  } "
-                        + "{ name: 'properties' value: "
-                        + "{ name: 'booleanKey1' value: [ 'true' 'false' 'true' ] } "
-                        + "{ name: 'byteKey1' value: "
-                        + "{ name: 'byteArray' value: [ '1' '2' '3' ] } "
-                        + "{ name: 'byteArray' value: [ '4' '5' '6' '7' ] }  } "
-                        + "{ name: 'documentKey1' value: [ '"
-                        + "{ name: 'creationTimestampMillis' value: 12345 } "
-                        + "{ name: 'id' value: sDocumentProperties1 } "
-                        + "{ name: 'namespace' value: namespace } "
-                        + "{ name: 'properties' value:  } "
-                        + "{ name: 'schemaType' value: sDocumentPropertiesSchemaType1 } "
-                        + "{ name: 'score' value: 0 } "
-                        + "{ name: 'ttlMillis' value: 0 } ' '"
-                        + "{ name: 'creationTimestampMillis' value: 6789 } "
-                        + "{ name: 'id' value: sDocumentProperties2 } "
-                        + "{ name: 'namespace' value: namespace } "
-                        + "{ name: 'properties' value:  } "
-                        + "{ name: 'schemaType' value: sDocumentPropertiesSchemaType2 } "
-                        + "{ name: 'score' value: 0 } "
-                        + "{ name: 'ttlMillis' value: 0 } ' ] } "
-                        + "{ name: 'doubleKey1' value: [ '1.0' '2.0' '3.0' ] } "
-                        + "{ name: 'longKey1' value: [ '1' '2' '3' ] } "
-                        + "{ name: 'stringKey1' value: [ 'String1' 'String2' 'String3' ] }  } "
-                        + "{ name: 'schemaType' value: schemaType1 } "
-                        + "{ name: 'score' value: 0 } "
-                        + "{ name: 'ttlMillis' value: 0 } ";
-        assertThat(document.toString()).isEqualTo(exceptedString);
+        GenericDocument document =
+                new GenericDocument.Builder<GenericDocument.Builder<?>>(
+                                "namespace", "id1", "schemaType1")
+                        .setCreationTimestampMillis(1L)
+                        .setScore(1)
+                        .setTtlMillis(1L)
+                        .setPropertyString("stringKey1", "val1", "val2")
+                        .setPropertyBytes("bytesKey1", new byte[] {(byte) 1, (byte) 2})
+                        .setPropertyLong("longKey1", 1L, 2L)
+                        .setPropertyDouble("doubleKey1", 1.0, 2.0)
+                        .setPropertyBoolean("booleanKey1", true, false)
+                        .setPropertyDocument("documentKey1", nestedDocValue)
+                        .build();
+
+        String documentString = document.toString();
+
+        String expectedString =
+                "{\n"
+                        + "  namespace: \"namespace\",\n"
+                        + "  id: \"id1\",\n"
+                        + "  score: 1,\n"
+                        + "  schemaType: \"schemaType1\",\n"
+                        + "  creationTimestampMillis: 1,\n"
+                        + "  timeToLiveMillis: 1,\n"
+                        + "  properties: {\n"
+                        + "    \"booleanKey1\": [true, false],\n"
+                        + "    \"bytesKey1\": [[1, 2]],\n"
+                        + "    \"documentKey1\": [\n"
+                        + "      {\n"
+                        + "        namespace: \"namespace\",\n"
+                        + "        id: \"id2\",\n"
+                        + "        score: 1,\n"
+                        + "        schemaType: \"schemaType2\",\n"
+                        + "        creationTimestampMillis: 1,\n"
+                        + "        timeToLiveMillis: 1,\n"
+                        + "        properties: {\n"
+                        + "          \"stringKey1\": [\"val1\", \"val2\"]\n"
+                        + "        }\n"
+                        + "      }\n"
+                        + "    ],\n"
+                        + "    \"doubleKey1\": [1.0, 2.0],\n"
+                        + "    \"longKey1\": [1, 2],\n"
+                        + "    \"stringKey1\": [\"val1\", \"val2\"]\n"
+                        + "  }\n"
+                        + "}";
+
+        assertThat(documentString).isEqualTo(expectedString);
     }
 
     @Test
@@ -876,4 +916,53 @@
         assertThat(doc.getPropertyBytes("propDocument[0].propBytes[0]"))
                 .isEqualTo(new byte[] {3, 4});
     }
+
+    @Test
+    public void testDocumentGetPropertyNamesSingleLevel() {
+        GenericDocument document =
+                new GenericDocument.Builder<>("namespace", "id1", "schemaType1")
+                        .setCreationTimestampMillis(5L)
+                        .setScore(1)
+                        .setTtlMillis(1L)
+                        .setPropertyLong("longKey1", 1L)
+                        .setPropertyDouble("doubleKey1", 1.0)
+                        .setPropertyBoolean("booleanKey1", true)
+                        .setPropertyString("stringKey1", "test-value1")
+                        .setPropertyBytes("byteKey1", sByteArray1)
+                        .build();
+        assertThat(document.getPropertyNames())
+                .containsExactly("longKey1", "doubleKey1", "booleanKey1", "stringKey1", "byteKey1");
+    }
+
+    @Test
+    public void testDocumentGetPropertyNamesMultiLevel() {
+        GenericDocument innerDoc0 =
+                new GenericDocument.Builder<>("namespace", "id2", "schema2")
+                        .setPropertyString("propString", "Goodbye", "Hello")
+                        .setPropertyString("propStringTwo", "Fee", "Fi")
+                        .setPropertyLong("propInts", 3, 1, 4)
+                        .build();
+        GenericDocument innerDoc1 =
+                new GenericDocument.Builder<>("namespace", "id3", "schema2")
+                        .setPropertyString("propString", "Aloha")
+                        .setPropertyLong("propInts", 7, 5, 6)
+                        .setPropertyLong("propIntsTwo", 8, 6)
+                        .build();
+        GenericDocument document =
+                new GenericDocument.Builder<>("namespace", "id1", "schemaType1")
+                        .setCreationTimestampMillis(5L)
+                        .setScore(1)
+                        .setTtlMillis(1L)
+                        .setPropertyString("stringKey1", "test-value1")
+                        .setPropertyDocument("docKey1", innerDoc0, innerDoc1)
+                        .build();
+        assertThat(document.getPropertyNames()).containsExactly("stringKey1", "docKey1");
+
+        GenericDocument[] documents = document.getPropertyDocumentArray("docKey1");
+        assertThat(documents).asList().containsExactly(innerDoc0, innerDoc1).inOrder();
+        assertThat(documents[0].getPropertyNames())
+                .containsExactly("propString", "propStringTwo", "propInts");
+        assertThat(documents[1].getPropertyNames())
+                .containsExactly("propString", "propInts", "propIntsTwo");
+    }
 }
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/GetByDocumentIdRequestCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/GetByDocumentIdRequestCtsTest.java
new file mode 100644
index 0000000..ba81ca9
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/GetByDocumentIdRequestCtsTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.GetByDocumentIdRequest;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class GetByDocumentIdRequestCtsTest {
+    @Test
+    public void testBuildRequest() {
+        List<String> expectedPropertyPaths1 = Arrays.asList("path1", "path2");
+        List<String> expectedPropertyPaths2 = Arrays.asList("path3", "path4");
+        GetByDocumentIdRequest getByDocumentIdRequest =
+                new GetByDocumentIdRequest.Builder("namespace")
+                        .addIds("uri1", "uri2")
+                        .addIds(Arrays.asList("uri3", "uri4"))
+                        .addProjection("schemaType1", expectedPropertyPaths1)
+                        .addProjection("schemaType2", expectedPropertyPaths2)
+                        .build();
+
+        assertThat(getByDocumentIdRequest.getIds()).containsExactly("uri1", "uri2", "uri3", "uri4");
+        assertThat(getByDocumentIdRequest.getNamespace()).isEqualTo("namespace");
+        assertThat(getByDocumentIdRequest.getProjections())
+                .containsExactly(
+                        "schemaType1",
+                        expectedPropertyPaths1,
+                        "schemaType2",
+                        expectedPropertyPaths2);
+    }
+}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/GlobalSearchSessionCtsTestBase.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java
similarity index 99%
rename from tests/appsearch/src/com/android/cts/appsearch/external/GlobalSearchSessionCtsTestBase.java
rename to tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java
index d929a9a..281a98e 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/GlobalSearchSessionCtsTestBase.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.app.appsearch.cts;
+package android.app.appsearch.cts.app;
 
 import static com.android.server.appsearch.testing.AppSearchTestUtils.checkIsBatchResultSuccess;
 import static com.android.server.appsearch.testing.AppSearchTestUtils.convertSearchResultsToDocuments;
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/PackageIdentifierCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/PackageIdentifierCtsTest.java
new file mode 100644
index 0000000..f81e21e
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/PackageIdentifierCtsTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.PackageIdentifier;
+
+import org.junit.Test;
+
+public class PackageIdentifierCtsTest {
+    @Test
+    public void testGetters() {
+        PackageIdentifier packageIdentifier =
+                new PackageIdentifier("com.packageName", /*sha256Certificate=*/ new byte[] {100});
+        assertThat(packageIdentifier.getPackageName()).isEqualTo("com.packageName");
+        assertThat(packageIdentifier.getSha256Certificate()).isEqualTo(new byte[] {100});
+    }
+}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/RemoveByDocumentIdRequestCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/RemoveByDocumentIdRequestCtsTest.java
new file mode 100644
index 0000000..c33cac0
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/RemoveByDocumentIdRequestCtsTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.RemoveByDocumentIdRequest;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+public class RemoveByDocumentIdRequestCtsTest {
+    @Test
+    public void testBuildRequest() {
+        RemoveByDocumentIdRequest request =
+                new RemoveByDocumentIdRequest.Builder("namespace")
+                        .addIds("uri1", "uri2")
+                        .addIds(Arrays.asList("uri3"))
+                        .build();
+
+        assertThat(request.getNamespace()).isEqualTo("namespace");
+        assertThat(request.getIds()).containsExactly("uri1", "uri2", "uri3").inOrder();
+    }
+}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/ReportSystemUsageRequestCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/ReportSystemUsageRequestCtsTest.java
new file mode 100644
index 0000000..4fbfb1d
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/ReportSystemUsageRequestCtsTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.ReportSystemUsageRequest;
+
+import org.junit.Test;
+
+public class ReportSystemUsageRequestCtsTest {
+    @Test
+    public void testGettersAndSetters() {
+        ReportSystemUsageRequest request =
+                new ReportSystemUsageRequest.Builder("package1", "database1", "namespace1", "id1")
+                        .setUsageTimestampMillis(32)
+                        .build();
+        assertThat(request.getPackageName()).isEqualTo("package1");
+        assertThat(request.getDatabaseName()).isEqualTo("database1");
+        assertThat(request.getNamespace()).isEqualTo("namespace1");
+        assertThat(request.getDocumentId()).isEqualTo("id1");
+        assertThat(request.getUsageTimestampMillis()).isEqualTo(32);
+    }
+
+    @Test
+    public void testUsageTimestampDefault() {
+        long startTs = System.currentTimeMillis();
+        ReportSystemUsageRequest request =
+                new ReportSystemUsageRequest.Builder("package1", "database1", "namespace1", "id1")
+                        .build();
+        assertThat(request.getUsageTimestampMillis()).isAtLeast(startTs);
+    }
+}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/ReportUsageRequestCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/ReportUsageRequestCtsTest.java
new file mode 100644
index 0000000..189ebb0
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/ReportUsageRequestCtsTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.ReportUsageRequest;
+
+import org.junit.Test;
+
+public class ReportUsageRequestCtsTest {
+    @Test
+    public void testGettersAndSetters() {
+        ReportUsageRequest request =
+                new ReportUsageRequest.Builder("namespace1", "id1")
+                        .setUsageTimestampMillis(32)
+                        .build();
+        assertThat(request.getNamespace()).isEqualTo("namespace1");
+        assertThat(request.getDocumentId()).isEqualTo("id1");
+        assertThat(request.getUsageTimestampMillis()).isEqualTo(32);
+    }
+
+    @Test
+    public void testUsageTimestampDefault() {
+        long startTs = System.currentTimeMillis();
+        ReportUsageRequest request = new ReportUsageRequest.Builder("namespace1", "id1").build();
+        assertThat(request.getUsageTimestampMillis()).isAtLeast(startTs);
+    }
+}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/SearchResultCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/SearchResultCtsTest.java
new file mode 100644
index 0000000..588210b
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/SearchResultCtsTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.SearchResult;
+
+import com.android.server.appsearch.testing.AppSearchEmail;
+
+import org.junit.Test;
+
+public class SearchResultCtsTest {
+
+    @Test
+    public void testBuildSearchResult() {
+        SearchResult.MatchRange exactMatchRange = new SearchResult.MatchRange(3, 8);
+        SearchResult.MatchRange snippetMatchRange = new SearchResult.MatchRange(1, 10);
+        SearchResult.MatchInfo matchInfo =
+                new SearchResult.MatchInfo.Builder("body")
+                        .setExactMatchRange(exactMatchRange)
+                        .setSnippetRange(snippetMatchRange)
+                        .build();
+
+        AppSearchEmail email =
+                new AppSearchEmail.Builder("namespace1", "id1").setBody("Hello World.").build();
+        SearchResult searchResult =
+                new SearchResult.Builder("packageName", "databaseName")
+                        .setGenericDocument(email)
+                        .addMatchInfo(matchInfo)
+                        .setRankingSignal(2.9)
+                        .build();
+
+        assertThat(searchResult.getPackageName()).isEqualTo("packageName");
+        assertThat(searchResult.getDatabaseName()).isEqualTo("databaseName");
+        assertThat(searchResult.getRankingSignal()).isEqualTo(2.9);
+        assertThat(searchResult.getGenericDocument()).isEqualTo(email);
+        assertThat(searchResult.getMatchInfos()).hasSize(1);
+        SearchResult.MatchInfo actualMatchInfo = searchResult.getMatchInfos().get(0);
+        assertThat(actualMatchInfo.getPropertyPath()).isEqualTo("body");
+        assertThat(actualMatchInfo.getExactMatchRange()).isEqualTo(exactMatchRange);
+        assertThat(actualMatchInfo.getSnippetRange()).isEqualTo(snippetMatchRange);
+        assertThat(actualMatchInfo.getExactMatch()).isEqualTo("lo Wo");
+        assertThat(actualMatchInfo.getSnippet()).isEqualTo("ello Worl");
+        assertThat(actualMatchInfo.getFullText()).isEqualTo("Hello World.");
+    }
+
+    @Test
+    public void testMatchRange() {
+        SearchResult.MatchRange matchRange = new SearchResult.MatchRange(13, 47);
+        assertThat(matchRange.getStart()).isEqualTo(13);
+        assertThat(matchRange.getEnd()).isEqualTo(47);
+    }
+}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/SearchSpecCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/SearchSpecCtsTest.java
new file mode 100644
index 0000000..c1a9f6c
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/SearchSpecCtsTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.app;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.SearchSpec;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+
+public class SearchSpecCtsTest {
+    @Test
+    public void testBuildSearchSpecWithoutTermMatch() {
+        SearchSpec searchSpec = new SearchSpec.Builder().addFilterSchemas("testSchemaType").build();
+        assertThat(searchSpec.getTermMatch()).isEqualTo(SearchSpec.TERM_MATCH_PREFIX);
+    }
+
+    @Test
+    public void testBuildSearchSpec() {
+        List<String> expectedPropertyPaths1 = ImmutableList.of("path1", "path2");
+        List<String> expectedPropertyPaths2 = ImmutableList.of("path3", "path4");
+        SearchSpec searchSpec =
+                new SearchSpec.Builder()
+                        .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+                        .addFilterNamespaces("namespace1", "namespace2")
+                        .addFilterNamespaces(ImmutableList.of("namespace3"))
+                        .addFilterSchemas("schemaTypes1", "schemaTypes2")
+                        .addFilterSchemas(ImmutableList.of("schemaTypes3"))
+                        .addFilterPackageNames("package1", "package2")
+                        .addFilterPackageNames(ImmutableList.of("package3"))
+                        .setSnippetCount(5)
+                        .setSnippetCountPerProperty(10)
+                        .setMaxSnippetSize(15)
+                        .setResultCountPerPage(42)
+                        .setOrder(SearchSpec.ORDER_ASCENDING)
+                        .setRankingStrategy(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE)
+                        .setResultGrouping(
+                                SearchSpec.GROUPING_TYPE_PER_NAMESPACE
+                                        | SearchSpec.GROUPING_TYPE_PER_PACKAGE,
+                                /*limit=*/ 37)
+                        .addProjection("schemaType1", expectedPropertyPaths1)
+                        .addProjection("schemaType2", expectedPropertyPaths2)
+                        .build();
+
+        assertThat(searchSpec.getTermMatch()).isEqualTo(SearchSpec.TERM_MATCH_PREFIX);
+        assertThat(searchSpec.getFilterNamespaces())
+                .containsExactly("namespace1", "namespace2", "namespace3")
+                .inOrder();
+        assertThat(searchSpec.getFilterSchemas())
+                .containsExactly("schemaTypes1", "schemaTypes2", "schemaTypes3")
+                .inOrder();
+        assertThat(searchSpec.getFilterPackageNames())
+                .containsExactly("package1", "package2", "package3")
+                .inOrder();
+        assertThat(searchSpec.getSnippetCount()).isEqualTo(5);
+        assertThat(searchSpec.getSnippetCountPerProperty()).isEqualTo(10);
+        assertThat(searchSpec.getMaxSnippetSize()).isEqualTo(15);
+        assertThat(searchSpec.getResultCountPerPage()).isEqualTo(42);
+        assertThat(searchSpec.getOrder()).isEqualTo(SearchSpec.ORDER_ASCENDING);
+        assertThat(searchSpec.getRankingStrategy())
+                .isEqualTo(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE);
+        assertThat(searchSpec.getResultGroupingTypeFlags())
+                .isEqualTo(
+                        SearchSpec.GROUPING_TYPE_PER_NAMESPACE
+                                | SearchSpec.GROUPING_TYPE_PER_PACKAGE);
+        assertThat(searchSpec.getProjections())
+                .containsExactly(
+                        "schemaType1",
+                        expectedPropertyPaths1,
+                        "schemaType2",
+                        expectedPropertyPaths2);
+        assertThat(searchSpec.getResultGroupingLimit()).isEqualTo(37);
+    }
+
+    @Test
+    public void testGetProjectionTypePropertyMasks() {
+        SearchSpec searchSpec =
+                new SearchSpec.Builder()
+                        .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+                        .addProjection("TypeA", ImmutableList.of("field1", "field2.subfield2"))
+                        .addProjection("TypeB", ImmutableList.of("field7"))
+                        .addProjection("TypeC", ImmutableList.of())
+                        .build();
+
+        Map<String, List<String>> typePropertyPathMap = searchSpec.getProjections();
+        assertThat(typePropertyPathMap.keySet()).containsExactly("TypeA", "TypeB", "TypeC");
+        assertThat(typePropertyPathMap.get("TypeA")).containsExactly("field1", "field2.subfield2");
+        assertThat(typePropertyPathMap.get("TypeB")).containsExactly("field7");
+        assertThat(typePropertyPathMap.get("TypeC")).isEmpty();
+    }
+}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/SetSchemaRequestCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/SetSchemaRequestCtsTest.java
new file mode 100644
index 0000000..3e37b2b
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/SetSchemaRequestCtsTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchSchema;
+import android.app.appsearch.GenericDocument;
+import android.app.appsearch.Migrator;
+import android.app.appsearch.PackageIdentifier;
+import android.app.appsearch.SetSchemaRequest;
+import android.util.ArrayMap;
+
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+public class SetSchemaRequestCtsTest {
+    @Test
+    public void testBuildSetSchemaRequest() {
+        AppSearchSchema.StringPropertyConfig prop1 =
+                new AppSearchSchema.StringPropertyConfig.Builder("prop1")
+                        .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                        .setIndexingType(
+                                AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+                        .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+                        .build();
+        AppSearchSchema schema1 = new AppSearchSchema.Builder("type1").addProperty(prop1).build();
+        AppSearchSchema schema2 = new AppSearchSchema.Builder("type2").addProperty(prop1).build();
+
+        PackageIdentifier packageIdentifier =
+                new PackageIdentifier("com.package.foo", new byte[] {100});
+
+        SetSchemaRequest request =
+                new SetSchemaRequest.Builder()
+                        .addSchemas(schema1, schema2)
+                        .setSchemaTypeDisplayedBySystem("type2", /*displayed=*/ false)
+                        .setSchemaTypeVisibilityForPackage(
+                                "type1", /*visible=*/ true, packageIdentifier)
+                        .build();
+
+        assertThat(request.getSchemas()).containsExactly(schema1, schema2);
+        assertThat(request.getSchemasNotDisplayedBySystem()).containsExactly("type2");
+
+        Map<String, Set<PackageIdentifier>> expectedVisibleToPackagesMap = new ArrayMap<>();
+        expectedVisibleToPackagesMap.put("type1", Collections.singleton(packageIdentifier));
+        assertThat(request.getSchemasVisibleToPackages())
+                .containsExactlyEntriesIn(expectedVisibleToPackagesMap);
+    }
+
+    @Test
+    public void testSetSchemaRequestTypeChanges() {
+        AppSearchSchema.StringPropertyConfig requiredProp =
+                new AppSearchSchema.StringPropertyConfig.Builder("prop1")
+                        .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+                        .setIndexingType(
+                                AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+                        .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+                        .build();
+        AppSearchSchema schema1 =
+                new AppSearchSchema.Builder("type1").addProperty(requiredProp).build();
+        AppSearchSchema schema2 =
+                new AppSearchSchema.Builder("type2").addProperty(requiredProp).build();
+
+        Migrator migrator =
+                new Migrator() {
+                    @Override
+                    public boolean shouldMigrate(int currentVersion, int finalVersion) {
+                        return true;
+                    }
+
+                    @NonNull
+                    @Override
+                    public GenericDocument onUpgrade(
+                            int currentVersion,
+                            int finalVersion,
+                            @NonNull GenericDocument document) {
+                        return document;
+                    }
+
+                    @NonNull
+                    @Override
+                    public GenericDocument onDowngrade(
+                            int currentVersion,
+                            int finalVersion,
+                            @NonNull GenericDocument document) {
+                        return document;
+                    }
+                };
+
+        SetSchemaRequest request =
+                new SetSchemaRequest.Builder()
+                        .addSchemas(schema1, schema2)
+                        .setForceOverride(/*forceOverride=*/ true)
+                        .setMigrator("type2", migrator)
+                        .build();
+
+        assertThat(request.isForceOverride()).isTrue();
+        Map<String, Migrator> expectedMigratorMap = new ArrayMap<>();
+        expectedMigratorMap.put("type2", migrator);
+        assertThat(request.getMigrators()).containsExactlyEntriesIn(expectedMigratorMap);
+    }
+}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/SetSchemaResponseCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/SetSchemaResponseCtsTest.java
new file mode 100644
index 0000000..ab28a08
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/SetSchemaResponseCtsTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.SetSchemaResponse;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+public class SetSchemaResponseCtsTest {
+    @Test
+    public void testRebuild() {
+        SetSchemaResponse.MigrationFailure failure1 =
+                new SetSchemaResponse.MigrationFailure(
+                        "namespace",
+                        "failure1",
+                        "schemaType",
+                        AppSearchResult.newFailedResult(
+                                AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
+        SetSchemaResponse.MigrationFailure failure2 =
+                new SetSchemaResponse.MigrationFailure(
+                        "namespace",
+                        "failure2",
+                        "schemaType",
+                        AppSearchResult.newFailedResult(
+                                AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
+
+        SetSchemaResponse.Builder builder =
+                new SetSchemaResponse.Builder()
+                        .addDeletedType("delete1")
+                        .addIncompatibleType("incompatible1")
+                        .addMigratedType("migrated1")
+                        .addMigrationFailure(failure1);
+        SetSchemaResponse original = builder.build();
+        assertThat(original.getDeletedTypes()).containsExactly("delete1");
+        assertThat(original.getIncompatibleTypes()).containsExactly("incompatible1");
+        assertThat(original.getMigratedTypes()).containsExactly("migrated1");
+        assertThat(original.getMigrationFailures()).containsExactly(failure1);
+
+        SetSchemaResponse rebuild =
+                builder.addDeletedType("delete2")
+                        .addIncompatibleType("incompatible2")
+                        .addMigratedType("migrated2")
+                        .addMigrationFailure(failure2)
+                        .build();
+
+        // rebuild won't effect the original object
+        assertThat(original.getDeletedTypes()).containsExactly("delete1");
+        assertThat(original.getIncompatibleTypes()).containsExactly("incompatible1");
+        assertThat(original.getMigratedTypes()).containsExactly("migrated1");
+        assertThat(original.getMigrationFailures()).containsExactly(failure1);
+
+        assertThat(rebuild.getDeletedTypes()).containsExactly("delete1", "delete2");
+        assertThat(rebuild.getIncompatibleTypes())
+                .containsExactly("incompatible1", "incompatible2");
+        assertThat(rebuild.getMigratedTypes()).containsExactly("migrated1", "migrated2");
+        assertThat(rebuild.getMigrationFailures()).containsExactly(failure1, failure2);
+    }
+
+    @Test
+    public void testPluralAdds() {
+        SetSchemaResponse.MigrationFailure failure1 =
+                new SetSchemaResponse.MigrationFailure(
+                        "namespace",
+                        "failure1",
+                        "schemaType",
+                        AppSearchResult.newFailedResult(
+                                AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
+
+        SetSchemaResponse.Builder builder =
+                new SetSchemaResponse.Builder()
+                        .addDeletedTypes(Arrays.asList("delete1"))
+                        .addIncompatibleTypes(Arrays.asList("incompatible1"))
+                        .addMigratedTypes(Arrays.asList("migrated1"))
+                        .addMigrationFailures(Arrays.asList(failure1));
+        SetSchemaResponse singleEntries = builder.build();
+        assertThat(singleEntries.getDeletedTypes()).containsExactly("delete1");
+        assertThat(singleEntries.getIncompatibleTypes()).containsExactly("incompatible1");
+        assertThat(singleEntries.getMigratedTypes()).containsExactly("migrated1");
+        assertThat(singleEntries.getMigrationFailures()).containsExactly(failure1);
+
+        SetSchemaResponse.MigrationFailure failure2 =
+                new SetSchemaResponse.MigrationFailure(
+                        "namespace",
+                        "failure2",
+                        "schemaType",
+                        AppSearchResult.newFailedResult(
+                                AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
+        SetSchemaResponse multiEntries =
+                builder.addDeletedTypes(Arrays.asList("delete2", "deleted3", "deleted4"))
+                        .addIncompatibleTypes(Arrays.asList("incompatible2"))
+                        .addMigratedTypes(Arrays.asList("migrated2", "migrate3"))
+                        .addMigrationFailures(Arrays.asList(failure2))
+                        .build();
+
+        assertThat(multiEntries.getDeletedTypes())
+                .containsExactly("delete1", "delete2", "deleted3", "deleted4");
+        assertThat(multiEntries.getIncompatibleTypes())
+                .containsExactly("incompatible1", "incompatible2");
+        assertThat(multiEntries.getMigratedTypes())
+                .containsExactly("migrated1", "migrated2", "migrate3");
+        assertThat(multiEntries.getMigrationFailures()).containsExactly(failure1, failure2);
+    }
+}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/StorageInfoCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/StorageInfoCtsTest.java
new file mode 100644
index 0000000..ac89131
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/StorageInfoCtsTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.StorageInfo;
+
+import org.junit.Test;
+
+public class StorageInfoCtsTest {
+
+    @Test
+    public void testBuildStorageInfo() {
+        StorageInfo storageInfo =
+                new StorageInfo.Builder()
+                        .setAliveDocumentsCount(10)
+                        .setSizeBytes(1L)
+                        .setAliveNamespacesCount(10)
+                        .build();
+
+        assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(10);
+        assertThat(storageInfo.getSizeBytes()).isEqualTo(1L);
+        assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(10);
+    }
+
+    @Test
+    public void testBuildStorageInfo_withDefaults() {
+        StorageInfo storageInfo = new StorageInfo.Builder().build();
+
+        assertThat(storageInfo.getAliveDocumentsCount()).isEqualTo(0);
+        assertThat(storageInfo.getSizeBytes()).isEqualTo(0L);
+        assertThat(storageInfo.getAliveNamespacesCount()).isEqualTo(0);
+    }
+}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/customer/CustomerDocumentTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/customer/CustomerDocumentTest.java
similarity index 98%
rename from tests/appsearch/src/com/android/cts/appsearch/external/customer/CustomerDocumentTest.java
rename to tests/appsearch/src/com/android/cts/appsearch/external/app/customer/CustomerDocumentTest.java
index 240afac..36d672c 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/customer/CustomerDocumentTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/customer/CustomerDocumentTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.app.appsearch.cts.customer;
+package android.app.appsearch.cts.app.customer;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/exceptions/AppSearchExceptionCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/exceptions/AppSearchExceptionCtsTest.java
new file mode 100644
index 0000000..470cd46
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/exceptions/AppSearchExceptionCtsTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.exceptions;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.exceptions.AppSearchException;
+
+import org.junit.Test;
+
+public class AppSearchExceptionCtsTest {
+    @Test
+    public void testNoMessageException() {
+        AppSearchException e = new AppSearchException(AppSearchResult.RESULT_IO_ERROR);
+        assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_IO_ERROR);
+
+        AppSearchResult<?> result = e.toAppSearchResult();
+        assertThat(result.isSuccess()).isFalse();
+        assertThat(result.getResultCode()).isEqualTo(AppSearchResult.RESULT_IO_ERROR);
+        assertThat(result.getErrorMessage()).isNull();
+    }
+
+    @Test
+    public void testExceptionWithMessage() {
+        AppSearchException e = new AppSearchException(AppSearchResult.RESULT_NOT_FOUND, "ERROR!");
+        assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+
+        AppSearchResult<?> result = e.toAppSearchResult();
+        assertThat(result.isSuccess()).isFalse();
+        assertThat(result.getResultCode()).isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+        assertThat(result.getErrorMessage()).isEqualTo("ERROR!");
+    }
+
+    @Test
+    public void testExceptionWithThrowable() {
+        IllegalArgumentException throwable = new IllegalArgumentException("You can't do that!");
+        AppSearchException e =
+                new AppSearchException(
+                        AppSearchResult.RESULT_INVALID_ARGUMENT, "ERROR!", throwable);
+        assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_INVALID_ARGUMENT);
+        assertThat(e.getCause()).isEqualTo(throwable);
+
+        AppSearchResult<?> result = e.toAppSearchResult();
+        assertThat(result.isSuccess()).isFalse();
+        assertThat(result.getResultCode()).isEqualTo(AppSearchResult.RESULT_INVALID_ARGUMENT);
+        assertThat(result.getErrorMessage()).isEqualTo("ERROR!");
+    }
+}
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraExtensionSessionTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraExtensionSessionTest.java
index 55bcd28..88bda03 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraExtensionSessionTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraExtensionSessionTest.java
@@ -26,6 +26,10 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
 import com.android.ex.camera2.blocking.BlockingSessionCallback;
 import com.android.ex.camera2.blocking.BlockingExtensionSessionCallback;
 import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
@@ -47,6 +51,8 @@
 import android.media.ExifInterface;
 import android.media.Image;
 import android.media.ImageReader;
+import android.os.SystemClock;
+import android.util.Range;
 import android.util.Size;
 
 import static android.hardware.camera2.cts.CameraTestUtils.*;
@@ -56,6 +62,7 @@
 import android.view.Surface;
 import android.view.TextureView;
 
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
 
 import org.junit.Rule;
@@ -79,6 +86,8 @@
     private SurfaceTexture mSurfaceTexture = null;
     private Camera2AndroidTestRule mTestRule = null;
 
+    private DeviceReportLog mReportLog;
+
     @Override
     public void setUp() throws Exception {
         super.setUp();
@@ -466,7 +475,8 @@
     }
 
     // Test case for multi-frame only capture on all supported extensions and expected state
-    // callbacks. Verify still frame output.
+    // callbacks. Verify still frame output, measure the average capture latency and if possible
+    // ensure that the value is within the reported range.
     @Test
     public void testMultiFrameCapture() throws Exception {
         final int IMAGE_COUNT = 10;
@@ -510,6 +520,12 @@
                             new ExtensionSessionConfiguration(extension, outputConfigs,
                                     new HandlerExecutor(mTestRule.getHandler()),
                                     sessionListener);
+                    String streamName = "test_extension_capture";
+                    mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
+                    mReportLog.addValue("camera_id", id, ResultType.NEUTRAL, ResultUnit.NONE);
+                    mReportLog.addValue("extension_id", extension, ResultType.NEUTRAL,
+                            ResultUnit.NONE);
+                    double[] captureTimes = new double[IMAGE_COUNT];
 
                     try {
                         mTestRule.openDevice(id);
@@ -534,11 +550,13 @@
                                         jpegOrientation);
                             }
                             CaptureRequest request = captureBuilder.build();
+                            long startTimeMs = SystemClock.elapsedRealtime();
                             int sequenceId = extensionSession.capture(request,
                                     new HandlerExecutor(mTestRule.getHandler()), captureCallback);
 
                             Image img =
                                     imageListener.getImage(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS);
+                            captureTimes[i] = SystemClock.elapsedRealtime() - startTimeMs;
                             if (captureFormat == ImageFormat.JPEG) {
                                 verifyJpegOrientation(img, maxSize, jpegOrientation);
                             } else {
@@ -557,12 +575,32 @@
                                     .onCaptureSequenceCompleted(extensionSession, sequenceId);
                         }
 
+                        long avgCaptureLatency = (long) Stat.getAverage(captureTimes);
+                        String resultFormat = "avg_latency size: " + maxSize.toString() +
+                                " image format: " + captureFormat;
+                        mReportLog.addValue(resultFormat, avgCaptureLatency,
+                                ResultType.LOWER_BETTER, ResultUnit.MS);
+
                         verify(captureCallback, times(0))
                                 .onCaptureSequenceAborted(any(CameraExtensionSession.class),
                                         anyInt());
                         verify(captureCallback, times(0))
                                 .onCaptureFailed(any(CameraExtensionSession.class),
                                         any(CaptureRequest.class));
+                        Range<Long> latencyRange =
+                                extensionChars.getEstimatedCaptureLatencyRangeMillis(extension,
+                                        maxSize, captureFormat);
+                        if (latencyRange != null) {
+                            String msg = String.format("Camera [%s]: The measured average "
+                                            + "capture latency of %d ms. for extension type %d  "
+                                            + "with image format: %d and size: %dx%d must be "
+                                            + "within the advertised range of [%d, %d] ms.",
+                                    id, avgCaptureLatency, extension, captureFormat,
+                                    maxSize.getWidth(), maxSize.getHeight(),
+                                    latencyRange.getLower(), latencyRange.getUpper());
+                            assertTrue(msg, latencyRange.contains(avgCaptureLatency));
+                        }
+
 
                         extensionSession.close();
 
@@ -572,6 +610,7 @@
                     } finally {
                         mTestRule.closeDevice(id);
                         extensionImageReader.close();
+                        mReportLog.submit(InstrumentationRegistry.getInstrumentation());
                     }
                 }
             }
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index a6b6bd1..f7953b0 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -25,6 +25,7 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraCharacteristics.Key;
 import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraExtensionCharacteristics;
 import android.hardware.camera2.CameraManager;
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureRequest;
@@ -2645,6 +2646,17 @@
                         jpegSize.getWidth() >= FULLHD.getWidth() &&
                         jpegSize.getHeight() >= FULLHD.getHeight());
             }
+
+            // H-1-9
+            CameraExtensionCharacteristics extensionChars =
+                    mCameraManager.getCameraExtensionCharacteristics(cameraId);
+            List<Integer> supportedExtensions = extensionChars.getSupportedExtensions();
+            mCollector.expectTrue(
+                    "Primary rear/front camera must support the HDR camera2 extension",
+                    supportedExtensions.contains(CameraExtensionCharacteristics.EXTENSION_HDR));
+            mCollector.expectTrue(
+                    "Primary rear/front camera must support the NIGHT camera2 extension",
+                    supportedExtensions.contains(CameraExtensionCharacteristics.EXTENSION_NIGHT));
         }
         mCollector.expectTrue("There must be a primary rear camera for S performance class.",
                 hasPrimaryRear);
diff --git a/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java b/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java
index dc34087..c37a76c 100644
--- a/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java
@@ -167,16 +167,20 @@
         }
 
         private Object mPictureSignal = new Object();
+        private boolean mGotPicture = false;
         private byte[] mPictureData = null;
 
         public byte[] waitForPicture() {
+            Log.i(TAG, "waitForPicture called");
             synchronized(mPictureSignal) {
                 boolean waited = false;
                 while (!waited) {
                     try {
                         mPictureSignal.wait(WAIT_FOR_PICTURE_TIMEOUT_MS);
                         waited = true;
+                        Log.i(TAG, "waitForPicture returned with mGotPicture = " + mGotPicture);
                     } catch (InterruptedException e) {
+                        Log.e(TAG, "waitForPicture gets interrupted exception!");
                     }
                 }
                 return mPictureData;
@@ -184,8 +188,10 @@
         }
 
         public void onPictureTaken(byte[] data, Camera camera) {
+            Log.i(TAG, "onPictureTaken called");
             synchronized(mPictureSignal) {
                 mPictureData = data;
+                mGotPicture = true;
                 mPictureSignal.notifyAll();
             }
         }
diff --git a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
index 48f6d32..66c5473 100644
--- a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -16,6 +16,8 @@
 
 package android.hardware.camera2.cts;
 
+import static android.hardware.camera2.cts.CameraTestUtils.REPORT_LOG_NAME;
+
 import static com.android.ex.camera2.blocking.BlockingSessionCallback.SESSION_CLOSED;
 
 import static org.junit.Assert.assertNotNull;
@@ -78,7 +80,6 @@
 @RunWith(JUnit4.class)
 public class PerformanceTest {
     private static final String TAG = "PerformanceTest";
-    private static final String REPORT_LOG_NAME = "CtsCameraTestCases";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     private static final int NUM_TEST_LOOPS = 10;
     private static final int NUM_MAX_IMAGES = 4;
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 7a91b1c..98f5ec0 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -128,6 +128,7 @@
     public static final int MAX_READER_IMAGES = 5;
 
     public static final String OFFLINE_CAMERA_ID = "offline_camera_id";
+    public static final String REPORT_LOG_NAME = "CtsCameraTestCases";
 
     private static final int EXIF_DATETIME_LENGTH = 19;
     private static final int EXIF_DATETIME_ERROR_MARGIN_SEC = 60;
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
index f01c382..b8df9f1 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
@@ -47,8 +47,8 @@
 import com.android.bedstead.harrier.annotations.EnsureHasNoWorkProfile;
 import com.android.bedstead.harrier.annotations.EnsureHasPermission;
 import com.android.bedstead.harrier.annotations.Postsubmit;
-import com.android.bedstead.harrier.annotations.RequireDoesNotHaveFeatures;
-import com.android.bedstead.harrier.annotations.RequireFeatures;
+import com.android.bedstead.harrier.annotations.RequireDoesNotHaveFeature;
+import com.android.bedstead.harrier.annotations.RequireFeature;
 import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
 import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.packages.Package;
@@ -111,10 +111,8 @@
 
     @RequireRunOnPrimaryUser
     @EnsureHasNoWorkProfile
-    @RequireFeatures({
-            PackageManager.FEATURE_DEVICE_ADMIN,
-            PackageManager.FEATURE_MANAGED_USERS
-    })
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @Test
     @Postsubmit(reason="b/181207615 flaky")
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
@@ -135,10 +133,8 @@
 
     @RequireRunOnPrimaryUser
     @EnsureHasNoWorkProfile
-    @RequireFeatures({
-            PackageManager.FEATURE_DEVICE_ADMIN,
-            PackageManager.FEATURE_MANAGED_USERS
-    })
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @Test
     @Postsubmit(reason="b/181207615 flaky")
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
@@ -159,10 +155,8 @@
 
     @RequireRunOnPrimaryUser
     @EnsureHasNoWorkProfile
-    @RequireFeatures({
-            PackageManager.FEATURE_DEVICE_ADMIN,
-            PackageManager.FEATURE_MANAGED_USERS
-    })
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @Test
     @Postsubmit(reason="b/181207615 flaky")
     @EnsureHasPermission({MANAGE_PROFILE_AND_DEVICE_OWNERS, INTERACT_ACROSS_USERS_FULL})
@@ -185,10 +179,8 @@
 
     @RequireRunOnPrimaryUser
     @EnsureHasNoWorkProfile
-    @RequireFeatures({
-            PackageManager.FEATURE_DEVICE_ADMIN,
-            PackageManager.FEATURE_MANAGED_USERS
-    })
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @Test
     @Postsubmit(reason="b/181207615 flaky")
     @EnsureHasPermission({MANAGE_PROFILE_AND_DEVICE_OWNERS, INTERACT_ACROSS_USERS})
@@ -210,10 +202,8 @@
 
     @RequireRunOnPrimaryUser
     @EnsureHasNoWorkProfile
-    @RequireFeatures({
-            PackageManager.FEATURE_DEVICE_ADMIN,
-            PackageManager.FEATURE_MANAGED_USERS
-    })
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @Test
     @Postsubmit(reason="new test")
     @Ignore
@@ -238,10 +228,8 @@
 
     @RequireRunOnPrimaryUser
     @EnsureHasNoWorkProfile
-    @RequireFeatures({
-            PackageManager.FEATURE_DEVICE_ADMIN,
-            PackageManager.FEATURE_MANAGED_USERS
-    })
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @Test
     @Postsubmit(reason="new test")
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
@@ -266,10 +254,8 @@
 
     @RequireRunOnPrimaryUser
     @EnsureHasNoWorkProfile
-    @RequireFeatures({
-            PackageManager.FEATURE_DEVICE_ADMIN,
-            PackageManager.FEATURE_MANAGED_USERS
-    })
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @Test
     @Ignore
     @Postsubmit(reason="new test")
@@ -295,10 +281,8 @@
 
     @RequireRunOnPrimaryUser
     @EnsureHasNoWorkProfile
-    @RequireFeatures({
-            PackageManager.FEATURE_DEVICE_ADMIN,
-            PackageManager.FEATURE_MANAGED_USERS
-    })
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @Test
     @Postsubmit(reason="new test")
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
@@ -324,10 +308,8 @@
 
     @RequireRunOnPrimaryUser
     @EnsureHasNoWorkProfile
-    @RequireFeatures({
-            PackageManager.FEATURE_DEVICE_ADMIN,
-            PackageManager.FEATURE_MANAGED_USERS
-    })
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @Test
     @Postsubmit(reason="new test")
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
@@ -440,7 +422,7 @@
     }
 
     @RequireRunOnPrimaryUser
-    @RequireFeatures(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
     @Test
     @EnsureHasPermission({MANAGE_PROFILE_AND_DEVICE_OWNERS})
     public void newlyProvisionedFullyManagedDevice_setsDeviceOwner() throws Exception {
@@ -459,7 +441,7 @@
     }
 
     @RequireRunOnPrimaryUser
-    @RequireFeatures(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
     @Test
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
     public void newlyProvisionedFullyManagedDevice_doesNotThrowException() throws Exception {
@@ -476,7 +458,7 @@
     }
 
     @RequireRunOnPrimaryUser
-    @RequireFeatures(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
     @Test
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
     public void newlyProvisionedFullyManagedDevice_canControlSensorPermissionGrantsByDefault()
@@ -496,7 +478,7 @@
     }
 
     @RequireRunOnPrimaryUser
-    @RequireFeatures(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
     @Test
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
     public void newlyProvisionedFullyManagedDevice_canOptOutOfControllingSensorPermissionGrants()
@@ -518,7 +500,7 @@
     }
 
     @RequireRunOnPrimaryUser
-    @RequireFeatures(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
     @Test
     @Postsubmit(reason="new test")
     @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
@@ -542,8 +524,8 @@
         }
     }
 
-    @RequireFeatures(PackageManager.FEATURE_DEVICE_ADMIN)
-    @RequireDoesNotHaveFeatures(PackageManager.FEATURE_AUTOMOTIVE)
+
+    @RequireDoesNotHaveFeature(PackageManager.FEATURE_AUTOMOTIVE)
     @EnsureHasPermission(MANAGE_DEVICE_ADMINS)
     @Test
     public void getPolicyExemptAppsCanOnlyBeDefinedOnAutomotiveBuilds() throws Exception {
@@ -566,14 +548,14 @@
         try (PermissionContext p = sTestApis.permissions().withPermission(WRITE_SECURE_SETTINGS)) {
             Settings.Secure.putInt(sContext.getContentResolver(), USER_SETUP_COMPLETE_KEY, 0);
         }
-        sDevicePolicyManager.forceUpdateUserSetupComplete();
+        sDevicePolicyManager.forceUpdateUserSetupComplete(sContext.getUserId());
     }
 
     private void setUserSetupCompletedFlag() {
         try (PermissionContext p = sTestApis.permissions().withPermission(WRITE_SECURE_SETTINGS)) {
             Settings.Secure.putInt(sContext.getContentResolver(), USER_SETUP_COMPLETE_KEY, 1);
         }
-        sDevicePolicyManager.forceUpdateUserSetupComplete();
+        sDevicePolicyManager.forceUpdateUserSetupComplete(sContext.getUserId());
     }
 
     private Set<String> findSystemApps() {
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/NegativeCallAuthorizationTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/NegativeCallAuthorizationTest.java
index a759dcd..7b3ff7e 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/NegativeCallAuthorizationTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/NegativeCallAuthorizationTest.java
@@ -27,7 +27,7 @@
 
 import com.android.bedstead.harrier.BedsteadJUnit4;
 import com.android.bedstead.harrier.DeviceState;
-import com.android.bedstead.harrier.annotations.RequireFeatures;
+import com.android.bedstead.harrier.annotations.RequireFeature;
 
 import org.junit.ClassRule;
 import org.junit.Rule;
@@ -53,13 +53,13 @@
     public static final DeviceState sDeviceState = new DeviceState();
 
     @Test
-    @RequireFeatures(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
     public void testHasKeyPair_failIfNotOwner() {
         assertThrows(SecurityException.class, () -> sDpm.hasKeyPair(ALIAS));
     }
 
     @Test
-    @RequireFeatures(PackageManager.FEATURE_DEVICE_ADMIN)
+    @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
     public void testGetKeyPairGrants_failIfNotOwner() {
         assertThrows(SecurityException.class, () -> sDpm.getKeyPairGrants(ALIAS));
     }
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/StartProfilesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/StartProfilesTest.java
index 6f13728..02aaba8 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/StartProfilesTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/StartProfilesTest.java
@@ -37,12 +37,13 @@
 
 import com.android.bedstead.harrier.BedsteadJUnit4;
 import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.EnsureDoesNotHavePermission;
 import com.android.bedstead.harrier.annotations.EnsureHasPermission;
 import com.android.bedstead.harrier.annotations.EnsureHasSecondaryUser;
 import com.android.bedstead.harrier.annotations.EnsureHasTvProfile;
 import com.android.bedstead.harrier.annotations.EnsureHasWorkProfile;
 import com.android.bedstead.harrier.annotations.Postsubmit;
-import com.android.bedstead.harrier.annotations.RequireFeatures;
+import com.android.bedstead.harrier.annotations.RequireFeature;
 import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
 import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.users.UserReference;
@@ -57,11 +58,6 @@
 
 @RunWith(BedsteadJUnit4.class)
 public final class StartProfilesTest {
-
-    // We set this to 30 seconds because if the total test time goes over 66 seconds then it causes
-    // infrastructure problems
-    private static final long PROFILE_ACCESSIBLE_BROADCAST_TIMEOUT = 30 * 1000;
-
     private static final Context sContext = ApplicationProvider.getApplicationContext();
     private static final UserManager sUserManager = sContext.getSystemService(UserManager.class);
     private static final ActivityManager sActivityManager =
@@ -79,7 +75,7 @@
     }
 
     @Test
-    @RequireFeatures(PackageManager.FEATURE_MANAGED_USERS)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @RequireRunOnPrimaryUser
     @EnsureHasWorkProfile
     @EnsureHasPermission({INTERACT_ACROSS_USERS_FULL, INTERACT_ACROSS_USERS, CREATE_USERS})
@@ -90,7 +86,7 @@
     }
 
     @Test
-    @RequireFeatures(PackageManager.FEATURE_MANAGED_USERS)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @RequireRunOnPrimaryUser
     @EnsureHasWorkProfile
     @EnsureHasPermission({INTERACT_ACROSS_USERS_FULL, INTERACT_ACROSS_USERS, CREATE_USERS})
@@ -107,80 +103,59 @@
     }
 
     @Test
-    @RequireFeatures(PackageManager.FEATURE_MANAGED_USERS)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @RequireRunOnPrimaryUser
     @EnsureHasWorkProfile
     @Postsubmit(reason="b/181207615 flaky")
     @EnsureHasPermission({INTERACT_ACROSS_USERS_FULL, INTERACT_ACROSS_USERS, CREATE_USERS})
     public void stopProfile_returnsTrue() {
-        sDeviceState.workProfile().start();
-
-        try {
-            assertThat(sActivityManager.stopProfile(
-                    sDeviceState.workProfile().userHandle())).isTrue();
-        } finally {
-            // TODO(b/171565394): Remove once teardown is done for us
-            sDeviceState.workProfile().start();
-        }
+        assertThat(sActivityManager.stopProfile(sDeviceState.workProfile().userHandle())).isTrue();
     }
 
     @Test
-    @RequireFeatures(PackageManager.FEATURE_MANAGED_USERS)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @RequireRunOnPrimaryUser
     @EnsureHasWorkProfile
     @Postsubmit(reason="b/181207615 flaky")
     @EnsureHasPermission({INTERACT_ACROSS_USERS_FULL, INTERACT_ACROSS_USERS, CREATE_USERS})
     public void stopProfile_profileIsStopped() {
-        sDeviceState.workProfile().start();
         BlockingBroadcastReceiver broadcastReceiver = sDeviceState.registerBroadcastReceiver(
                 Intent.ACTION_PROFILE_INACCESSIBLE, userIsEqual(sDeviceState.workProfile()));
 
-        try {
-            sActivityManager.stopProfile(sDeviceState.workProfile().userHandle());
-            broadcastReceiver.awaitForBroadcastOrFail();
+        sActivityManager.stopProfile(sDeviceState.workProfile().userHandle());
+        broadcastReceiver.awaitForBroadcastOrFail();
 
-            assertThat(
-                    sUserManager.isUserRunning(sDeviceState.workProfile().userHandle())).isFalse();
-        } finally {
-            // TODO(b/171565394): Remove once teardown is done for us
-            sDeviceState.workProfile().start();
-        }
+        assertThat(
+                sUserManager.isUserRunning(sDeviceState.workProfile().userHandle())).isFalse();
     }
 
     @Test
-    @RequireFeatures(PackageManager.FEATURE_MANAGED_USERS)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @RequireRunOnPrimaryUser
     @EnsureHasWorkProfile
     @Postsubmit(reason="b/181207615 flaky")
     @EnsureHasPermission({INTERACT_ACROSS_USERS_FULL, INTERACT_ACROSS_USERS, CREATE_USERS})
     public void startUser_immediatelyAfterStopped_profileIsStarted() {
-        sDeviceState.workProfile().start();
-        BlockingBroadcastReceiver broadcastReceiver = sDeviceState.registerBroadcastReceiver(
-                Intent.ACTION_PROFILE_INACCESSIBLE, userIsEqual(sDeviceState.workProfile()));
-
-        sActivityManager.stopProfile(sDeviceState.workProfile().userHandle());
-        broadcastReceiver.awaitForBroadcast();
-
-        try {
-            // start profile as soon as ACTION_PROFILE_INACCESSIBLE is received
-            // verify that ACTION_PROFILE_ACCESSIBLE is received if profile is re-started
-            broadcastReceiver = sDeviceState.registerBroadcastReceiver(
-                    Intent.ACTION_PROFILE_ACCESSIBLE, userIsEqual(sDeviceState.workProfile()));
-            sActivityManager.startProfile(sDeviceState.workProfile().userHandle());
-            Intent broadcast = broadcastReceiver.awaitForBroadcast();
-
-            assertWithMessage("Expected to receive ACTION_PROFILE_ACCESSIBLE broadcast").that(
-                    broadcast).isNotNull();
-            assertThat(
-                    sUserManager.isUserRunning(sDeviceState.workProfile().userHandle())).isTrue();
-        } finally {
-            // TODO(b/171565394): Remove once teardown is done for us
-            sDeviceState.workProfile().start();
+        try (BlockingBroadcastReceiver broadcastReceiver = sDeviceState.registerBroadcastReceiver(
+                Intent.ACTION_PROFILE_INACCESSIBLE, userIsEqual(sDeviceState.workProfile()))) {
+            sActivityManager.stopProfile(sDeviceState.workProfile().userHandle());
         }
+
+        // start profile as soon as ACTION_PROFILE_INACCESSIBLE is received
+        // verify that ACTION_PROFILE_ACCESSIBLE is received if profile is re-started
+        BlockingBroadcastReceiver broadcastReceiver = sDeviceState.registerBroadcastReceiver(
+               Intent.ACTION_PROFILE_ACCESSIBLE, userIsEqual(sDeviceState.workProfile()));
+        sActivityManager.startProfile(sDeviceState.workProfile().userHandle());
+        Intent broadcast = broadcastReceiver.awaitForBroadcast();
+
+        assertWithMessage("Expected to receive ACTION_PROFILE_ACCESSIBLE broadcast").that(
+                broadcast).isNotNull();
+        assertThat(
+                sUserManager.isUserRunning(sDeviceState.workProfile().userHandle())).isTrue();
     }
 
     @Test
-    @RequireFeatures(PackageManager.FEATURE_MANAGED_USERS)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @RequireRunOnPrimaryUser
     @EnsureHasWorkProfile
     @Postsubmit(reason="b/181207615 flaky")
@@ -190,21 +165,16 @@
 
         // stop and restart profile without waiting for ACTION_PROFILE_INACCESSIBLE broadcast
         sActivityManager.stopProfile(sDeviceState.workProfile().userHandle());
-        try {
-            sActivityManager.startProfile(sDeviceState.workProfile().userHandle());
+        sActivityManager.startProfile(sDeviceState.workProfile().userHandle());
 
-            assertThat(sUserManager.isUserRunning(
-                    sDeviceState.workProfile().userHandle())).isTrue();
-        } finally {
-            // TODO(b/171565394): Remove once teardown is done for us
-            sDeviceState.workProfile().start();
-        }
+        assertThat(sUserManager.isUserRunning(sDeviceState.workProfile().userHandle())).isTrue();
     }
 
     @Test
-    @RequireFeatures(PackageManager.FEATURE_MANAGED_USERS)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @RequireRunOnPrimaryUser
     @EnsureHasWorkProfile
+    @EnsureDoesNotHavePermission({INTERACT_ACROSS_USERS_FULL, INTERACT_ACROSS_USERS, CREATE_USERS})
     @Postsubmit(reason="b/181207615 flaky")
     public void startProfile_withoutPermission_throwsException() {
         assertThrows(SecurityException.class,
@@ -212,17 +182,13 @@
     }
 
     @Test
-    @RequireFeatures(PackageManager.FEATURE_MANAGED_USERS)
+    @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @RequireRunOnPrimaryUser
     @EnsureHasWorkProfile
+    @EnsureDoesNotHavePermission({INTERACT_ACROSS_USERS_FULL, INTERACT_ACROSS_USERS, CREATE_USERS})
     public void stopProfile_withoutPermission_throwsException() {
-        try {
-            assertThrows(SecurityException.class,
-                    () -> sActivityManager.stopProfile(sDeviceState.workProfile().userHandle()));
-        } finally {
-            // TODO(b/171565394): Remove once teardown is done for us
-            sDeviceState.workProfile().start();
-        }
+        assertThrows(SecurityException.class,
+                () -> sActivityManager.stopProfile(sDeviceState.workProfile().userHandle()));
     }
 
     @Test
@@ -240,13 +206,8 @@
     @EnsureHasSecondaryUser
     @EnsureHasPermission({INTERACT_ACROSS_USERS_FULL, INTERACT_ACROSS_USERS, CREATE_USERS})
     public void stopProfile_stoppingFullUser_throwsException() {
-        try {
-            assertThrows(IllegalArgumentException.class,
-                    () -> sActivityManager.stopProfile(sDeviceState.secondaryUser().userHandle()));
-        } finally {
-            // TODO(b/171565394): Remove once teardown is done for us
-            sDeviceState.secondaryUser().start();
-        }
+        assertThrows(IllegalArgumentException.class,
+                () -> sActivityManager.stopProfile(sDeviceState.secondaryUser().userHandle()));
     }
 
     @Test
@@ -256,19 +217,14 @@
     public void startProfile_tvProfile_profileIsStarted() {
         sDeviceState.tvProfile().stop();
 
-        try {
-            BlockingBroadcastReceiver broadcastReceiver = sDeviceState.registerBroadcastReceiver(
-                    Intent.ACTION_PROFILE_ACCESSIBLE, userIsEqual(sDeviceState.tvProfile()));
 
+        try (BlockingBroadcastReceiver broadcastReceiver = sDeviceState.registerBroadcastReceiver(
+                Intent.ACTION_PROFILE_ACCESSIBLE, userIsEqual(sDeviceState.tvProfile()))) {
             assertThat(
                     sActivityManager.startProfile(sDeviceState.tvProfile().userHandle())).isTrue();
-            broadcastReceiver.awaitForBroadcast();
-
-            assertThat(sUserManager.isUserRunning(sDeviceState.tvProfile().userHandle())).isTrue();
-        } finally {
-            // TODO(b/171565394): Remove once teardown is done for us
-            sDeviceState.tvProfile().start();
         }
+
+        assertThat(sUserManager.isUserRunning(sDeviceState.tvProfile().userHandle())).isTrue();
     }
 
     @Test
@@ -276,19 +232,13 @@
     @EnsureHasTvProfile
     @EnsureHasPermission({INTERACT_ACROSS_USERS_FULL, INTERACT_ACROSS_USERS, CREATE_USERS})
     public void stopProfile_tvProfile_profileIsStopped() {
-        sDeviceState.tvProfile().start();
+        BlockingBroadcastReceiver broadcastReceiver = sDeviceState.registerBroadcastReceiver(
+                Intent.ACTION_PROFILE_INACCESSIBLE, userIsEqual(sDeviceState.tvProfile()));
 
-        try {
-            BlockingBroadcastReceiver broadcastReceiver = sDeviceState.registerBroadcastReceiver(
-                    Intent.ACTION_PROFILE_INACCESSIBLE, userIsEqual(sDeviceState.tvProfile()));
+        assertThat(
+                sActivityManager.stopProfile(sDeviceState.tvProfile().userHandle())).isTrue();
+        broadcastReceiver.awaitForBroadcast();
 
-            assertThat(
-                    sActivityManager.stopProfile(sDeviceState.tvProfile().userHandle())).isTrue();
-            broadcastReceiver.awaitForBroadcast();
-
-            assertThat(sUserManager.isUserRunning(sDeviceState.tvProfile().userHandle())).isFalse();
-        } finally {
-            sDeviceState.tvProfile().start();
-        }
+        assertThat(sUserManager.isUserRunning(sDeviceState.tvProfile().userHandle())).isFalse();
     }
 }
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/FreeformWindowingModeTests.java b/tests/framework/base/windowmanager/src/android/server/wm/FreeformWindowingModeTests.java
index 1456486..40bfcc6 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/FreeformWindowingModeTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/FreeformWindowingModeTests.java
@@ -83,7 +83,7 @@
 
     @Test
     public void testNonResizeableActivityHasFullDisplayBounds() throws Exception {
-        createManagedSupportsNonResizableMultiWindowSession().set(0);
+        createManagedDevEnableNonResizableMultiWindowSession().set(0);
         launchActivity(TEST_ACTIVITY);
 
         mWmState.computeState(TEST_ACTIVITY);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
index 4d44076..f6eb851 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
@@ -40,7 +40,9 @@
 import static android.server.wm.app.Components.BROADCAST_RECEIVER_ACTIVITY;
 import static android.server.wm.app.Components.LAUNCHING_ACTIVITY;
 import static android.server.wm.app.Components.NON_RESIZEABLE_ACTIVITY;
+import static android.server.wm.app.Components.NO_HISTORY_ACTIVITY;
 import static android.server.wm.app.Components.RESIZEABLE_ACTIVITY;
+import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_ACTIVITY;
 import static android.server.wm.app.Components.SINGLE_TOP_ACTIVITY;
 import static android.server.wm.app.Components.TEST_ACTIVITY;
 import static android.server.wm.app.Components.TOP_ACTIVITY;
@@ -1001,6 +1003,37 @@
                 mWmState.getActivityCountInTask(taskId2, null));
     }
 
+    @Test
+    public void testLaunchNoHistoryActivityOnNewDisplay() {
+        launchActivity(NO_HISTORY_ACTIVITY);
+        waitAndAssertTopResumedActivity(NO_HISTORY_ACTIVITY, DEFAULT_DISPLAY,
+                "Activity launched on primary display and on top");
+
+        final int taskId = mWmState.getTaskByActivity(NO_HISTORY_ACTIVITY).getTaskId();
+
+        final PrimaryDisplayStateSession displayStateSession =
+                mObjectTracker.manage(new PrimaryDisplayStateSession());
+
+        // Create new virtual display.
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
+                .setSimulateDisplay(true)
+                .createDisplay();
+
+        launchActivityOnDisplay(NO_HISTORY_ACTIVITY, newDisplay.mId);
+
+        // Check that the activity is resumed on the external display
+        waitAndAssertActivityStateOnDisplay(NO_HISTORY_ACTIVITY, STATE_RESUMED, newDisplay.mId,
+                "Activity launched on external display must be resumed");
+        final int taskId2 = mWmState.getTaskByActivity(NO_HISTORY_ACTIVITY).getTaskId();
+
+        displayStateSession.turnScreenOff();
+        launchActivity(SHOW_WHEN_LOCKED_ACTIVITY);
+
+        assertNotEquals("Activity must not be in the same task.", taskId, taskId2);
+        assertEquals("Activity is the only member of its task", 1,
+                mWmState.getActivityCountInTask(taskId2, null));
+    }
+
     private void assertBroughtExistingTaskToAnotherDisplay(int flags, ComponentName topActivity) {
         // Start TEST_ACTIVITY on top of LAUNCHING_ACTIVITY within the same task
         getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY).execute();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayKeyguardTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayKeyguardTests.java
index 06312f0..369069a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayKeyguardTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayKeyguardTests.java
@@ -26,6 +26,8 @@
 import android.server.wm.WindowManagerState.DisplayContent;
 import android.util.Size;
 
+import androidx.test.filters.FlakyTest;
+
 import org.junit.Before;
 import org.junit.Test;
 
@@ -189,6 +191,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 185566696)
     public void testUnlockScreen_decoredSystemDisplayChanged_dismissesKeyguardOnUnlock() {
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
         final VirtualDisplaySession virtualDisplaySession = createManagedVirtualDisplaySession();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiWindowTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiWindowTests.java
index 1651a0a..b7a90c8 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiWindowTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiWindowTests.java
@@ -38,9 +38,11 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
 import android.content.ComponentName;
+import android.content.res.Resources;
 import android.platform.test.annotations.Presubmit;
 import android.server.wm.CommandSession.ActivityCallback;
 import android.window.WindowContainerToken;
@@ -83,31 +85,61 @@
     /** Resizeable activity should be able to enter multi-window mode.*/
     @Test
     public void testResizeableActivity() {
-        launchActivityInPrimarySplit(TEST_ACTIVITY);
-        mWmState.assertVisibility(TEST_ACTIVITY, true);
-        mWmState.waitForActivityState(TEST_ACTIVITY, STATE_RESUMED);
+        assertActivitySupportedInSplitScreen(TEST_ACTIVITY);
     }
 
     /**
-     * Non-resizeable activity should NOT be able to enter multi-window mode,
-     * but should still be visible.
+     * Depending on the value of
+     * {@link com.android.internal.R.integer.config_supportsNonResizableMultiWindow},
+     * non-resizeable activity may or may not be able to enter multi-window mode.
+     *
+     * Based on the flag value:
+     * -1: not support non-resizable in multi window.
+     *  0: check the screen smallest width, if it is a large screen, support non-resizable in multi
+     *     window. Otherwise, not support.
+     *  1: always support non-resizable in multi window.
      */
     @Test
     public void testNonResizeableActivity() {
-        createManagedSupportsNonResizableMultiWindowSession().set(0);
-
-        boolean gotAssertionError = false;
+        createManagedDevEnableNonResizableMultiWindowSession().set(0);
+        final Resources resources = mContext.getResources();
+        final int configSupportsNonResizableMultiWindow;
         try {
-            launchActivityInPrimarySplit(NON_RESIZEABLE_ACTIVITY);
-        } catch (AssertionError e) {
-            gotAssertionError = true;
+            configSupportsNonResizableMultiWindow = resources.getInteger(resources.getIdentifier(
+                    "config_supportsNonResizableMultiWindow", "integer", "android"));
+        } catch (Resources.NotFoundException e) {
+            fail("Device must define config_supportsNonResizableMultiWindow");
+            return;
         }
-        assertTrue("Trying to put non-resizeable activity in split should throw error.",
-                gotAssertionError);
-        assertTrue(mWmState.containsActivityInWindowingMode(
-                NON_RESIZEABLE_ACTIVITY, WINDOWING_MODE_FULLSCREEN));
-        mWmState.assertVisibility(NON_RESIZEABLE_ACTIVITY, true);
-        mWmState.waitForActivityState(NON_RESIZEABLE_ACTIVITY, STATE_RESUMED);
+        switch (configSupportsNonResizableMultiWindow) {
+            case -1:
+                assertActivityNotSupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY);
+                break;
+            case 1:
+                assertActivitySupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY);
+                break;
+            case 0:
+                final int configLargeScreenSmallestScreenWidthDp;
+                try {
+                    configLargeScreenSmallestScreenWidthDp =
+                            resources.getInteger(resources.getIdentifier(
+                                    "config_largeScreenSmallestScreenWidthDp",
+                                    "integer", "android"));
+                } catch (Resources.NotFoundException e) {
+                    fail("Device must define config_largeScreenSmallestScreenWidthDp");
+                    return;
+                }
+                final int smallestScreenWidthDp = mWmState.getHomeTask()
+                        .mFullConfiguration.smallestScreenWidthDp;
+                if (smallestScreenWidthDp >= configLargeScreenSmallestScreenWidthDp) {
+                    assertActivitySupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY);
+                } else {
+                    assertActivityNotSupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY);
+                }
+                break;
+            default:
+                fail("config_supportsNonResizableMultiWindow must be -1, 0, or 1.");
+        }
     }
 
     /**
@@ -116,15 +148,10 @@
      * set.
      */
     @Test
-    public void testSupportsNonResizeableMultiWindow_splitScreenPrimary() {
-        createManagedSupportsNonResizableMultiWindowSession().set(1);
+    public void testDevEnableNonResizeableMultiWindow_splitScreenPrimary() {
+        createManagedDevEnableNonResizableMultiWindowSession().set(1);
 
-        launchActivityInPrimarySplit(NON_RESIZEABLE_ACTIVITY);
-
-        mWmState.waitForActivityState(NON_RESIZEABLE_ACTIVITY, STATE_RESUMED);
-        mWmState.assertVisibility(NON_RESIZEABLE_ACTIVITY, true);
-        assertTrue(mWmState.containsActivityInWindowingMode(
-                NON_RESIZEABLE_ACTIVITY, WINDOWING_MODE_MULTI_WINDOW));
+        assertActivitySupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY);
     }
 
     /**
@@ -133,51 +160,8 @@
      * set.
      */
     @Test
-    public void testSupportsNonResizeableMultiWindow_splitScreenSecondary() {
-        createManagedSupportsNonResizableMultiWindowSession().set(1);
-
-        launchActivityInPrimarySplit(TEST_ACTIVITY);
-
-        mWmState.waitForActivityState(TEST_ACTIVITY, STATE_RESUMED);
-        mWmState.assertVisibility(TEST_ACTIVITY, true);
-        assertTrue(mWmState.containsActivityInWindowingMode(
-                TEST_ACTIVITY, WINDOWING_MODE_MULTI_WINDOW));
-
-        launchActivityInSecondarySplit(NON_RESIZEABLE_ACTIVITY);
-
-        mWmState.waitForActivityState(NON_RESIZEABLE_ACTIVITY, STATE_RESUMED);
-        mWmState.assertVisibility(NON_RESIZEABLE_ACTIVITY, true);
-        assertTrue(mWmState.containsActivityInWindowingMode(
-                NON_RESIZEABLE_ACTIVITY, WINDOWING_MODE_MULTI_WINDOW));
-    }
-
-    /**
-     * Non-resizeable activity can enter split-screen if
-     * {@link android.provider.Settings.Global#DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW} is
-     * set.
-     */
-    @Test
-    public void testSupportsNonResizeableMultiWindow_SplitScreenPrimary() {
-        createManagedSupportsNonResizableMultiWindowSession().set(1);
-
-        launchActivitiesInSplitScreen(
-                getLaunchActivityBuilder().setTargetActivity(NON_RESIZEABLE_ACTIVITY),
-                getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
-
-        mWmState.waitForActivityState(NON_RESIZEABLE_ACTIVITY, STATE_RESUMED);
-        mWmState.assertVisibility(NON_RESIZEABLE_ACTIVITY, true);
-        assertTrue(mWmState.containsActivityInWindowingMode(
-                NON_RESIZEABLE_ACTIVITY, WINDOWING_MODE_MULTI_WINDOW));
-    }
-
-    /**
-     * Non-resizeable activity can enter split-screen if
-     * {@link android.provider.Settings.Global#DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW} is
-     * set.
-     */
-    @Test
-    public void testSupportsNonResizeableMultiWindow_SplitScreenSecondary() {
-        createManagedSupportsNonResizableMultiWindowSession().set(1);
+    public void testDevEnableNonResizeableMultiWindow_splitScreenSecondary() {
+        createManagedDevEnableNonResizableMultiWindowSession().set(1);
 
         launchActivitiesInSplitScreen(
                 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY),
@@ -189,6 +173,29 @@
                 NON_RESIZEABLE_ACTIVITY, WINDOWING_MODE_MULTI_WINDOW));
     }
 
+    /** Asserts that the give activity can be shown in split screen. */
+    private void assertActivitySupportedInSplitScreen(ComponentName activity) {
+        launchActivityInPrimarySplit(activity);
+        mWmState.waitForActivityState(activity, STATE_RESUMED);
+        mWmState.assertVisibility(activity, true);
+        assertTrue(mWmState.containsActivityInWindowingMode(activity, WINDOWING_MODE_MULTI_WINDOW));
+    }
+
+    /** Asserts that the give activity can NOT be shown in split screen. */
+    private void assertActivityNotSupportedInSplitScreen(ComponentName activity) {
+        boolean gotAssertionError = false;
+        try {
+            launchActivityInPrimarySplit(activity);
+        } catch (AssertionError e) {
+            gotAssertionError = true;
+        }
+        assertTrue("Trying to put non-resizeable activity in split should throw error.",
+                gotAssertionError);
+        mWmState.waitForActivityState(activity, STATE_RESUMED);
+        mWmState.assertVisibility(activity, true);
+        assertTrue(mWmState.containsActivityInWindowingMode(activity, WINDOWING_MODE_FULLSCREEN));
+    }
+
     @Test
     public void testLaunchToSideMultiWindowCallbacks() {
         // Launch two activities in split-screen mode.
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityStarterTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityStarterTests.java
index f5d1693..e60ae4f 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityStarterTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityStarterTests.java
@@ -24,10 +24,12 @@
 import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
 import static android.server.wm.ComponentNameUtils.getActivityName;
+import static android.server.wm.UiDeviceUtils.pressWakeupButton;
 import static android.server.wm.WindowManagerState.STATE_DESTROYED;
 import static android.server.wm.WindowManagerState.STATE_RESUMED;
 import static android.server.wm.app.Components.ALIAS_TEST_ACTIVITY;
 import static android.server.wm.app.Components.NO_HISTORY_ACTIVITY;
+import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY;
 import static android.server.wm.app.Components.TEST_ACTIVITY;
 import static android.server.wm.lifecycle.LifecycleLog.ActivityCallback.ON_STOP;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -183,6 +185,84 @@
     }
 
     /**
+     * This test case tests the behavior that a fullscreen activity was started on top of the
+     * no-history activity within different tasks during sleeping. The no-history activity must be
+     * finished.
+     */
+    @Test
+    public void testNoHistoryActivityWithDifferentTask() {
+        assumeTrue(supportsLockScreen());
+
+        final LockScreenSession lockScreenSession = createManagedLockScreenSession();
+        // Launch a no-history activity
+        getLaunchActivityBuilder().setTargetActivity(NO_HISTORY_ACTIVITY)
+                .setIntentExtra(extra -> extra.putBoolean(
+                        Components.NoHistoryActivity.EXTRA_SHOW_WHEN_LOCKED, true))
+                .setWaitForLaunched(false)
+                .setUseInstrumentation()
+                .execute();
+
+        // Wait for the activity resumed.
+        waitAndAssertActivityState(NO_HISTORY_ACTIVITY, STATE_RESUMED,
+                "Activity must be resumed");
+        final int taskId = mWmState.getTaskByActivity(NO_HISTORY_ACTIVITY).getTaskId();
+        lockScreenSession.sleepDevice();
+
+        // Launch a single instance activity
+        getLaunchActivityBuilder().setTargetActivity(SINGLE_INSTANCE_ACTIVITY)
+                .setIntentExtra(extra -> extra.putBoolean(
+                        SingleInstanceActivity.EXTRA_SHOW_WHEN_LOCKED, true))
+                .setWaitForLaunched(false)
+                .setUseInstrumentation()
+                .execute();
+
+        // Make sure the activity is finished.
+        final String waitFinishMsg = "Instance of no-history activity must not exist";
+        assertTrue(waitFinishMsg, mWmState.waitForWithAmState(
+                amState -> 0 == amState.getActivityCountInTask(taskId, NO_HISTORY_ACTIVITY),
+                waitFinishMsg));
+
+        // Turn the screen on after the test is completed to prevent keyDispatchingTimedOut during
+        // the lockScreenSession close.
+        pressWakeupButton();
+    }
+
+    /**
+     * This test case tests the behavior that a translucent activity was started on top of the
+     * no-history activity during sleeping. The no-history activity must not be finished.
+     */
+    @Test
+    public void testNoHistoryActivityWithTranslucentActivity() {
+        assumeTrue(supportsLockScreen());
+
+        final LockScreenSession lockScreenSession = createManagedLockScreenSession();
+        // Launch a no-history activity
+        getLaunchActivityBuilder().setTargetActivity(NO_HISTORY_ACTIVITY)
+                .setIntentExtra(extra -> extra.putBoolean(
+                        Components.NoHistoryActivity.EXTRA_SHOW_WHEN_LOCKED, true))
+                .setWaitForLaunched(false)
+                .setUseInstrumentation()
+                .execute();
+
+        // Wait for the activity resumed.
+        waitAndAssertActivityState(NO_HISTORY_ACTIVITY, STATE_RESUMED,
+                "Activity must be resumed");
+
+        final int taskId = mWmState.getTaskByActivity(NO_HISTORY_ACTIVITY).getTaskId();
+        lockScreenSession.sleepDevice();
+        launchActivityNoWait(SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY);
+
+        final String waitFinishMsg = "Instance of no-history activity must exist";
+        assertTrue(waitFinishMsg, mWmState.waitForWithAmState(
+                amState -> 1 == amState.getActivityCountInTask(taskId, NO_HISTORY_ACTIVITY),
+                waitFinishMsg));
+
+        // Turn the screen on after the test is completed to prevent keyDispatchingTimedOut during
+        // the lockScreenSession close.
+        pressWakeupButton();
+    }
+
+    /**
      * This test case tests "single top" activity behavior.
      * - A first launched standard activity and a second launched single top
      * activity are in same task.
@@ -662,6 +742,14 @@
 
     // Test activity
     public static class SingleInstanceActivity extends Activity {
+        public static final String EXTRA_SHOW_WHEN_LOCKED = "showWhenLocked";
+        @Override
+        protected void onCreate(Bundle icicle) {
+            super.onCreate(icicle);
+            if (getIntent().getBooleanExtra(EXTRA_SHOW_WHEN_LOCKED, false)) {
+                setShowWhenLocked(true);
+            }
+        }
     }
 
     // Test activity
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 4e2aa67..0aa2394 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
@@ -1243,9 +1243,9 @@
     }
 
     /** @see ObjectTracker#manage(AutoCloseable) */
-    protected SupportsNonResizableMultiWindowSession
-        createManagedSupportsNonResizableMultiWindowSession() {
-        return mObjectTracker.manage(new SupportsNonResizableMultiWindowSession());
+    protected DevEnableNonResizableMultiWindowSession
+    createManagedDevEnableNonResizableMultiWindowSession() {
+        return mObjectTracker.manage(new DevEnableNonResizableMultiWindowSession());
     }
 
     /** @see ObjectTracker#manage(AutoCloseable) */
@@ -1550,8 +1550,8 @@
         }
     }
 
-    protected class SupportsNonResizableMultiWindowSession extends SettingsSession<Integer> {
-        SupportsNonResizableMultiWindowSession() {
+    protected class DevEnableNonResizableMultiWindowSession extends SettingsSession<Integer> {
+        DevEnableNonResizableMultiWindowSession() {
             super(Settings.Global.getUriFor(
                     Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW),
                     (cr, name) -> Settings.Global.getInt(cr, name, 0 /* def */),
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 eca4e75..f9fe6d5 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
@@ -246,7 +246,7 @@
         return TYPE_NAVIGATION_BAR == navState.getType();
     }
 
-/**
+    /**
      * For a given WindowContainer, traverse down the hierarchy and add all children of type
      * {@code T} to {@code outChildren}.
      */
@@ -1614,31 +1614,31 @@
     static WindowContainer getWindowContainer(WindowContainerChildProto proto,
             WindowContainer parent) {
         if (proto.displayContent != null) {
-           return new DisplayContent(proto.displayContent);
+            return new DisplayContent(proto.displayContent);
         }
 
         if (proto.displayArea != null) {
-           return new DisplayArea(proto.displayArea);
+            return new DisplayArea(proto.displayArea);
         }
 
         if (proto.task != null) {
-           return new ActivityTask(proto.task);
+            return new ActivityTask(proto.task);
         }
 
         if (proto.activity != null) {
-           return new Activity(proto.activity, parent);
+            return new Activity(proto.activity, parent);
         }
 
         if (proto.windowToken != null) {
-           return new WindowToken(proto.windowToken);
+            return new WindowToken(proto.windowToken);
         }
 
         if (proto.window != null) {
-           return new WindowState(proto.window);
+            return new WindowState(proto.window);
         }
 
         if (proto.windowContainer != null) {
-           return new GenericWindowContainer(proto.windowContainer);
+            return new GenericWindowContainer(proto.windowContainer);
         }
         return null;
     }
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
index f12f204..dfd7929 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
@@ -672,7 +672,7 @@
         for (int i = 0; ; i++) {
             String csdKey = "csd-" + i;
             if (format.containsKey(csdKey)) {
-                mCsdBuffers.add(format.getByteBuffer(csdKey));
+                mCsdBuffers.add(format.getByteBuffer(csdKey).duplicate());
                 format.removeKey(csdKey);
             } else break;
         }
@@ -688,7 +688,8 @@
         for (String decoder : listOfDecoders) {
             mCodec = MediaCodec.createByCodecName(decoder);
             int loopCounter = 0;
-            for (MediaFormat fmt : formats) {
+            for (int i = 0; i < formats.size(); i++) {
+                MediaFormat fmt = formats.get(i);
                 for (boolean eosMode : boolStates) {
                     for (boolean isAsync : boolStates) {
                         boolean validateFormat = true;
@@ -707,7 +708,7 @@
                             validateFormat = false;
                         }
                         mCodec.start();
-                        queueCodecConfig();
+                        if (i == 0) queueCodecConfig();
                         doWork(Integer.MAX_VALUE);
                         queueEOS();
                         waitForAllOutputs();
diff --git a/tests/quickaccesswallet/AndroidManifest.xml b/tests/quickaccesswallet/AndroidManifest.xml
index e7a1df5..d8e38d1 100755
--- a/tests/quickaccesswallet/AndroidManifest.xml
+++ b/tests/quickaccesswallet/AndroidManifest.xml
@@ -25,7 +25,7 @@
     <!-- Required to test QuickAccessWalletClient feature availability -->
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
 
-    <application>
+    <application android:testOnly="true">
         <uses-library android:name="android.test.runner"/>
         <activity android:name="android.quickaccesswallet.QuickAccessWalletActivity"
              android:exported="true">
diff --git a/tests/quickaccesswallet/AndroidTest.xml b/tests/quickaccesswallet/AndroidTest.xml
index c605ec0..3f7a774 100644
--- a/tests/quickaccesswallet/AndroidTest.xml
+++ b/tests/quickaccesswallet/AndroidTest.xml
@@ -20,6 +20,7 @@
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="install-arg" value="-t" />
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsQuickAccessWalletTestCases.apk" />
     </target_preparer>
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
index 012a3a6..5f12ea7 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
@@ -51,6 +51,8 @@
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AppModeInstant;
 import android.provider.Settings;
+import android.server.wm.WindowManagerState;
+import android.server.wm.WindowManagerStateHelper;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.Until;
@@ -124,6 +126,8 @@
             "android.app.usage.cts.test2.FinishingTaskRootActivity";
     private static final String TEST_APP2_CLASS_PIP =
             "android.app.usage.cts.test2.PipActivity";
+    private static final ComponentName TEST_APP2_PIP_COMPONENT = new ComponentName(TEST_APP2_PKG,
+            TEST_APP2_CLASS_PIP);
 
     private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
     private static final long MINUTE = TimeUnit.MINUTES.toMillis(1);
@@ -147,6 +151,7 @@
     private int mOtherUser;
     private Context mOtherUserContext;
     private UsageStatsManager mOtherUsageStats;
+    private WindowManagerStateHelper mWMStateHelper;
 
     @Before
     public void setUp() throws Exception {
@@ -158,6 +163,8 @@
         mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
         mTargetPackage = mContext.getPackageName();
 
+        mWMStateHelper = new WindowManagerStateHelper();
+
         assumeTrue("App Standby not enabled on device", AppStandbyUtils.isAppStandbyEnabled());
         setAppOpsMode("allow");
         mCachedUsageSourceSetting = getSetting(Settings.Global.APP_TIME_LIMIT_USAGE_SOURCE);
@@ -174,6 +181,7 @@
         setSetting(Settings.Global.ENABLE_RESTRICTED_BUCKET, mCachedEnableRestrictedBucketSetting);
         // Force stop test package to avoid any running test code from carrying over to the next run
         SystemUtil.runWithShellPermissionIdentity(() -> mAm.forceStopPackage(TEST_APP_PKG));
+        SystemUtil.runWithShellPermissionIdentity(() -> mAm.forceStopPackage(TEST_APP2_PKG));
         mUiDevice.pressHome();
         // Destroy the other user if created
         if (mOtherUser != 0) {
@@ -986,7 +994,7 @@
     private ArrayList<Event> waitForEventCount(int[] whichEvents, long startTime, int count,
             String packageName) {
         final ArrayList<Event> events = new ArrayList<>();
-        final long endTime = SystemClock.uptimeMillis() + 2000;
+        final long endTime = SystemClock.uptimeMillis() + TIMEOUT;
         do {
             events.clear();
             getEvents(whichEvents, startTime, events, packageName);
@@ -1530,6 +1538,9 @@
     @AppModeFull(reason = "No usage events access in instant apps")
     @Test
     public void testPipActivity() throws Exception {
+        assumeTrue("Test cannot run without Picture in Picture support",
+                mContext.getPackageManager().hasSystemFeature(
+                        PackageManager.FEATURE_PICTURE_IN_PICTURE));
         mUiDevice.wakeUp();
         dismissKeyguard(); // also want to start out with the keyguard dismissed.
         mUiDevice.pressHome();
@@ -1543,6 +1554,13 @@
         launchTestActivity(TEST_APP_PKG, TEST_APP_CLASS);
         SystemClock.sleep(500);
 
+        mWMStateHelper.waitForActivityState(TEST_APP2_PIP_COMPONENT,
+                WindowManagerState.STATE_PAUSED);
+
+        mWMStateHelper.assertActivityDisplayed(TEST_APP2_PIP_COMPONENT);
+        mWMStateHelper.assertNotFocusedActivity("Pip activity should not be in focus",
+                TEST_APP2_PIP_COMPONENT);
+
         final long endTime = System.currentTimeMillis();
         final UsageEvents events = mUsageStatsManager.queryEvents(startTime, endTime);
 
@@ -1582,12 +1600,13 @@
     @AppModeFull(reason = "No usage events access in instant apps")
     @Test
     public void testPipActivity_StopToPause() throws Exception {
+        assumeTrue("Test cannot run without Picture in Picture support",
+                mContext.getPackageManager().hasSystemFeature(
+                        PackageManager.FEATURE_PICTURE_IN_PICTURE));
         mUiDevice.wakeUp();
         dismissKeyguard(); // also want to start out with the keyguard dismissed.
         mUiDevice.pressHome();
 
-        final long startTime = System.currentTimeMillis();
-
         launchTestActivity(TEST_APP2_PKG, TEST_APP2_CLASS_PIP);
         SystemClock.sleep(500);
 
@@ -1595,9 +1614,17 @@
         launchTestActivity(TEST_APP_PKG, TEST_APP_CLASS);
         SystemClock.sleep(500);
 
+        mWMStateHelper.assertActivityDisplayed(TEST_APP2_PIP_COMPONENT);
+        mWMStateHelper.assertNotFocusedActivity("Pip activity should not be in focus",
+                TEST_APP2_PIP_COMPONENT);
+
         // Sleeping the device should cause the Pip activity to stop.
         final long sleepTime = System.currentTimeMillis();
         sleepDevice();
+        mWMStateHelper.waitForActivityState(TEST_APP2_PIP_COMPONENT,
+                WindowManagerState.STATE_STOPPED);
+
+        // Pip activity stop should show up in UsageStats.
         final ArrayList<Event> stoppedEvent = waitForEventCount(STOPPED_EVENT, sleepTime, 1,
                 TEST_APP2_PKG);
         assertEquals(Event.ACTIVITY_STOPPED, stoppedEvent.get(0).getEventType());
@@ -1606,52 +1633,24 @@
         final long wakeTime = System.currentTimeMillis();
         mUiDevice.wakeUp();
         dismissKeyguard();
-        final ArrayList<Event> pausedEvent = waitForEventCount(PAUSED_EVENT, wakeTime, 1,
-                TEST_APP2_PKG);
-        assertEquals(Event.ACTIVITY_PAUSED, pausedEvent.get(0).getEventType());
+        mWMStateHelper.waitForActivityState(TEST_APP2_PIP_COMPONENT,
+                WindowManagerState.STATE_PAUSED);
+
+        mWMStateHelper.assertActivityDisplayed(TEST_APP2_PIP_COMPONENT);
+        mWMStateHelper.assertNotFocusedActivity("Pip activity should not be in focus",
+                TEST_APP2_PIP_COMPONENT);
 
         // Sleeping the device should cause the Pip activity to stop again.
         final long secondSleepTime = System.currentTimeMillis();
         sleepDevice();
+        mWMStateHelper.waitForActivityState(TEST_APP2_PIP_COMPONENT,
+                WindowManagerState.STATE_STOPPED);
+
+        // Pip activity stop should show up in UsageStats again.
         final ArrayList<Event> secondStoppedEvent = waitForEventCount(STOPPED_EVENT,
                 secondSleepTime, 1,
                 TEST_APP2_PKG);
         assertEquals(Event.ACTIVITY_STOPPED, secondStoppedEvent.get(0).getEventType());
-
-        final long endTime = System.currentTimeMillis();
-        final UsageEvents events = mUsageStatsManager.queryEvents(startTime, endTime);
-
-        int resumes = 0;
-        int pauses = 0;
-        int stops = 0;
-
-        while (events.hasNextEvent()) {
-            final UsageEvents.Event event = new UsageEvents.Event();
-            assertTrue(events.getNextEvent(event));
-
-            if(TEST_APP2_PKG.equals(event.getPackageName())) {
-                switch (event.mEventType) {
-                    case Event.ACTIVITY_RESUMED:
-                        assertNotNull("ACTIVITY_RESUMED event Task Root should not be null",
-                                event.getTaskRootPackageName());
-                        resumes++;
-                        break;
-                    case Event.ACTIVITY_PAUSED:
-                        assertNotNull("ACTIVITY_PAUSED event Task Root should not be null",
-                                event.getTaskRootPackageName());
-                        pauses++;
-                        break;
-                    case Event.ACTIVITY_STOPPED:
-                        assertNotNull("ACTIVITY_STOPPED event Task Root should not be null",
-                                event.getTaskRootPackageName());
-                        stops++;
-                        break;
-                }
-            }
-        }
-        assertEquals("Unexpected number of activity resumes", 1, resumes);
-        assertEquals("Unexpected number of activity pauses", 2, pauses);
-        assertEquals("Unexpected number of activity stops", 2, stops);
     }
 
     @AppModeFull(reason = "No usage events access in instant apps")
diff --git a/tests/tests/appop/src/android/app/appops/cts/DiscreteAppopsTest.kt b/tests/tests/appop/src/android/app/appops/cts/DiscreteAppopsTest.kt
index 67337d8..c522e997 100644
--- a/tests/tests/appop/src/android/app/appops/cts/DiscreteAppopsTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/DiscreteAppopsTest.kt
@@ -118,6 +118,8 @@
                             "$KEY_BG_STATE_SETTLE_TIME=10")
         }
 
+        enableDiscreteRegistryDebugMode()
+
         val serviceIntent = Intent().setComponent(ComponentName(PACKAGE_NAME,
                 "$PACKAGE_NAME.AppOpsForegroundControlService"))
 
@@ -984,17 +986,22 @@
         }
     }
 
-    private fun setQuantization(timeQuantMillis: Long) {
+    private fun enableDiscreteRegistryDebugMode() {
         runWithShellPermissionIdentity {
             appOpsManager.setHistoryParameters(HISTORICAL_MODE_ENABLED_PASSIVE,
                     SNAPSHOT_INTERVAL_MILLIS, INTERVAL_COMPRESSION_MULTIPLIER)
-            DeviceConfig.setProperty(NAMESPACE_PRIVACY, PROPERTY_QUANTIZATION,
-                    timeQuantMillis.toString(), false)
             appOpsManager.setHistoryParameters(HISTORICAL_MODE_ENABLED_ACTIVE,
                     SNAPSHOT_INTERVAL_MILLIS, INTERVAL_COMPRESSION_MULTIPLIER)
         }
     }
 
+    private fun setQuantization(timeQuantMillis: Long) {
+        runWithShellPermissionIdentity {
+            DeviceConfig.setProperty(NAMESPACE_PRIVACY, PROPERTY_QUANTIZATION,
+                    timeQuantMillis.toString(), false)
+        }
+    }
+
     private fun noteOp(
         op: String,
         uid: Int,
diff --git a/tests/tests/content/AndroidTest.xml b/tests/tests/content/AndroidTest.xml
index d221460..6163ab2 100644
--- a/tests/tests/content/AndroidTest.xml
+++ b/tests/tests/content/AndroidTest.xml
@@ -92,7 +92,6 @@
         <option name="push-file" key="HelloWorld5.apk" value="/data/local/tmp/cts/content/malformed.apk" />
         <option name="push-file" key="malformed.apk.idsig" value="/data/local/tmp/cts/content/malformed.apk.idsig" />
         <option name="push-file" key="test-cert.x509.pem" value="/data/local/tmp/cts/content/test-cert.x509.pem" />
-
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/tests/content/HelloWorldApp/res/values/res_hardening.xml b/tests/tests/content/HelloWorldApp/res/values/res_hardening.xml
new file mode 100644
index 0000000..70cb280
--- /dev/null
+++ b/tests/tests/content/HelloWorldApp/res/values/res_hardening.xml
@@ -0,0 +1,58 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <string name="inc_string">true</string>
+    <string name="inc_string_end">true</string>
+
+    <bool name="inc_bool">true</bool>
+    <bool name="inc_bool_end">true</bool>
+
+    <integer name="inc_integer">1</integer>
+    <integer name="inc_integer_end">1</integer>
+
+    <string-array name="inc_string_array">
+        <item>@string/inc_string</item>
+    </string-array>
+    <string-array name="inc_string_array_end" />
+
+    <attr name="inc_string_attr" />
+    <attr name="inc_bool_attr" />
+    <attr name="inc_integer_attr" />
+
+    <style name="IncStyle">
+        <item name="inc_string_attr">@string/inc_string</item>
+        <item name="inc_bool_attr">@bool/inc_bool</item>
+        <item name="inc_integer_attr">@integer/inc_integer</item>
+    </style>
+
+    <public type="string" name="inc_string" id ="0x7f021000"/>
+    <public type="string" name="inc_string_end" id ="0x7f022000"/>
+
+    <public type="bool" name="inc_bool" id ="0x7f031000"/>
+    <public type="bool" name="inc_bool_end" id ="0x7f032000"/>
+
+    <public type="integer" name="inc_integer" id ="0x7f041000"/>
+    <public type="integer" name="inc_integer_end" id ="0x7f042000"/>
+
+    <public type="array" name="inc_string_array" id ="0x7f051000"/>
+    <public type="array" name="inc_string_array_end" id ="0x7f052000"/>
+
+    <public type="style" name="IncStyle" id ="0x7f061000"/>
+
+    <public type="attr" name="inc_string_attr" id ="0x7f011000"/>
+    <public type="attr" name="inc_bool_attr" id ="0x7f011001"/>
+    <public type="attr" name="inc_integer_attr" id ="0x7f011002"/>
+</resources>
\ No newline at end of file
diff --git a/tests/tests/content/HelloWorldApp/res/xml/test_xml.xml b/tests/tests/content/HelloWorldApp/res/xml/test_xml.xml
new file mode 100644
index 0000000..3f225ee
--- /dev/null
+++ b/tests/tests/content/HelloWorldApp/res/xml/test_xml.xml
@@ -0,0 +1,18 @@
+<?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.
+  -->
+
+<Test>true</Test>
\ No newline at end of file
diff --git a/tests/tests/content/HelloWorldApp/res/xml/test_xml_attrs.xml b/tests/tests/content/HelloWorldApp/res/xml/test_xml_attrs.xml
new file mode 100644
index 0000000..28ce9bd
--- /dev/null
+++ b/tests/tests/content/HelloWorldApp/res/xml/test_xml_attrs.xml
@@ -0,0 +1,21 @@
+<?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.
+  -->
+
+<Test xmlns:app="http://schemas.android.com/apk/res-auto"
+      app:inc_string_attr="@string/inc_string"
+      app:inc_bool_attr="@bool/inc_bool"
+      app:inc_integer_attr="@integer/inc_integer" />
\ No newline at end of file
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
index 5aebc24..e5ff3dc 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
@@ -992,7 +992,7 @@
                         atraceDumpDelayMs));
     }
 
-    private boolean isAppInstalled(String packageName) throws IOException {
+    static boolean isAppInstalled(String packageName) throws IOException {
         final String commandResult = executeShellCommand("pm list packages");
         final int prefixLength = "package:".length();
         return Arrays.stream(commandResult.split("\\r?\\n"))
@@ -1092,7 +1092,7 @@
         return readTime;
     }
 
-    private String uninstallPackageSilently(String packageName) throws IOException {
+    static String uninstallPackageSilently(String packageName) throws IOException {
         return executeShellCommand("pm uninstall " + packageName);
     }
 
@@ -1100,7 +1100,7 @@
         boolean await() throws Exception;
     }
 
-    private static String executeShellCommand(String command) throws IOException {
+    static String executeShellCommand(String command) throws IOException {
         try (InputStream inputStream = executeShellCommandStream(command)) {
             return readFullStream(inputStream);
         }
@@ -1143,18 +1143,18 @@
         return new ParcelFileDescriptor.AutoCloseInputStream(stdout);
     }
 
-    private static String readFullStream(InputStream inputStream, long expected)
+    static String readFullStream(InputStream inputStream, long expected)
             throws IOException {
         ByteArrayOutputStream result = new ByteArrayOutputStream();
         writeFullStream(inputStream, result, expected);
         return result.toString("UTF-8");
     }
 
-    private static String readFullStream(InputStream inputStream) throws IOException {
+    static String readFullStream(InputStream inputStream) throws IOException {
         return readFullStream(inputStream, -1);
     }
 
-    private static void writeFullStream(InputStream inputStream, OutputStream outputStream,
+    static void writeFullStream(InputStream inputStream, OutputStream outputStream,
             long expected)
             throws IOException {
         final byte[] buffer = new byte[1024];
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
index 2379d10..598e882 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
@@ -160,6 +160,8 @@
             + "iRKAay19k5VFlSaM7QW9uhvlrLQqsTW01ofFzxNDbp2QfIFHZR6rebKzKBz6byQFM0DYQnYMwFWXjWkMPN"
             + "dqkRLykoFLyBup53G68k2n8w";
     private static final String SHELL_PACKAGE_NAME = "com.android.shell";
+    private static final String HELLO_WORLD_PACKAGE_NAME = "com.example.helloworld";
+    private static final String HELLO_WORLD_APK = SAMPLE_APK_BASE + "HelloWorld5.apk";
 
     @Before
     public void setup() throws Exception {
@@ -171,6 +173,7 @@
     public void tearDown() throws Exception {
         uninstallPackage(EMPTY_APP_PACKAGE_NAME);
         uninstallPackage(EMPTY_APP_MAX_PACKAGE_NAME);
+        uninstallPackage(HELLO_WORLD_PACKAGE_NAME);
     }
 
     @Test
@@ -1310,6 +1313,16 @@
                 .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
     }
 
+    @Test
+    public void testGetApplicationInfo_icon_MatchesUseRoundIcon() throws Exception {
+        installPackage(HELLO_WORLD_APK);
+        final boolean useRoundIcon = mContext.getResources().getBoolean(
+                mContext.getResources().getIdentifier("config_useRoundIcon", "bool", "android"));
+        final ApplicationInfo info = mPackageManager.getApplicationInfo(HELLO_WORLD_PACKAGE_NAME,
+                0 /*flags*/);
+        assertThat(info.icon).isEqualTo((useRoundIcon ? info.roundIconRes : info.iconRes));
+    }
+
     private boolean isUpdatingApexSupported() {
         return SystemProperties.getBoolean("ro.apex.updatable", false);
     }
diff --git a/tests/tests/content/src/android/content/pm/cts/ResourcesHardeningTest.java b/tests/tests/content/src/android/content/pm/cts/ResourcesHardeningTest.java
new file mode 100644
index 0000000..c7ae4cc
--- /dev/null
+++ b/tests/tests/content/src/android/content/pm/cts/ResourcesHardeningTest.java
@@ -0,0 +1,345 @@
+/*
+ * 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.content.pm.cts;
+
+import static android.content.pm.cts.PackageManagerShellCommandIncrementalTest.isAppInstalled;
+import static android.content.pm.cts.PackageManagerShellCommandIncrementalTest.uninstallPackageSilently;
+import static android.content.pm.cts.PackageManagerShellCommandIncrementalTest.writeFullStream;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertTrue;
+
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.cts.util.XmlUtils;
+import android.content.pm.PackageManager;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.MatcherUtils;
+import com.android.incfs.install.IBlockFilter;
+import com.android.incfs.install.IncrementalInstallSession;
+import com.android.incfs.install.PendingBlock;
+
+import org.hamcrest.Matcher;
+import org.hamcrest.MatcherAssert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Paths;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@RunWith(AndroidJUnit4.class)
+@AppModeFull
+@LargeTest
+public class ResourcesHardeningTest {
+    private static final String TEST_APK_PATH = "/data/local/tmp/cts/content/";
+    private static final String[] TEST_APKS = {"HelloWorld5.apk", "HelloWorld5_mdpi-v4.apk"};
+    private static final String TEST_APP_PACKAGE = "com.example.helloworld";
+
+    private static final String RES_IDENTIFIER = TEST_APP_PACKAGE + ":string/inc_string";
+    private static final String RES_XML_PATH = "res/xml/test_xml.xml";
+    private static final String RES_XML_LARGE_PATH = "res/xml/test_xml_attrs.xml";
+    private static final String RES_DRAWABLE_PATH = "res/drawable-mdpi-v4/background.jpg";
+    private static final int RES_STRING = 0x7f021000;
+    private static final int RES_ARRAY = 0x7f051000;
+    private static final int RES_STYLE = 0x7f061000;
+    private static final int[] RES_STYLEABLE = {0x7f011000, 0x7f011001, 0x7f011002};
+
+    @Test
+    public void checkGetIdentifier() throws Exception {
+        testReadSuccessAndFailure(
+                (res, filter) -> {
+                    filter.stopSendingBlocks();
+                    return res.getIdentifier(RES_IDENTIFIER, "", "");
+                },
+                not(equalTo(0)), equalTo(0));
+    }
+
+    @Test
+    public void checkGetResourceName() throws Exception {
+        testReadSuccessAndFailureException(
+                (res, filter) -> {
+                    filter.stopSendingBlocks();
+                    return res.getResourceName(RES_STRING);
+                },
+                equalTo(RES_IDENTIFIER), instanceOf(Resources.NotFoundException.class));
+    }
+
+    @Test
+    public void checkGetString() throws Exception {
+        testReadSuccessAndFailureException(
+                (res, filter) -> {
+                    filter.stopSendingBlocks();
+                    return res.getString(RES_STRING);
+                },
+                equalTo("true"), instanceOf(Resources.NotFoundException.class));
+    }
+
+    @Test
+    public void checkGetStringArray() throws Exception {
+        testReadSuccessAndFailureException(
+                (res, filter) -> {
+                    filter.stopSendingBlocks();
+                    return res.getStringArray(RES_ARRAY);
+                },
+                equalTo(new String[]{"true"}), instanceOf(Resources.NotFoundException.class));
+    }
+
+    @Test
+    public void checkOpenXmlResourceParser() throws Exception {
+        testReadSuccessAndFailureException(
+                (res, filter) -> {
+                    filter.stopSendingBlocks();
+                    final AssetManager assets = res.getAssets();
+                    try (XmlResourceParser p = assets.openXmlResourceParser(RES_XML_PATH)) {
+                        XmlUtils.beginDocument(p, "Test");
+                        return p.nextText();
+                    }
+                },
+                equalTo("true"), instanceOf(FileNotFoundException.class));
+    }
+
+    @Test
+    public void checkApplyStyle() throws Exception {
+        testReadSuccessAndFailure(
+                (res, filter) -> {
+                    filter.stopSendingBlocks();
+                    final Resources.Theme theme = res.newTheme();
+                    theme.applyStyle(RES_STYLE, true);
+                    final TypedArray values = theme.obtainStyledAttributes(RES_STYLEABLE);
+                    return new String[]{
+                            values.getString(0),
+                            values.getString(1),
+                            values.getString(2),
+                    };
+                },
+                equalTo(new String[]{"true", "true", "1"}),
+                equalTo(new String[]{null, null, null}));
+    }
+
+    @Test
+    public void checkXmlAttributes() throws Exception {
+        testReadSuccessAndFailure(
+                (res, filter) -> {
+                    final AssetManager assets = res.getAssets();
+                    try (XmlResourceParser p = assets.openXmlResourceParser(RES_XML_LARGE_PATH)) {
+                        XmlUtils.beginDocument(p, "Test");
+                        filter.stopSendingBlocks();
+                        final TypedArray values = res.obtainAttributes(p, RES_STYLEABLE);
+                        return new String[]{
+                                values.getString(0),
+                                values.getString(1),
+                                values.getString(2),
+                        };
+                    }
+                },
+                equalTo(new String[]{"true", "true", "1"}),
+                equalTo(new String[]{null, null, null}));
+    }
+
+    @Test
+    public void checkOpen() throws Exception {
+        testReadSuccessAndFailureException(
+                (res, filter) -> {
+                    final AssetManager assets = res.getAssets();
+                    try (InputStream is = assets.openNonAsset(RES_DRAWABLE_PATH)) {
+                        filter.stopSendingBlocks();
+                        ByteArrayOutputStream result = new ByteArrayOutputStream();
+                        writeFullStream(is, result, AssetFileDescriptor.UNKNOWN_LENGTH);
+                        return true;
+                    }
+                }, equalTo(true), instanceOf(IOException.class));
+    }
+
+    @Test
+    public void checkOpenFd() throws Exception {
+        testReadSuccessAndFailureException(
+                (res, filter) -> {
+                    final AssetManager assets = res.getAssets();
+                    try (AssetFileDescriptor fd = assets.openNonAssetFd(RES_DRAWABLE_PATH)) {
+                        filter.stopSendingBlocks();
+                        final ByteArrayOutputStream result = new ByteArrayOutputStream();
+                        writeFullStream(fd.createInputStream(), result,
+                                AssetFileDescriptor.UNKNOWN_LENGTH);
+                        return true;
+                    }
+                }, equalTo(true), instanceOf(IOException.class));
+    }
+
+    private interface ThrowingFunction<R> {
+        R apply(Resources res, BlockFilterController filter) throws Exception;
+    }
+
+    /**
+     * Runs the test twice to test resource resolution when all necessary blocks are available and
+     * when some necessary blocks are missing due to incremental installation.
+     *
+     * During the test of the failure path {@link TestBlockFilter#stopSendingBlocks()} will be
+     * invoked when {@link BlockFilterController#stopSendingBlocks()} is invoked; preventing any
+     * blocks that have not been served from being served during the test of the failure path.
+     *
+     * @param getValue executes resource resolution and returns a T object
+     * @param checkSuccess the matcher that represents the value when all pages are available
+     * @param checkFailure the matcher that represents the value when all pages are missing
+     * @param <T> the expected return type of the resource resolution
+     */
+    private <T> void testReadSuccessAndFailure(ThrowingFunction<T> getValue,
+            Matcher<? super T> checkSuccess, Matcher<? super T> checkFailure) throws Exception {
+        try (ShellInstallSession session = startInstallSession()) {
+            final T value = getValue.apply(session.getPackageResources(),
+                    BlockFilterController.noop());
+            MatcherAssert.assertThat(value, checkSuccess);
+        }
+        try (ShellInstallSession session = startInstallSession()) {
+            final T value = getValue.apply(session.getPackageResources(),
+                    BlockFilterController.allowDisable(session));
+            MatcherAssert.assertThat(value, checkFailure);
+        }
+    }
+
+    /**
+     * Variant of {@link #testReadSuccessAndFailure(ThrowingFunction, Matcher, Matcher)} that
+     * expects an exception to be thrown during the failure path.
+     */
+    private <T> void testReadSuccessAndFailureException(ThrowingFunction<T> getValue,
+            Matcher<? super T> checkSuccess, Matcher<Throwable> checkFailure)
+            throws Exception {
+        try (ShellInstallSession session = startInstallSession()) {
+            final T value = getValue.apply(session.getPackageResources(),
+                    BlockFilterController.noop());
+            MatcherAssert.assertThat(value, checkSuccess);
+        }
+        try (ShellInstallSession session = startInstallSession()) {
+            MatcherUtils.assertThrows(checkFailure,
+                    () -> getValue.apply(session.getPackageResources(),
+                            BlockFilterController.allowDisable(session)));
+        }
+    }
+
+    private static ShellInstallSession startInstallSession() throws IOException,
+            InterruptedException {
+        return startInstallSession(TEST_APKS, TEST_APP_PACKAGE);
+    }
+
+    private static ShellInstallSession startInstallSession(String[] apks, String packageName)
+            throws IOException, InterruptedException {
+        final String v4SignatureSuffix = ".idsig";
+        final TestBlockFilter filter = new TestBlockFilter();
+        final IncrementalInstallSession.Builder builder = new IncrementalInstallSession.Builder()
+                .addExtraArgs("-t", "-i", getContext().getPackageName())
+                .setLogger(new IncrementalDeviceConnection.Logger())
+                .setBlockFilter(filter);
+        for (final String apk : apks) {
+            final String path = TEST_APK_PATH + apk;
+            builder.addApk(Paths.get(path), Paths.get(path + v4SignatureSuffix));
+        }
+
+        final ShellInstallSession session = new ShellInstallSession(
+                builder.build(), filter, packageName);
+        session.session.start(Executors.newSingleThreadExecutor(),
+                IncrementalDeviceConnection.Factory.reliable());
+        session.session.waitForInstallCompleted(10, TimeUnit.SECONDS);
+        assertTrue(isAppInstalled(packageName));
+        return session;
+    }
+
+    private static class BlockFilterController {
+        private final ShellInstallSession mSession;
+        BlockFilterController(ShellInstallSession session) {
+            mSession = session;
+        }
+        public static BlockFilterController allowDisable(ShellInstallSession session) {
+            return new BlockFilterController(session);
+        }
+        public static BlockFilterController noop() {
+            return new BlockFilterController(null);
+        }
+        public void stopSendingBlocks() {
+            if (mSession != null) {
+                mSession.stopSendingBlocks();
+            }
+        }
+    }
+
+    /**
+     * A wrapper for {@link IncrementalInstallSession} that uninstalls the installed package when
+     * testing is finished.
+     */
+    private static class ShellInstallSession implements AutoCloseable {
+        public final IncrementalInstallSession session;
+        private final TestBlockFilter mFilter;
+        private final String mPackageName;
+        private ShellInstallSession(IncrementalInstallSession session,
+                TestBlockFilter filter, String packageName) {
+            this.session = session;
+            this.mFilter = filter;
+            this.mPackageName = packageName;
+            getUiAutomation().adoptShellPermissionIdentity();
+        }
+
+        public void stopSendingBlocks() {
+            mFilter.stopSendingBlocks();
+        }
+
+        public Resources getPackageResources() throws PackageManager.NameNotFoundException {
+            return getContext().createPackageContext(mPackageName, 0).getResources();
+        }
+
+        @Override
+        public void close() throws IOException {
+            session.close();
+            getUiAutomation().dropShellPermissionIdentity();
+            uninstallPackageSilently(mPackageName);
+        }
+    }
+
+    private static class TestBlockFilter implements IBlockFilter {
+        private final AtomicBoolean mDisabled = new AtomicBoolean();
+        @Override
+        public boolean shouldServeBlock(PendingBlock block) {
+            return !mDisabled.get();
+        }
+        public void stopSendingBlocks() {
+            mDisabled.set(true);
+        }
+    }
+
+    private static Context getContext() {
+        return InstrumentationRegistry.getInstrumentation().getContext();
+    }
+
+    private static UiAutomation getUiAutomation() {
+        return InstrumentationRegistry.getInstrumentation().getUiAutomation();
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
index cdbbd09..0c7e676 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
@@ -55,6 +55,7 @@
         Paint paint = new Paint();
         paint.setColor(Color.BLUE);
         paint.setColorFilter(filter);
+        paint.setAntiAlias(false);
         canvas.drawPoint(0, 0, paint);
         ColorUtils.verifyColor(Color.CYAN, bitmap.getPixel(0, 0));
         paint.setColor(Color.GREEN);
diff --git a/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java
index b3dfd3a..da892b8 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java
@@ -60,6 +60,7 @@
         pathPaint.setStyle(Style.STROKE);
         pathPaint.setStrokeWidth(0);
         pathPaint.setPathEffect(effect);
+        pathPaint.setAntiAlias(false);
 
         Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Config.ARGB_8888);
         Canvas canvas = new Canvas(bitmap);
diff --git a/tests/tests/graphics/src/android/graphics/cts/DashPathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/DashPathEffectTest.java
index d1c7889..959f607 100644
--- a/tests/tests/graphics/src/android/graphics/cts/DashPathEffectTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/DashPathEffectTest.java
@@ -62,6 +62,7 @@
         paint.setStrokeWidth(0);
         paint.setColor(FOREGROUND);
         paint.setPathEffect(effect);
+        paint.setAntiAlias(false);
 
         Canvas canvas = new Canvas(bitmap);
         canvas.drawPath(path, paint);
diff --git a/tests/tests/graphics/src/android/graphics/cts/DiscretePathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/DiscretePathEffectTest.java
index e76db8f..6cf975d 100644
--- a/tests/tests/graphics/src/android/graphics/cts/DiscretePathEffectTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/DiscretePathEffectTest.java
@@ -56,6 +56,7 @@
         paint.setStyle(Style.STROKE);
         paint.setStrokeWidth(0);
         paint.setPathEffect(effect);
+        paint.setAntiAlias(false);
 
         Path path = new Path();
         path.moveTo(START_X, COORD_Y);
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
index b1d99f8..b43f77e 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
@@ -371,11 +371,17 @@
     public void testSetAntiAlias() {
         Paint p = new Paint();
 
-        p.setAntiAlias(true);
-        assertTrue(p.isAntiAlias());
-
         p.setAntiAlias(false);
         assertFalse(p.isAntiAlias());
+
+        p.setAntiAlias(true);
+        assertTrue(p.isAntiAlias());
+    }
+
+    @Test
+    public void testDefaultAntiAlias() {
+        Paint p = new Paint();
+        assertTrue(p.isAntiAlias());
     }
 
     @Test
@@ -951,11 +957,17 @@
     public void testSetDither() {
         Paint p = new Paint();
 
-        p.setDither(true);
-        assertTrue(p.isDither());
-
         p.setDither(false);
         assertFalse(p.isDither());
+
+        p.setDither(true);
+        assertTrue(p.isDither());
+    }
+
+    @Test
+    public void testDefaultDither() {
+        Paint p = new Paint();
+        assertTrue(p.isDither());
     }
 
     @Test
@@ -1150,7 +1162,8 @@
 
         p.reset();
         assertEquals(Paint.FILTER_BITMAP_FLAG | Paint.DEV_KERN_TEXT_FLAG
-                    | Paint.EMBEDDED_BITMAP_TEXT_FLAG, p.getFlags());
+                    | Paint.EMBEDDED_BITMAP_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG
+                    | Paint.DITHER_FLAG, p.getFlags());
         assertEquals(null, p.getColorFilter());
         assertEquals(null, p.getMaskFilter());
         assertEquals(null, p.getPathEffect());
diff --git a/tests/tests/graphics/src/android/graphics/cts/PictureTest.java b/tests/tests/graphics/src/android/graphics/cts/PictureTest.java
index e49e933..13ebaf6 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PictureTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PictureTest.java
@@ -141,6 +141,7 @@
         // GREEN rectangle covering the entire canvas
         paint.setColor(Color.GREEN);
         paint.setStyle(Style.FILL);
+        paint.setAntiAlias(false);
         canvas.drawRect(0, 0, TEST_WIDTH, TEST_HEIGHT, paint);
         // horizontal red line starting from (0,0); overwrites first line of the rectangle
         paint.setColor(Color.RED);
diff --git a/tests/tests/graphics/src/android/graphics/cts/SumPathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/SumPathEffectTest.java
index 207f74e6..e6ba859 100644
--- a/tests/tests/graphics/src/android/graphics/cts/SumPathEffectTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/SumPathEffectTest.java
@@ -60,6 +60,7 @@
         paint.setPathEffect(first);
         paint.setStyle(Paint.Style.STROKE);
         paint.setStrokeWidth(0); // 1-pixel hairline
+        paint.setAntiAlias(false);
         canvas.drawPath(path, paint);
 
         PathEffect second = new DashPathEffect(new float[] { 10, 5 }, 5);
diff --git a/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java b/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java
index 8b26b5b..f7db74a 100644
--- a/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageManager;
@@ -75,6 +76,7 @@
     private FeatureInfo mVulkanHardwareLevel = null;
     private FeatureInfo mVulkanHardwareVersion = null;
     private FeatureInfo mVulkanHardwareCompute = null;
+    private JSONObject mVkJSON = null;
     private JSONObject mVulkanDevices[];
     private JSONObject mBestDevice = null;
 
@@ -103,7 +105,8 @@
             }
         }
 
-        mVulkanDevices = getVulkanDevices();
+        mVkJSON = new JSONObject(nativeGetVkJSON());
+        mVulkanDevices = getVulkanDevices(mVkJSON);
         mBestDevice = getBestDevice();
     }
     @CddTest(requirement = "7.1.4.2/C-1-1,C-2-1")
@@ -199,7 +202,7 @@
                 VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME +
                 " (version >= " + VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION +
                 ")",
-                hasExtension(mBestDevice,
+                hasDeviceExtension(mBestDevice,
                     VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
                     VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION));
         assertTrue("Devices with Vulkan 1.1 must support SYNC_FD external semaphores",
@@ -212,6 +215,17 @@
                     "externalFenceFeatures", 0x3 /* importable + exportable */));
     }
 
+    @CddTest(requirement = "7.1.4.2/C-1-7")
+    @Test
+    public void testVulkanRequiredExtensions() throws JSONException {
+        assumeTrue("Skipping because Vulkan is not supported", mVulkanDevices.length > 0);
+
+        assertVulkanInstanceExtension("VK_KHR_surface", 25);
+        assertVulkanInstanceExtension("VK_KHR_android_surface", 6);
+        assertVulkanDeviceExtension("VK_KHR_swapchain", 68);
+        assertVulkanDeviceExtension("VK_KHR_incremental_present", 1);
+    }
+
     @CddTest(requirement = "7.9.2/C-1-5")
     @Test
     public void testVulkanVersionForVrHighPerformance() {
@@ -230,7 +244,7 @@
             assertTrue("Device - " + device.getJSONObject("properties").getString("deviceName")
                             + " supports extension " + VK_KHR_PERFORMANCE_QUERY
                             + ". It is blocked and hence should not be supported",
-                    !hasExtension(device, VK_KHR_PERFORMANCE_QUERY, 0));
+                    !hasDeviceExtension(device, VK_KHR_PERFORMANCE_QUERY, 0));
         }
     }
 
@@ -364,9 +378,46 @@
         return false;
     }
 
-    private boolean hasExtension(JSONObject device, String name, int minVersion)
+    private void assertVulkanDeviceExtension(final String name, final int minVersion)
             throws JSONException {
-        JSONArray extensions = device.getJSONArray("extensions");
+        assertTrue(
+                String.format(
+                        "Devices with Vulkan must support device extension %s (version >= %d)",
+                        name,
+                        minVersion),
+                hasDeviceExtension(mBestDevice, name, minVersion));
+    }
+
+    private void assertVulkanInstanceExtension(final String name, final int minVersion)
+            throws JSONException {
+        assertTrue(
+                String.format(
+                        "Devices with Vulkan must support instance extension %s (version >= %d)",
+                        name,
+                        minVersion),
+                hasInstanceExtension(name, minVersion));
+    }
+
+    private static boolean hasDeviceExtension(
+            final JSONObject device,
+            final String name,
+            final int minVersion) throws JSONException {
+        final JSONArray deviceExtensions = device.getJSONArray("extensions");
+        return hasExtension(deviceExtensions, name, minVersion);
+    }
+
+    private boolean hasInstanceExtension(
+            final String name,
+            final int minVersion) throws JSONException {
+        // Instance extensions are in the top-level vkjson object.
+        final JSONArray instanceExtensions = mVkJSON.getJSONArray("extensions");
+        return hasExtension(instanceExtensions, name, minVersion);
+    }
+
+    private static boolean hasExtension(
+            final JSONArray extensions,
+            final String name,
+            final int minVersion) throws JSONException {
         for (int i = 0; i < extensions.length(); i++) {
             JSONObject ext = extensions.getJSONObject(i);
             if (ext.getString("extensionName").equals(name) &&
@@ -391,11 +442,11 @@
 
     private static native String nativeGetVkJSON();
 
-    private JSONObject[] getVulkanDevices() throws JSONException, UnsupportedEncodingException {
-        JSONArray vkjson = (new JSONObject(nativeGetVkJSON())).getJSONArray("devices");
-        JSONObject[] devices = new JSONObject[vkjson.length()];
-        for (int i = 0; i < vkjson.length(); i++) {
-            devices[i] = vkjson.getJSONObject(i);
+    private static JSONObject[] getVulkanDevices(final JSONObject vkJSON) throws JSONException {
+        JSONArray devicesArray = vkJSON.getJSONArray("devices");
+        JSONObject[] devices = new JSONObject[devicesArray.length()];
+        for (int i = 0; i < devicesArray.length(); i++) {
+            devices[i] = devicesArray.getJSONObject(i);
         }
         return devices;
     }
diff --git a/tests/tests/libnativehelper/OWNERS b/tests/tests/libnativehelper/OWNERS
index da3f4a8..8d9029d 100644
--- a/tests/tests/libnativehelper/OWNERS
+++ b/tests/tests/libnativehelper/OWNERS
@@ -1,5 +1,4 @@
 # Bug component: 86431
-enh@google.com
 mast@google.com
 ngeoffray@google.com
 oth@google.com
diff --git a/tests/tests/media/src/android/media/cts/AudioModeListenerTest.java b/tests/tests/media/src/android/media/cts/AudioModeListenerTest.java
index 5818d5a..e222e28 100644
--- a/tests/tests/media/src/android/media/cts/AudioModeListenerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioModeListenerTest.java
@@ -18,6 +18,7 @@
 
 import android.content.pm.PackageManager;
 import android.media.AudioManager;
+import android.platform.test.annotations.AppModeFull;
 import android.util.Log;
 
 import androidx.test.filters.SdkSuppress;
@@ -95,6 +96,7 @@
         }
     }
 
+    @AppModeFull(reason = "Instant apps don't have MODIFY_AUDIO_SETTINGS")
     public void testModeListener() throws Exception {
         if (!isValidPlatform("testModeListener")) return;
 
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index 82366ae..35597b1 100755
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -32,6 +32,7 @@
 import android.media.AudioMetadata;
 import android.media.AudioMetadataReadMap;
 import android.media.AudioPresentation;
+import android.media.AudioSystem;
 import android.media.AudioTimestamp;
 import android.media.AudioTrack;
 import android.media.PlaybackParams;
@@ -1856,6 +1857,117 @@
         Thread.sleep(waitMsec); // wait for release to complete
     }
 
+    private void playOnceStreamByteBuffer(
+            String testName, double testFrequency, double testSweep,
+            int testStreamType, int testSampleRate, int testChannelMask, int testEncoding,
+            int testTransferMode, int testWriteMode,
+            boolean useChannelIndex, boolean useDirect) throws Exception {
+        AudioTrack track = null;
+        try {
+            AudioFormat.Builder afb = new AudioFormat.Builder()
+                    .setEncoding(testEncoding)
+                    .setSampleRate(testSampleRate);
+            if (useChannelIndex) {
+                afb.setChannelIndexMask(testChannelMask);
+            } else {
+                afb.setChannelMask(testChannelMask);
+            }
+            final AudioFormat format = afb.build();
+            final int frameSize = AudioHelper.frameSizeFromFormat(format);
+            final int frameCount =
+                    AudioHelper.frameCountFromMsec(300 /* ms */, format);
+            final int bufferSize = frameCount * frameSize;
+            final int bufferSamples = frameCount * format.getChannelCount();
+
+            track = new AudioTrack.Builder()
+                    .setAudioFormat(format)
+                    .setTransferMode(testTransferMode)
+                    .setBufferSizeInBytes(bufferSize)
+                    .build();
+
+            assertEquals(testName + ": state",
+                    AudioTrack.STATE_INITIALIZED, track.getState());
+            assertEquals(testName + ": sample rate",
+                    testSampleRate, track.getSampleRate());
+            assertEquals(testName + ": encoding",
+                    testEncoding, track.getAudioFormat());
+
+            ByteBuffer bb = useDirect
+                    ? ByteBuffer.allocateDirect(bufferSize)
+                    : ByteBuffer.allocate(bufferSize);
+            bb.order(java.nio.ByteOrder.nativeOrder());
+
+            final double sampleFrequency = testFrequency / format.getChannelCount();
+            switch (testEncoding) {
+                case AudioFormat.ENCODING_PCM_8BIT: {
+                    byte data[] = AudioHelper.createSoundDataInByteArray(
+                            bufferSamples, testSampleRate,
+                            sampleFrequency, testSweep);
+                    bb.put(data);
+                    bb.flip();
+                }
+                break;
+                case AudioFormat.ENCODING_PCM_16BIT: {
+                    short data[] = AudioHelper.createSoundDataInShortArray(
+                            bufferSamples, testSampleRate,
+                            sampleFrequency, testSweep);
+                    ShortBuffer sb = bb.asShortBuffer();
+                    sb.put(data);
+                    bb.limit(sb.limit() * 2);
+                }
+                break;
+                case AudioFormat.ENCODING_PCM_FLOAT: {
+                    float data[] = AudioHelper.createSoundDataInFloatArray(
+                            bufferSamples, testSampleRate,
+                            sampleFrequency, testSweep);
+                    FloatBuffer fb = bb.asFloatBuffer();
+                    fb.put(data);
+                    bb.limit(fb.limit() * 4);
+                }
+                break;
+            }
+            // start the AudioTrack
+            // This can be done before or after the first write.
+            // Current behavior for streaming tracks is that
+            // actual playback does not begin before the internal
+            // data buffer is completely full.
+            track.play();
+
+            // write data
+            final long startTime = System.currentTimeMillis();
+            final long maxDuration = frameCount * 1000 / testSampleRate + 1000;
+            for (int written = 0; written < bufferSize; ) {
+                // ret may return a short count if write
+                // is non blocking or even if write is blocking
+                // when a stop/pause/flush is issued from another thread.
+                final int kBatchFrames = 1000;
+                int ret = track.write(bb,
+                        Math.min(bufferSize - written, frameSize * kBatchFrames),
+                        testWriteMode);
+                // for non-blocking mode, this loop may spin quickly
+                assertTrue(testName + ": write error " + ret, ret >= 0);
+                assertTrue(testName + ": write timeout",
+                        (System.currentTimeMillis() - startTime) <= maxDuration);
+                written += ret;
+            }
+
+            // for streaming tracks, stop will allow the rest of the data to
+            // drain out, but we don't know how long to wait unless
+            // we check the position before stop. if we check position
+            // after we stop, we read 0.
+            final int position = track.getPlaybackHeadPosition();
+            final int remainingTimeMs = (int)((double)(frameCount - position)
+                    * 1000 / testSampleRate);
+            track.stop();
+            Thread.sleep(remainingTimeMs);
+            Thread.sleep(WAIT_MSEC);
+        } finally {
+            if (track != null) {
+                track.release();
+            }
+        }
+    }
+
     @Test
     public void testPlayStreamByteBuffer() throws Exception {
         // constants for test
@@ -1877,7 +1989,7 @@
         };
         final int TEST_MODE = AudioTrack.MODE_STREAM;
         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
-        final float TEST_SWEEP = 0; // sine wave only
+        final double TEST_SWEEP = 0; // sine wave only
 
         for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
             double frequency = 800; // frequency changes for each test
@@ -1885,76 +1997,14 @@
                 for (int TEST_CONF : TEST_CONF_ARRAY) {
                     for (int TEST_WRITE_MODE : TEST_WRITE_MODE_ARRAY) {
                         for (int useDirect = 0; useDirect < 2; ++useDirect) {
-                            // -------- initialization --------------
-                            int minBufferSize = AudioTrack.getMinBufferSize(TEST_SR,
-                                    TEST_CONF, TEST_FORMAT); // in bytes
-                            int bufferSize = 12 * minBufferSize;
-                            int bufferSamples = bufferSize
-                                    / AudioFormat.getBytesPerSample(TEST_FORMAT);
+                            playOnceStreamByteBuffer(TEST_NAME, frequency, TEST_SWEEP,
+                                    TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+                                    TEST_MODE, TEST_WRITE_MODE,
+                                    false /* useChannelIndex */, useDirect != 0);
 
-                            // create audio track and confirm settings
-                            AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR,
-                                    TEST_CONF, TEST_FORMAT, minBufferSize, TEST_MODE);
-                            assertEquals(TEST_NAME + ": state",
-                                    AudioTrack.STATE_INITIALIZED, track.getState());
-                            assertEquals(TEST_NAME + ": sample rate",
-                                    TEST_SR, track.getSampleRate());
-                            assertEquals(TEST_NAME + ": channel mask",
-                                    TEST_CONF, track.getChannelConfiguration());
-                            assertEquals(TEST_NAME + ": encoding",
-                                    TEST_FORMAT, track.getAudioFormat());
-
-                            ByteBuffer bb = (useDirect == 1)
-                                    ? ByteBuffer.allocateDirect(bufferSize)
-                                            : ByteBuffer.allocate(bufferSize);
-                            bb.order(java.nio.ByteOrder.nativeOrder());
-
-                            // -------- test --------------
-                            switch (TEST_FORMAT) {
-                                case AudioFormat.ENCODING_PCM_8BIT: {
-                                    byte data[] = AudioHelper.createSoundDataInByteArray(
-                                            bufferSamples, TEST_SR,
-                                            frequency, TEST_SWEEP);
-                                    bb.put(data);
-                                    bb.flip();
-                                } break;
-                                case AudioFormat.ENCODING_PCM_16BIT: {
-                                    short data[] = AudioHelper.createSoundDataInShortArray(
-                                            bufferSamples, TEST_SR,
-                                            frequency, TEST_SWEEP);
-                                    ShortBuffer sb = bb.asShortBuffer();
-                                    sb.put(data);
-                                    bb.limit(sb.limit() * 2);
-                                } break;
-                                case AudioFormat.ENCODING_PCM_FLOAT: {
-                                    float data[] = AudioHelper.createSoundDataInFloatArray(
-                                            bufferSamples, TEST_SR,
-                                            frequency, TEST_SWEEP);
-                                    FloatBuffer fb = bb.asFloatBuffer();
-                                    fb.put(data);
-                                    bb.limit(fb.limit() * 4);
-                                } break;
-                            }
-
-                            boolean hasPlayed = false;
-                            int written = 0;
-                            while (written < bufferSize) {
-                                int ret = track.write(bb,
-                                        Math.min(bufferSize - written, minBufferSize),
-                                        TEST_WRITE_MODE);
-                                assertTrue(TEST_NAME, ret >= 0);
-                                written += ret;
-                                if (!hasPlayed) {
-                                    track.play();
-                                    hasPlayed = true;
-                                }
-                            }
-
-                            track.stop();
-                            Thread.sleep(WAIT_MSEC);
-                            // -------- tear down --------------
-                            track.release();
-                            frequency += 200; // increment test tone frequency
+                            // add a gap to make tones distinct
+                            Thread.sleep(100 /* millis */);
+                            frequency += 30; // increment test tone frequency
                         }
                     }
                 }
@@ -1992,7 +2042,9 @@
                 AudioTrack.WRITE_BLOCKING,
                 AudioTrack.WRITE_NON_BLOCKING,
         };
-        final float TEST_SWEEP = 0;
+        final double TEST_SWEEP = 0;
+        final int TEST_MODE = AudioTrack.MODE_STREAM;
+        final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
 
         for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
             for (int TEST_CONF : TEST_CONF_ARRAY) {
@@ -2000,93 +2052,14 @@
                 for (int TEST_SR : TEST_SR_ARRAY) {
                     for (int TEST_WRITE_MODE : TEST_WRITE_MODE_ARRAY) {
                         for (int useDirect = 0; useDirect < 2; ++useDirect) {
-                            AudioFormat format = new AudioFormat.Builder()
-                                    .setEncoding(TEST_FORMAT)
-                                    .setSampleRate(TEST_SR)
-                                    .setChannelIndexMask(TEST_CONF)
-                                    .build();
-                            AudioTrack track = new AudioTrack.Builder()
-                                    .setAudioFormat(format)
-                                    .build();
-                            assertEquals(TEST_NAME,
-                                    AudioTrack.STATE_INITIALIZED, track.getState());
+                            playOnceStreamByteBuffer(TEST_NAME, frequency, TEST_SWEEP,
+                                    TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+                                    TEST_MODE, TEST_WRITE_MODE,
+                                    true /* useChannelIndex */, useDirect != 0);
 
-                            // create the byte buffer and fill with test data
-                            final int frameSize = AudioHelper.frameSizeFromFormat(format);
-                            final int frameCount =
-                                    AudioHelper.frameCountFromMsec(300 /* ms */, format);
-                            final int bufferSize = frameCount * frameSize;
-                            final int bufferSamples = frameCount * format.getChannelCount();
-                            ByteBuffer bb = (useDirect == 1)
-                                    ? ByteBuffer.allocateDirect(bufferSize)
-                                            : ByteBuffer.allocate(bufferSize);
-                            bb.order(java.nio.ByteOrder.nativeOrder());
-
-                            switch (TEST_FORMAT) {
-                            case AudioFormat.ENCODING_PCM_8BIT: {
-                                byte data[] = AudioHelper.createSoundDataInByteArray(
-                                        bufferSamples, TEST_SR,
-                                        frequency, TEST_SWEEP);
-                                bb.put(data);
-                                bb.flip();
-                            } break;
-                            case AudioFormat.ENCODING_PCM_16BIT: {
-                                short data[] = AudioHelper.createSoundDataInShortArray(
-                                        bufferSamples, TEST_SR,
-                                        frequency, TEST_SWEEP);
-                                ShortBuffer sb = bb.asShortBuffer();
-                                sb.put(data);
-                                bb.limit(sb.limit() * 2);
-                            } break;
-                            case AudioFormat.ENCODING_PCM_FLOAT: {
-                                float data[] = AudioHelper.createSoundDataInFloatArray(
-                                        bufferSamples, TEST_SR,
-                                        frequency, TEST_SWEEP);
-                                FloatBuffer fb = bb.asFloatBuffer();
-                                fb.put(data);
-                                bb.limit(fb.limit() * 4);
-                            } break;
-                            }
-
-                            // start the AudioTrack
-                            // This can be done before or after the first write.
-                            // Current behavior for streaming tracks is that
-                            // actual playback does not begin before the internal
-                            // data buffer is completely full.
-                            track.play();
-
-                            // write data
-                            final long startTime = System.currentTimeMillis();
-                            final long maxDuration = frameCount * 1000 / TEST_SR + 1000;
-                            for (int written = 0; written < bufferSize; ) {
-                                // ret may return a short count if write
-                                // is non blocking or even if write is blocking
-                                // when a stop/pause/flush is issued from another thread.
-                                final int kBatchFrames = 1000;
-                                int ret = track.write(bb,
-                                        Math.min(bufferSize - written, frameSize * kBatchFrames),
-                                        TEST_WRITE_MODE);
-                                // for non-blocking mode, this loop may spin quickly
-                                assertTrue(TEST_NAME + ": write error " + ret, ret >= 0);
-                                assertTrue(TEST_NAME + ": write timeout",
-                                        (System.currentTimeMillis() - startTime) <= maxDuration);
-                                written += ret;
-                            }
-
-                            // for streaming tracks, stop will allow the rest of the data to
-                            // drain out, but we don't know how long to wait unless
-                            // we check the position before stop. if we check position
-                            // after we stop, we read 0.
-                            final int position = track.getPlaybackHeadPosition();
-                            final int remainingTimeMs = (int)((double)(frameCount - position)
-                                    * 1000 / TEST_SR);
-                            track.stop();
-                            Thread.sleep(remainingTimeMs);
-                            // tear down
-                            track.release();
                             // add a gap to make tones distinct
                             Thread.sleep(100 /* millis */);
-                            frequency += 200; // increment test tone frequency
+                            frequency += 30; // increment test tone frequency
                         }
                     }
                 }
@@ -3198,6 +3171,99 @@
         });
     }
 
+    /**
+     * Tests height channel masks and higher channel counts
+     * used in immersive AudioTrack streaming.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testImmersiveStreaming() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
+
+        final String TEST_NAME = "testImmersiveStreaming";
+        final int TEST_FORMAT_ARRAY[] = {
+            AudioFormat.ENCODING_PCM_16BIT,
+            AudioFormat.ENCODING_PCM_FLOAT,
+        };
+        final int TEST_SR_ARRAY[] = {
+            48000,  // do not set too high - costly in memory.
+        };
+        final int TEST_CONF_ARRAY[] = {
+            AudioFormat.CHANNEL_OUT_5POINT1POINT2, // 8 ch (includes height channels vs 7.1).
+            AudioFormat.CHANNEL_OUT_7POINT1POINT4, // 12 ch
+            AudioFormat.CHANNEL_OUT_22POINT2,      // 24 ch
+        };
+
+        final int TEST_MODE = AudioTrack.MODE_STREAM;
+        final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+        final float TEST_SWEEP = 0; // sine wave only
+        final boolean TEST_IS_LOW_RAM_DEVICE = false;
+        for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
+            double frequency = 400; // Note: frequency changes for each test
+            for (int TEST_SR : TEST_SR_ARRAY) {
+                for (int TEST_CONF : TEST_CONF_ARRAY) {
+                    if (AudioFormat.channelCountFromOutChannelMask(TEST_CONF)
+                            > AudioSystem.OUT_CHANNEL_COUNT_MAX) {
+                        continue; // Skip if the channel count exceeds framework capabilities.
+                    }
+                    playOnceStreamData(TEST_NAME, TEST_MODE, TEST_STREAM_TYPE, TEST_SWEEP,
+                            TEST_IS_LOW_RAM_DEVICE, TEST_FORMAT, frequency, TEST_SR, TEST_CONF,
+                            WAIT_MSEC);
+                    frequency += 50; // increment test tone frequency
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testImmersiveChannelIndex() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
+
+        final String TEST_NAME = "testImmersiveChannelIndex";
+        final int TEST_FORMAT_ARRAY[] = {
+                AudioFormat.ENCODING_PCM_FLOAT,
+        };
+        final int TEST_SR_ARRAY[] = {
+                48000,  // do not set too high - costly in memory.
+        };
+        final int MAX_CHANNEL_BIT = 1 << (AudioSystem.FCC_24 - 1); // highest allowed channel.
+        final int TEST_CONF_ARRAY[] = {
+                (1 << AudioSystem.OUT_CHANNEL_COUNT_MAX) - 1,
+                MAX_CHANNEL_BIT,      // likely silent - no physical device on top channel.
+                MAX_CHANNEL_BIT | 1,  // first channel will likely have physical device.
+        };
+        final int TEST_WRITE_MODE_ARRAY[] = {
+                AudioTrack.WRITE_BLOCKING,
+                AudioTrack.WRITE_NON_BLOCKING,
+        };
+        final double TEST_SWEEP = 0;
+        final int TEST_TRANSFER_MODE = AudioTrack.MODE_STREAM;
+        final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+        double frequency = 200; // frequency changes for each test
+        for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
+            for (int TEST_CONF : TEST_CONF_ARRAY) {
+                for (int TEST_SR : TEST_SR_ARRAY) {
+                    for (int TEST_WRITE_MODE : TEST_WRITE_MODE_ARRAY) {
+                        for (int useDirect = 0; useDirect < 2; ++useDirect) {
+                            playOnceStreamByteBuffer(
+                                    TEST_NAME, frequency, TEST_SWEEP,
+                                    TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+                                    TEST_TRANSFER_MODE, TEST_WRITE_MODE,
+                                    true /* useChannelIndex */, useDirect != 0);
+                            frequency += 30; // increment test tone frequency
+                        }
+                    }
+                }
+            }
+        }
+    }
+
 /* 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/os/src/android/os/cts/AppHibernationIntegrationTest.kt b/tests/tests/os/src/android/os/cts/AppHibernationIntegrationTest.kt
index 7b0539f..72b98cf 100644
--- a/tests/tests/os/src/android/os/cts/AppHibernationIntegrationTest.kt
+++ b/tests/tests/os/src/android/os/cts/AppHibernationIntegrationTest.kt
@@ -23,6 +23,7 @@
 import android.content.pm.PackageManager
 import android.os.Build
 import android.net.Uri
+import android.platform.test.annotations.AppModeFull
 import android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION
 import android.provider.Settings
 import android.support.test.uiautomator.By
@@ -133,6 +134,7 @@
         }
     }
 
+    @AppModeFull(reason = "Uses application details settings")
     @Test
     fun testAppInfo_RemovePermissionsAndFreeUpSpaceToggleExists() {
         withDeviceConfig(NAMESPACE_APP_HIBERNATION, "app_hibernation_enabled", "true") {
diff --git a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
index 226c528..35b56ce 100644
--- a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
+++ b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
@@ -138,9 +138,17 @@
 
                 // Verify
                 assertPermission(PERMISSION_DENIED)
-                runShellCommandOrThrow("cmd statusbar expand-notifications")
+                if (hasFeatureWatch()) {
+                    expandNotificationsWatch()
+                } else {
+                    runShellCommandOrThrow("cmd statusbar expand-notifications")
+                }
                 waitFindObject(By.textContains("unused app"))
                         .click()
+                if (hasFeatureWatch()) {
+                    // In wear os, notification has one additional button to open it
+                    waitFindObject(By.text("Open")).click();
+                }
                 waitFindObject(By.text(supportedAppPackageName))
                 waitFindObject(By.text("Calendar permission removed"))
             }
@@ -406,6 +414,15 @@
         return context.packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)
     }
 
+    private fun expandNotificationsWatch() {
+        with(uiDevice) {
+            wakeUp()
+            // Swipe up from bottom to reveal notifications
+            val x = displayWidth / 2
+            swipe(x, displayHeight, x, 0, 1)
+        }
+    }
+
     private fun assertAllowlistState(state: Boolean) {
         assertThat(
             waitFindObject(By.textStartsWith("Auto-revoke allowlisted: ")).text,
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/DenyInstallationTestWatch.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/DenyInstallationTestWatch.kt
new file mode 100644
index 0000000..9cdb8b9
--- /dev/null
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/DenyInstallationTestWatch.kt
@@ -0,0 +1,110 @@
+/*
+ * 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.packageinstaller.install.cts
+
+import android.app.Activity
+import android.os.Build
+import android.platform.test.annotations.AppModeFull
+import android.support.test.uiautomator.By
+import android.support.test.uiautomator.BySelector
+import android.support.test.uiautomator.UiDevice
+import android.support.test.uiautomator.Until
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.concurrent.TimeUnit
+
+private const val ERROR_MESSAGE_ID = "android:id/message"
+private const val OK_BUTTON_ID = "button1"
+
+@AppModeFull(reason = "Instant apps cannot create installer sessions")
+@RunWith(AndroidJUnit4::class)
+class DenyInstallationTestWatch : PackageInstallerTestBase() {
+
+    private val instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val uiDevice = UiDevice.getInstance(instrumentation)
+
+    /**
+     * Check that apps cannot be installed on watches via a package-installer session
+     */
+    @Test
+    fun confirmSessionInstallationFails() {
+        assumeWatch()
+
+        val installation = startInstallationViaSession()
+        assertWearErrorDialogShown("Install blocking dialog not shown for install via session")
+
+        // Install confirm dialog returns 'canceled' after getting dismissed
+        assertEquals(Activity.RESULT_CANCELED, installation.get(TIMEOUT, TimeUnit.MILLISECONDS))
+
+        // Make sure app is not installed
+        assertNotInstalled()
+    }
+
+    /**
+     * Check that apps cannot be installed on watches via a package-installer intent
+     */
+    @Test
+    fun confirmIntentInstallationFails() {
+        assumeWatch()
+
+        val installation = startInstallationViaIntent()
+        assertWearErrorDialogShown("Install blocking dialog not shown for install via intent")
+
+        // Install confirm dialog returns 'canceled' after getting dismissed
+        assertEquals(Activity.RESULT_CANCELED, installation.get(TIMEOUT, TimeUnit.MILLISECONDS))
+
+        // Make sure app is not installed
+        assertNotInstalled()
+    }
+
+    /**
+     * Test suite will need to be updated for S, this test checks this fact.
+     */
+    @Test
+    fun confirmPlatformVersionLessThanS() {
+        assumeWatch()
+
+        assertTrue(
+            "Must revisit method for Apk blocking for watches using Android S+, see b/187944296",
+            Build.VERSION.SDK_INT <= Build.VERSION_CODES.R
+        )
+    }
+
+    /**
+     * Click the Ok button in the alert dialog blocking installation
+     */
+    private fun clickOkButton() {
+        uiDevice.wait(Until.findObject(By.res(SYSTEM_PACKAGE_NAME, OK_BUTTON_ID)), TIMEOUT)
+            .click()
+    }
+
+    private fun assertUiObject(errorMessage: String, selector: BySelector) {
+        Assert.assertNotNull(
+            "$errorMessage after $TIMEOUT ms",
+            uiDevice.wait(Until.findObject(selector), TIMEOUT)
+        )
+    }
+
+    private fun assertWearErrorDialogShown(errorMessage: String) {
+        assertUiObject(errorMessage, By.res(ERROR_MESSAGE_ID))
+        clickOkButton()
+    }
+}
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExcludeWatch.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExcludeWatch.kt
new file mode 100644
index 0000000..20cba14
--- /dev/null
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExcludeWatch.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.packageinstaller.install.cts
+
+import android.content.pm.PackageManager
+import org.junit.Assume.assumeFalse
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+class ExcludeWatch(
+    val motivation: String,
+    val packageManager: PackageManager
+) : TestRule {
+
+    override fun apply(stmt: Statement?, desc: Description?): Statement {
+        return FeatureStatement()
+    }
+
+    inner class FeatureStatement : Statement() {
+        override fun evaluate() {
+            assumeFalse(
+                motivation,
+                packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)
+            )
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExternalSourcesTestAppOpAllowed.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExternalSourcesTestAppOpAllowed.kt
index 3e7cd4a..bdb4b20 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExternalSourcesTestAppOpAllowed.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExternalSourcesTestAppOpAllowed.kt
@@ -75,11 +75,13 @@
 
     @Test
     fun allowedSourceTestViaIntent() {
+        assumeNotWatch()
         allowedSourceTest { startInstallationViaIntent() }
     }
 
     @Test
     fun allowedSourceTestViaSession() {
+        assumeNotWatch()
         allowedSourceTest { startInstallationViaSession() }
     }
 
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/InstallSourceInfoTest.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/InstallSourceInfoTest.kt
index 42fddd8..5396efc 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/InstallSourceInfoTest.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/InstallSourceInfoTest.kt
@@ -40,6 +40,8 @@
 
     @Test
     fun installViaIntent() {
+        assumeNotWatch()
+
         val packageInstallerPackageName = getPackageInstallerPackageName()
 
         val installation = startInstallationViaIntent()
@@ -56,6 +58,8 @@
 
     @Test
     fun InstallViaSession() {
+        assumeNotWatch()
+
         startInstallationViaSession()
         clickInstallerUIButton(INSTALL_BUTTON_ID)
 
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt
index 33a8966..2220893 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt
@@ -49,6 +49,8 @@
      */
     @Test
     fun confirmInstallation() {
+        assumeNotWatch()
+
         val installation = startInstallationViaIntent()
         clickInstallerUIButton(INSTALL_BUTTON_ID)
 
@@ -63,6 +65,8 @@
      */
     @Test
     fun cancelInstallation() {
+        assumeNotWatch()
+
         val installation = startInstallationViaIntent()
         clickInstallerUIButton(CANCEL_BUTTON_ID)
 
@@ -76,6 +80,8 @@
      */
     @Test
     fun reinstallViaPackageUri() {
+        assumeNotWatch()
+
         // Regular install
         confirmInstallation()
 
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/PackageInstallerTestBase.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/PackageInstallerTestBase.kt
index f006c1b..6fc29db 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/PackageInstallerTestBase.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/PackageInstallerTestBase.kt
@@ -41,6 +41,8 @@
 import com.android.compatibility.common.util.FutureResultActivity
 import org.junit.After
 import org.junit.Assert
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
 import org.junit.Before
 import org.junit.Rule
 import java.io.File
@@ -227,4 +229,16 @@
     fun uninstallTestPackage() {
         uiDevice.executeShellCommand("pm uninstall $TEST_APK_PACKAGE_NAME")
     }
+
+    fun assumeWatch() {
+        assumeTrue("Test only valid for watch", hasFeatureWatch())
+    }
+
+    fun assumeNotWatch() {
+        assumeFalse("Installing APKs not supported on watch", hasFeatureWatch())
+    }
+
+    private fun hasFeatureWatch(): Boolean {
+        return pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
+    }
 }
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/SessionTest.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/SessionTest.kt
index 8df0c6b..e81f1d1 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/SessionTest.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/SessionTest.kt
@@ -27,6 +27,7 @@
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertTrue
 import org.junit.Assert.fail
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import java.util.concurrent.TimeUnit
@@ -40,6 +41,9 @@
     private val context = InstrumentationRegistry.getTargetContext()
     private val pm = context.packageManager
 
+    @get:Rule
+    val excludeWatch = ExcludeWatch("Installing APKs not supported on watch", pm)
+
     /**
      * Check that we can install an app via a package-installer session
      */
diff --git a/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt
index 0c59dc5..a7b4709 100644
--- a/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt
@@ -127,6 +127,11 @@
         return UiAutomatorUtils.waitFindObject(selector, timeoutMillis)
     }
 
+    protected fun waitFindObjectOrNull(selector: BySelector, timeoutMillis: Long): UiObject2? {
+        waitForIdle()
+        return UiAutomatorUtils.waitFindObjectOrNull(selector, timeoutMillis)
+    }
+
     protected fun click(selector: BySelector, timeoutMillis: Long = 20_000) {
         waitFindObject(selector, timeoutMillis).click()
         waitForIdle()
diff --git a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
index 9b229f6..07245ec 100644
--- a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
@@ -157,7 +157,7 @@
         click(By.res("android:id/button1"))
 
     protected fun clickPermissionReviewContinue() {
-        if (isAutomotive) {
+        if (isAutomotive || isWatch) {
             click(By.text(getPermissionControllerString("review_button_continue")))
         } else {
             click(By.res("com.android.permissioncontroller:id/continue_button"))
@@ -165,7 +165,7 @@
     }
 
     protected fun clickPermissionReviewCancel() {
-        if (isAutomotive) {
+        if (isAutomotive || isWatch) {
             click(By.text(getPermissionControllerString("review_button_cancel")))
         } else {
             click(By.res("com.android.permissioncontroller:id/cancel_button"))
@@ -296,7 +296,7 @@
     }
 
     protected fun clickAllowAlwaysInSettings() {
-        if (isAutomotive || isTv) {
+        if (isAutomotive || isTv || isWatch) {
             click(By.text(getPermissionControllerString("app_permission_button_allow_always")))
         } else {
             click(By.res("com.android.permissioncontroller:id/allow_always_radio_button"))
@@ -313,7 +313,7 @@
     }
 
     protected fun clickPermissionRequestDenyButton() {
-        if (isAutomotive) {
+        if (isAutomotive || isWatch) {
             click(By.text(getPermissionControllerString(DENY_BUTTON_TEXT)))
         } else {
             click(By.res(DENY_BUTTON))
@@ -322,7 +322,7 @@
 
     protected fun clickPermissionRequestSettingsLinkAndDeny() {
         clickPermissionRequestSettingsLink()
-        if (isAutomotive) {
+        if (isAutomotive || isWatch) {
             click(By.text(getPermissionControllerString("app_permission_button_deny")))
         } else {
             click(By.res("com.android.permissioncontroller:id/deny_radio_button"))
@@ -356,14 +356,23 @@
     protected fun clickPermissionRequestDenyAndDontAskAgainButton() {
         if (isAutomotive) {
             click(By.text(getPermissionControllerString(DENY_AND_DONT_ASK_AGAIN_BUTTON_TEXT)))
+        } else if (isWatch) {
+            click(By.text(getPermissionControllerString(DENY_BUTTON_TEXT)))
         } else {
             click(By.res(DENY_AND_DONT_ASK_AGAIN_BUTTON))
         }
     }
 
     // Only used in TV and Watch form factors
-    protected fun clickPermissionRequestDontAskAgainButton() =
-        click(By.res("com.android.permissioncontroller:id/permission_deny_dont_ask_again_button"))
+    protected fun clickPermissionRequestDontAskAgainButton() {
+        if (isWatch) {
+            click(By.text(getPermissionControllerString(DENY_BUTTON_TEXT)))
+        } else {
+            click(
+                By.res("com.android.permissioncontroller:id/permission_deny_dont_ask_again_button")
+            )
+        }
+    }
 
     protected fun clickPermissionRequestNoUpgradeAndDontAskAgainButton() {
         if (isAutomotive) {
@@ -426,11 +435,20 @@
 
             click(By.text(permissionLabel))
 
+            // Watch does not show an alert dialog when the user turns on permission, only when they
+            // turns it off.
+            if (isWatch && waitFindObjectOrNull(By.text(permissionLabel), 1000) != null) {
+                continue
+            }
+
             val wasGranted = if (isAutomotive) {
                 // Automotive doesn't support one time permissions, and thus
                 // won't show an "Ask every time" message
                 !waitFindObject(byTextRes(R.string.deny)).isChecked
             } else {
+                if (isWatch) {
+                    click(By.text("Deny"))
+                }
                 !(waitFindObject(byTextRes(R.string.deny)).isChecked ||
                     (!isLegacyApp && hasAskButton(permission) &&
                         waitFindObject(byTextRes(R.string.ask)).isChecked))
@@ -488,7 +506,9 @@
                     null
                 )
                 val confirmText = resources.getString(confirmTextRes)
-                click(byTextStartsWithCaseInsensitive(confirmText))
+                if (!isWatch) {
+                    click(byTextStartsWithCaseInsensitive(confirmText))
+                }
             }
             pressBack()
         }
diff --git a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
index cf52bf2..98fd59e 100644
--- a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
+++ b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
@@ -370,7 +370,7 @@
 
     @Nullable
     private UiObject2 findDontAskAgainCheck(boolean expected) throws UiObjectNotFoundException {
-        BySelector selector = By.text("Don\u2019t ask again");
+        BySelector selector = By.res("com.android.permissioncontroller:id/dont_ask_again");
         return expected
                 ? waitFindObject(selector)
                 : waitFindObjectOrNull(selector, UNEXPECTED_TIMEOUT_MILLIS);
diff --git a/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt
index 03edc50..8368b3a 100644
--- a/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt
+++ b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt
@@ -16,18 +16,24 @@
 
 package android.sensorprivacy.cts
 
+import android.app.AppOpsManager
 import android.content.Intent
+import android.content.pm.PackageManager
 import android.hardware.SensorPrivacyManager
 import android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener
+import android.hardware.SensorPrivacyManager.Sensors.CAMERA
+import android.hardware.SensorPrivacyManager.Sensors.MICROPHONE
 import android.support.test.uiautomator.By
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
-import com.android.compatibility.common.util.SystemUtil
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import com.android.compatibility.common.util.SystemUtil.eventually
 import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow
 import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import com.android.compatibility.common.util.ThrowingSupplier
 import com.android.compatibility.common.util.UiAutomatorUtils
+import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
 import org.junit.Assert.assertTrue
 import org.junit.Assume
 import org.junit.Before
@@ -51,6 +57,9 @@
                 "android.sensorprivacy.cts.usemiccamera.extra.USE_MICROPHONE"
         const val USE_CAM_EXTRA =
                 "android.sensorprivacy.cts.usemiccamera.extra.USE_CAMERA"
+        const val PKG_NAME = "android.sensorprivacy.cts.usemiccamera"
+        const val ACTIVITY_TITLE_SNIP = "CtsUseMic"
+        const val SENSOR_USE_TIME_MS = 5L
     }
 
     protected val instrumentation = InstrumentationRegistry.getInstrumentation()!!
@@ -59,9 +68,11 @@
     protected val context = instrumentation.targetContext!!
     protected val spm = context.getSystemService(SensorPrivacyManager::class.java)!!
     protected val packageManager = context.packageManager!!
+    protected val op = getOpForSensor(sensor)
 
     @Before
     fun init() {
+        setSensor(false)
         Assume.assumeTrue(spm.supportsSensorToggle(sensor))
         uiDevice.wakeUp()
         runShellCommandOrThrow("wm dismiss-keyguard")
@@ -80,24 +91,14 @@
     @Test
     fun testDialog() {
         setSensor(true)
-        val intent = Intent(MIC_CAM_ACTIVITY_ACTION)
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-                .addFlags(Intent.FLAG_ACTIVITY_MATCH_EXTERNAL)
-        for (extra in extras) {
-            intent.putExtra(extra, true)
-        }
-        context.startActivity(intent)
+        startTestApp()
         UiAutomatorUtils.waitFindObject(By.text(
                 Pattern.compile("Unblock", Pattern.CASE_INSENSITIVE))).click()
-        SystemUtil.eventually {
+        eventually {
             assertFalse(isSensorPrivacyEnabled())
         }
 
-        // instant apps can't broadcast to other instant apps; use the shell
-        runShellCommandOrThrow("am broadcast" +
-                " --user ${context.userId}" +
-                " -a $FINISH_MIC_CAM_ACTIVITY_ACTION" +
-                " -f ${Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS}")
+        finishTestApp()
     }
 
     @Test
@@ -129,15 +130,165 @@
         latchEnabled.await(100, TimeUnit.MILLISECONDS)
     }
 
-    fun setSensor(enable: Boolean) {
+    @Test
+    fun testOpNotRunningWhileSensorPrivacyEnabled() {
+        setSensor(false)
+        val before = System.currentTimeMillis()
+        startTestApp()
+        eventually {
+            assertOpRunning(true)
+        }
+        Thread.sleep(SENSOR_USE_TIME_MS)
+        setSensor(true)
+        eventually {
+            val after = System.currentTimeMillis()
+            assertOpRunning(false)
+            assertLastAccessTimeAndDuration(before, after)
+        }
+        finishTestApp()
+    }
+
+    @Test
+    fun testOpStartsRunningAfterStartedWithSensoryPrivacyEnabled() {
+        setSensor(true)
+        startTestApp()
+        UiAutomatorUtils.waitFindObject(By.text(
+                Pattern.compile("Cancel", Pattern.CASE_INSENSITIVE))).click()
+        assertOpRunning(false)
+        setSensor(false)
+        eventually {
+            assertOpRunning(true)
+        }
+        finishTestApp()
+    }
+
+    @Test
+    fun testOpGetsRecordedAfterStartedWithSensorPrivacyEnabled() {
+        setSensor(true)
+        startTestApp()
+        UiAutomatorUtils.waitFindObject(By.text(
+                Pattern.compile("Cancel", Pattern.CASE_INSENSITIVE))).click()
+        val before = System.currentTimeMillis()
+        setSensor(false)
+        eventually {
+            assertOpRunning(true)
+        }
+        setSensor(true)
+        eventually {
+            val after = System.currentTimeMillis()
+            assertLastAccessTimeAndDuration(before, after)
+        }
+        finishTestApp()
+    }
+
+    @Test
+    fun testOpLastAccessUpdatesAfterToggleSensorPrivacy() {
+        setSensor(false)
+        val before = System.currentTimeMillis()
+        startTestApp()
+        eventually {
+            assertOpRunning(true)
+        }
+        Thread.sleep(SENSOR_USE_TIME_MS)
+        setSensor(true)
+        eventually {
+            val after = System.currentTimeMillis()
+            assertOpRunning(false)
+            assertLastAccessTimeAndDuration(before, after)
+        }
+
+        val before2 = System.currentTimeMillis()
+        setSensor(false)
+        eventually {
+            assertOpRunning(true)
+        }
+        Thread.sleep(SENSOR_USE_TIME_MS)
+        setSensor(true)
+        eventually {
+            val after = System.currentTimeMillis()
+            assertOpRunning(false)
+            assertLastAccessTimeAndDuration(before2, after)
+        }
+        finishTestApp()
+    }
+
+    private fun startTestApp() {
+        val intent = Intent(MIC_CAM_ACTIVITY_ACTION)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                .addFlags(Intent.FLAG_ACTIVITY_MATCH_EXTERNAL)
+        for (extra in extras) {
+            intent.putExtra(extra, true)
+        }
+        context.startActivity(intent)
+        // Wait for app to open
+        UiAutomatorUtils.waitFindObject(By.textContains(ACTIVITY_TITLE_SNIP))
+    }
+
+    private fun finishTestApp() {
+        // instant apps can't broadcast to other instant apps; use the shell
+        runShellCommandOrThrow("am broadcast" +
+                " --user ${context.userId}" +
+                " -a $FINISH_MIC_CAM_ACTIVITY_ACTION" +
+                " -f ${Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS}")
+    }
+
+    private fun setSensor(enable: Boolean) {
         runWithShellPermissionIdentity {
             spm.setSensorPrivacy(sensor, enable)
         }
     }
 
-    fun isSensorPrivacyEnabled(): Boolean {
-        return runWithShellPermissionIdentity(ThrowingSupplier {
+    private fun isSensorPrivacyEnabled(): Boolean {
+        return callWithShellPermissionIdentity {
             spm.isSensorPrivacyEnabled(sensor)
-        })
+        }
+    }
+
+    private fun getOpForSensor(sensor: Int): String? {
+        return when (sensor) {
+            CAMERA -> AppOpsManager.OPSTR_CAMERA
+            MICROPHONE -> AppOpsManager.OPSTR_RECORD_AUDIO
+            else -> null
+        }
+    }
+
+    private fun getOpForPackage(): AppOpsManager.PackageOps {
+        return callWithShellPermissionIdentity {
+            val uid = try {
+                packageManager.getPackageUid(PKG_NAME, 0)
+            } catch (e: PackageManager.NameNotFoundException) {
+                // fail test
+                assertNull(e)
+                -1
+            }
+            val appOpsManager: AppOpsManager =
+                    context.getSystemService(AppOpsManager::class.java)!!
+            val pkgOps = appOpsManager.getOpsForPackage(uid, PKG_NAME, op)
+            assertFalse("expected non empty app op list", pkgOps.isEmpty())
+            pkgOps[0]
+        }
+    }
+
+    private fun assertOpRunning(isRunning: Boolean) {
+        val pkgOp = getOpForPackage()
+        for (op in pkgOp.ops) {
+            for ((_, attrOp) in op.attributedOpEntries) {
+                assertEquals("Unexpected op running state", isRunning, attrOp.isRunning)
+            }
+        }
+    }
+
+    private fun assertLastAccessTimeAndDuration(before: Long, after: Long) {
+        val pkgOp = getOpForPackage()
+        for (op in pkgOp.ops) {
+            for ((_, attrOp) in op.attributedOpEntries) {
+                val lastAccess = attrOp.getLastAccessTime(AppOpsManager.OP_FLAGS_ALL_TRUSTED)
+                val lastDuration = attrOp.getLastDuration(AppOpsManager.OP_FLAGS_ALL_TRUSTED)
+                assertTrue("lastAccess was $lastAccess, not between $before and $after",
+                        lastAccess in before..after)
+                assertTrue("lastAccess had duration $lastDuration, greater than ${after - before}",
+                lastDuration <= (after - before))
+            }
+        }
     }
 }
diff --git a/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt b/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt
index a4eb44b..bc81de5 100644
--- a/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt
+++ b/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt
@@ -121,7 +121,7 @@
                 cameraDevice.createCaptureSession(sessionConfiguration)
             }
 
-            override fun onDisconnected(ameraDevice: CameraDevice) {}
+            override fun onDisconnected(cameraDevice: CameraDevice) {}
             override fun onError(cameraDevice: CameraDevice, i: Int) {}
         }
 
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
index f3319f3..c868b1e 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
@@ -2192,8 +2192,6 @@
         runWithCallerWithStrictMode(mPackageContext1, () -> {
             assertTrue(getManager().setDynamicShortcuts(list(
                     makeShortcut("s1"))));
-            getManager().updateShortcutVisibility(
-                    mPackageContext2.getPackageName(), new byte[] {100}, true);
         });
 
         setDefaultLauncher(getInstrumentation(), mLauncherContext1);
diff --git a/tests/tests/syncmanager/src/android/content/syncmanager/cts/CtsSyncManagerTest.java b/tests/tests/syncmanager/src/android/content/syncmanager/cts/CtsSyncManagerTest.java
index 1071975..29509d8 100644
--- a/tests/tests/syncmanager/src/android/content/syncmanager/cts/CtsSyncManagerTest.java
+++ b/tests/tests/syncmanager/src/android/content/syncmanager/cts/CtsSyncManagerTest.java
@@ -28,6 +28,7 @@
 import static junit.framework.TestCase.assertEquals;
 
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import android.accounts.Account;
 import android.app.usage.UsageStatsManager;
@@ -251,6 +252,36 @@
 
         AmUtils.setStandbyBucket(APP1_PACKAGE, UsageStatsManager.STANDBY_BUCKET_RARE);
 
+        Bundle b = makeBundle(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, true,
+                ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
+
+        ContentResolver.requestSync(ACCOUNT_1_A, APP1_AUTHORITY, b);
+
+        waitUntil("Expedited job sync didn't run in Doze", 30, () -> {
+            final Response res = mRpc.invoke(APP1_PACKAGE,
+                    rb -> rb.setGetSyncInvocations(GetSyncInvocations.newBuilder()));
+            final int calls = res.getSyncInvocations().getSyncInvocationsCount();
+            Log.i(TAG, "NumSyncInvocations=" + calls);
+            return calls == 1;
+        });
+    }
+
+    @Test
+    public void testExpeditedJobSync_InDoze() throws Exception {
+        assumeTrue(isDozeFeatureEnabled());
+
+        setDozeState(false);
+        removeAllAccounts();
+
+        // Let the initial sync happen.
+        addAccountAndLetInitialSyncRun(ACCOUNT_1_A, APP1_AUTHORITY);
+
+        writeSyncConfig(2, 1, 2, 3);
+
+        clearSyncInvocations(APP1_PACKAGE);
+
+        AmUtils.setStandbyBucket(APP1_PACKAGE, UsageStatsManager.STANDBY_BUCKET_RARE);
+
         setDozeState(true);
         Bundle b = makeBundle(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, true,
                 ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
@@ -297,6 +328,11 @@
         assertTrue(extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE));
     }
 
+    private static boolean isDozeFeatureEnabled() {
+        final String output = ShellUtils.runShellCommand("cmd deviceidle enabled deep").trim();
+        return Integer.parseInt(output) != 0;
+    }
+
     private void setDozeState(final boolean on) throws Exception {
         ShellUtils.runShellCommand("cmd deviceidle " + (on ? "force-idle" : "unforce"));
         if (!on) {
diff --git a/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java
index b214df2..19a7cc5 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java
@@ -511,6 +511,7 @@
         verifyCarModeBound(mCarModeIncallServiceControlOne);
 
         disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_NORMAL);
+        mInCallCallbacks.getService().disconnectAllCalls();
     }
 
 
diff --git a/tests/tests/text/src/android/text/cts/TextPaintTest.java b/tests/tests/text/src/android/text/cts/TextPaintTest.java
index d5a6ca1..8d3ed45 100644
--- a/tests/tests/text/src/android/text/cts/TextPaintTest.java
+++ b/tests/tests/text/src/android/text/cts/TextPaintTest.java
@@ -33,7 +33,8 @@
         TextPaint textPaint;
 
         textPaint = new TextPaint();
-        assertEquals(DEFAULT_PAINT_FLAGS, textPaint.getFlags());
+        assertEquals(DEFAULT_PAINT_FLAGS | TextPaint.ANTI_ALIAS_FLAG | TextPaint.DITHER_FLAG,
+                textPaint.getFlags());
 
         textPaint = new TextPaint(TextPaint.DITHER_FLAG);
         assertEquals((TextPaint.DITHER_FLAG | DEFAULT_PAINT_FLAGS),
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
index d8c4c33..ddf9c54 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
@@ -123,6 +123,7 @@
                     Paint p = new Paint();
                     canvas.drawColor(Color.WHITE);
                     p.setColor(Color.BLACK);
+                    p.setAntiAlias(false);
                     float[] pts = {
                             0, 0, 80, 80, 80, 0, 0, 80, 40, 50, 60, 50
                     };
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
index 7c2121d..c962915 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
@@ -112,6 +112,7 @@
         // from there execute a normal canvas test with that.
         CanvasClient canvasClient = (canvas, width, height) -> {
             Paint paint = new Paint();
+            paint.setAntiAlias(false);
             modifierAccessor.modifyDrawing(canvas, paint);
             if (drawOp != null) {
                 drawOp.modifyDrawing(paint, canvas);
diff --git a/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java b/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java
index 4baa60f..7a3ba98 100644
--- a/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java
+++ b/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java
@@ -742,31 +742,31 @@
             }
         };
         verifyTest(callback,
-                new PixelChecker(PixelColor.RED) { //1111
+                new PixelChecker(PixelColor.RED) { //2500
                     @Override
                     public boolean checkPixels(int pixelCount, int width, int height) {
-                        return pixelCount > 1000 && pixelCount < 1250;
+                        return pixelCount > 2250 && pixelCount < 2750;
                     }
                 });
         verifyTest(callback,
-                new PixelChecker(PixelColor.BLUE) { //1111
+                new PixelChecker(PixelColor.BLUE) { //2500
                     @Override
                     public boolean checkPixels(int pixelCount, int width, int height) {
-                        return pixelCount > 1000 && pixelCount < 1250;
+                        return pixelCount > 2250 && pixelCount < 2750;
                     }
                 });
         verifyTest(callback,
-                new PixelChecker(PixelColor.MAGENTA) { //1111
+                new PixelChecker(PixelColor.MAGENTA) { //2500
                     @Override
                     public boolean checkPixels(int pixelCount, int width, int height) {
-                        return pixelCount > 1000 && pixelCount < 1250;
+                        return pixelCount > 2250 && pixelCount < 2750;
                     }
                 });
         verifyTest(callback,
-                new PixelChecker(PixelColor.GREEN) { //1111
+                new PixelChecker(PixelColor.GREEN) { //2500
                     @Override
                     public boolean checkPixels(int pixelCount, int width, int height) {
-                        return pixelCount > 1000 && pixelCount < 1250;
+                        return pixelCount > 2250 && pixelCount < 2750;
                     }
                 });
     }
diff --git a/tests/tests/view/src/android/view/cts/ViewRootSyncTest.java b/tests/tests/view/src/android/view/cts/AttachedSurfaceControlSyncTest.java
similarity index 95%
rename from tests/tests/view/src/android/view/cts/ViewRootSyncTest.java
rename to tests/tests/view/src/android/view/cts/AttachedSurfaceControlSyncTest.java
index b1f401a..453b07a 100644
--- a/tests/tests/view/src/android/view/cts/ViewRootSyncTest.java
+++ b/tests/tests/view/src/android/view/cts/AttachedSurfaceControlSyncTest.java
@@ -61,8 +61,8 @@
 @LargeTest
 @SuppressLint("RtlHardcoded")
 @RequiresDevice
-public class ViewRootSyncTest {
-    private static final String TAG = "ViewRootSyncTests";
+public class AttachedSurfaceControlSyncTest {
+    private static final String TAG = "AttachedSurfaceControlSyncTests";
 
     @Rule
     public ActivityTestRule<CapturedActivityWithResource> mActivityRule =
@@ -92,7 +92,7 @@
             t.setGeometry(mSurfaceControl, null, new Rect(mLocation[0], mLocation[1],
                     mLocation[0]+100,
                     mLocation[1]+100), 0);
-            getViewRoot().applyTransactionOnDraw(t);
+            getRootSurfaceControl().applyTransactionOnDraw(t);
             return true;
         };
 
@@ -125,7 +125,8 @@
         @Override
         protected void onAttachedToWindow() {
             super.onAttachedToWindow();
-            SurfaceControl.Transaction t = getViewRoot().buildReparentTransaction(mSurfaceControl);
+            SurfaceControl.Transaction t =
+                getRootSurfaceControl().buildReparentTransaction(mSurfaceControl);
             t.setLayer(mSurfaceControl, -1)
                 .setVisibility(mSurfaceControl, true)
                 .apply();
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ASurfaceControlTestActivity.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ASurfaceControlTestActivity.java
index e90fe2e..d20aebf 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ASurfaceControlTestActivity.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ASurfaceControlTestActivity.java
@@ -133,7 +133,8 @@
                 swBitmap.getHeight());
         swBitmap.recycle();
 
-        assertTrue(success);
+        assertTrue("Actual matched pixels:" + numMatchingPixels
+                + " Bitmap size:" + swBitmap.getWidth() + "x" + swBitmap.getHeight(), success);
     }
 
     public abstract static class PixelChecker {
diff --git a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
index 28ce7bf..c0a850d 100644
--- a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
+++ b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
@@ -161,6 +161,7 @@
         return componentName != null ? componentName.getPackageName() : "";
     }
 
+    @Ignore("b/184963112")
     @Test
     public void testNonTrustedRecognitionServiceCanBlameCallingApp() throws Throwable {
         // This is a workaound solution for R QPR. We treat trusted if the current voice recognizer
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 fa964ac..43448de 100644
--- a/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainHotwordDetectionService.java
+++ b/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainHotwordDetectionService.java
@@ -21,6 +21,7 @@
 import android.os.PersistableBundle;
 import android.os.SharedMemory;
 import android.service.voice.AlwaysOnHotwordDetector;
+import android.service.voice.HotwordDetectedResult;
 import android.service.voice.HotwordDetectionService;
 import android.system.ErrnoException;
 import android.text.TextUtils;
@@ -43,7 +44,7 @@
 
         // TODO: Check the capture session (needs to be reflectively accessed).
         if (eventPayload.getTriggerAudio().length == 1024) {
-            callback.onDetected(null);
+            callback.onDetected(new HotwordDetectedResult.Builder().build());
         }
     }
 
@@ -88,7 +89,7 @@
             if(isSame(buffer, BasicVoiceInteractionService.FAKE_HOTWORD_AUDIO_DATA,
                     buffer.length)) {
                 Log.d(TAG, "call callback.onDetected");
-                callback.onDetected(null);
+                callback.onDetected(new HotwordDetectedResult.Builder().build());
             }
         } catch (IOException e) {
             Log.w(TAG, "Failed to read data : ", e);
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java b/tests/tests/wifi/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java
index 101dc7c..2647aa2 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java
@@ -39,6 +39,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
@@ -370,6 +371,23 @@
         }
     }
 
+    /**
+     * Tests the {@link android.net.wifi.WifiManager#setWifiScoringEnabled(boolean)}
+     *
+     * TODO(b/167575586): Wait for S SDK finalization to determine the final minSdkVersion.
+     */
+    @SdkSuppress(minSdkVersion = 31, codeName = "S")
+    @Test
+    public void testSetWifiScoringEnabled() throws Exception {
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            uiAutomation.adoptShellPermissionIdentity();
+            assertTrue(mWifiManager.setWifiScoringEnabled(true));
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
     private static abstract class TestConnectedNetworkScorer implements
             WifiManager.WifiConnectedNetworkScorer {
         protected CountDownLatch mCountDownLatch;
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
index ec7f740..e7d5c9a 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
@@ -916,12 +916,8 @@
         assertThat(copy.getRealm()).isEqualTo(REALM);
     }
 
-    /**
-     * TODO(b/167575586): Wait for S SDK finalization to determine the final minSdkVersion.
-     */
-    @SdkSuppress(minSdkVersion = 31, codeName = "S")
     public void testIsEnterpriseConfigServerCertNotEnabled() {
-        if (!hasWifi()) {
+        if (!hasWifi() || !WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
             return;
         }
         WifiEnterpriseConfig baseConfig = new WifiEnterpriseConfig();
@@ -947,34 +943,22 @@
         assertFalse(noValidationConfig.isEapMethodServerCertUsed());
     }
 
-    /**
-     * TODO(b/167575586): Wait for S SDK finalization to determine the final minSdkVersion.
-     */
-    @SdkSuppress(minSdkVersion = 31, codeName = "S")
     public void testIsEnterpriseConfigServerCertEnabledWithPeap() {
-        if (!hasWifi()) {
+        if (!hasWifi() || !WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
             return;
         }
         testIsEnterpriseConfigServerCertEnabled(Eap.PEAP);
     }
 
-    /**
-     * TODO(b/167575586): Wait for S SDK finalization to determine the final minSdkVersion.
-     */
-    @SdkSuppress(minSdkVersion = 31, codeName = "S")
     public void testIsEnterpriseConfigServerCertEnabledWithTls() {
-        if (!hasWifi()) {
+        if (!hasWifi() || !WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
             return;
         }
         testIsEnterpriseConfigServerCertEnabled(Eap.TLS);
     }
 
-    /**
-     * TODO(b/167575586): Wait for S SDK finalization to determine the final minSdkVersion.
-     */
-    @SdkSuppress(minSdkVersion = 31, codeName = "S")
     public void testIsEnterpriseConfigServerCertEnabledWithTTLS() {
-        if (!hasWifi()) {
+        if (!hasWifi() || !WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
             return;
         }
         testIsEnterpriseConfigServerCertEnabled(Eap.TTLS);
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
index e81bafa..6156402 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
@@ -37,6 +37,7 @@
 import android.platform.test.annotations.AppModeFull;
 import android.support.test.uiautomator.UiDevice;
 
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -460,6 +461,10 @@
      */
     @Test
     public void testBuilderForWpa3EnterpriseWithStandardApi() {
+        if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(mContext)) {
+            // Skip the test if wifi module version is older than S.
+            return;
+        }
         WifiNetworkSpecifier specifier1 = new WifiNetworkSpecifier.Builder()
                 .setSsid(WifiInfo.sanitizeSsid(sTestNetwork.SSID))
                 .setWpa3EnterpriseStandardModeConfig(new WifiEnterpriseConfig())
@@ -477,6 +482,10 @@
      */
     @Test
     public void testBuilderForWpa3Enterprise192bit() {
+        if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(mContext)) {
+            // Skip the test if wifi module version is older than S.
+            return;
+        }
         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
         enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
         enterpriseConfig.setCaCertificate(CA_SUITE_B_ECDSA_CERT);
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java
index 82e2a0a..3278ad1 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java
@@ -852,12 +852,13 @@
 
     /**
      * Tests {@link android.net.wifi.WifiNetworkSuggestion.Builder} class.
-     *
-     * TODO(b/167575586): Wait for S SDK finalization to determine the final minSdkVersion.
      */
-    @SdkSuppress(minSdkVersion = 31, codeName = "S")
     @Test
     public void testBuilderWithWpa3EnterpriseWithStandardApi() throws Exception {
+        if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
+            // Skip the test if wifi module version is older than S.
+            return;
+        }
         WifiEnterpriseConfig enterpriseConfig = createEnterpriseConfig();
         WifiNetworkSuggestion suggestion =
                 createBuilderWithCommonParams()
@@ -942,12 +943,13 @@
 
     /**
      * Tests {@link android.net.wifi.WifiNetworkSuggestion.Builder} class.
-     *
-     * TODO(b/167575586): Wait for S SDK finalization to determine the final minSdkVersion.
      */
-    @SdkSuppress(minSdkVersion = 31, codeName = "S")
     @Test
     public void testBuilderWithWpa3Enterprise192bitWithSuiteBEccCerts() throws Exception {
+        if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) {
+            // Skip the test if wifi module version is older than S.
+            return;
+        }
         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
         enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
         enterpriseConfig.setCaCertificate(CA_SUITE_B_ECDSA_CERT);
diff --git a/tests/translation/src/android/translation/cts/TranslationManagerTest.java b/tests/translation/src/android/translation/cts/TranslationManagerTest.java
index 5c4f875..b5aa12c 100644
--- a/tests/translation/src/android/translation/cts/TranslationManagerTest.java
+++ b/tests/translation/src/android/translation/cts/TranslationManagerTest.java
@@ -166,6 +166,7 @@
 
         // unregister listeners
         manager.removeOnDeviceTranslationCapabilityUpdateListener(updateListener);
+        SystemClock.sleep(1_000);
 
         // update text to text TranslationCapability
         service.updateTranslationCapability(updatedText2TextCapability);